{"id":13433245,"url":"https://github.com/hookdeck/hookdeck-vercel","last_synced_at":"2025-04-23T16:17:10.255Z","repository":{"id":236309212,"uuid":"773893869","full_name":"hookdeck/hookdeck-vercel","owner":"hookdeck","description":"Authenticate, delay, filter, queue, throttle, and retry asynchronous HTTP requests (e.g., webhooks) made to a Vercel application via a middleware integration with Hookdeck","archived":false,"fork":false,"pushed_at":"2024-10-29T17:45:12.000Z","size":5073,"stargazers_count":32,"open_issues_count":4,"forks_count":1,"subscribers_count":4,"default_branch":"main","last_synced_at":"2025-04-23T16:17:03.340Z","etag":null,"topics":["asynchronous-apis","asynchronous-messaging","microservices","middleware","vercel","webhooks"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/hookdeck.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2024-03-18T15:29:25.000Z","updated_at":"2025-04-17T08:53:08.000Z","dependencies_parsed_at":"2024-05-06T19:39:40.081Z","dependency_job_id":"0d75c16b-2265-4fc9-a1af-15070d51b30f","html_url":"https://github.com/hookdeck/hookdeck-vercel","commit_stats":{"total_commits":52,"total_committers":3,"mean_commits":"17.333333333333332","dds":0.3653846153846154,"last_synced_commit":"c18a7db1823ec5639a89497d275cb524ed68c132"},"previous_names":["hookdeck/hookdeck-vercel"],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hookdeck%2Fhookdeck-vercel","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hookdeck%2Fhookdeck-vercel/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hookdeck%2Fhookdeck-vercel/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hookdeck%2Fhookdeck-vercel/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/hookdeck","download_url":"https://codeload.github.com/hookdeck/hookdeck-vercel/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250468277,"owners_count":21435453,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["asynchronous-apis","asynchronous-messaging","microservices","middleware","vercel","webhooks"],"created_at":"2024-07-31T02:01:23.028Z","updated_at":"2025-04-23T16:17:10.236Z","avatar_url":"https://github.com/hookdeck.png","language":"JavaScript","readme":"# Hookdeck Vercel Middleware\n\nThe Hookdeck Vercel Middleware adds the ability to authenticate, delay, filter, queue, throttle, and retry asynchronous HTTP requests (e.g., webhooks) made to a Vercel application. The use cases for this include managing webhooks from API providers such as Stripe, Shopify, and Twilio, or when building asynchronous APIs.\n\n![Hookdeck Vercel Middleware](img/hookdeck-vercel-middleware.png)\n\n## Get Started\n\nBefore you begin:\n\n- Create a [Vercel](https://vercel.com?ref=github-hookdeck-vercel) account and a project.\n- [Signup for a Hookdeck account](https://dashboard.hookdeck.com/signup?ref=github-hookdeck-vercel) and create your Hookdeck project.\n- Get the Hookdeck API key and Signing Secret from your [project secrets](https://dashboard.hookdeck.com/settings/project/secrets?ref=github-hookdeck-vercel).\n- Add `HOOKDECK_API_KEY` and `HOOKDECK_SIGNING_SECRET` (optional but recommended) as [environment variables](https://vercel.com/docs/projects/environment-variables?ref=github-hookdeck-vercel)\n  for your Vercel project.\n\nInstall the Hookdeck Vercel package:\n\n```bash\nnpm i @hookdeck/vercel\n```\n\n\u003e Once installed, package a `hookdeck.config.js` file is created at the root of your project. Also, the command `hookdeck-vercel deploy` is appended to the `prebuild` script of your `package.json`.\n\nEnsure the `match` key in `hookdeck.config.js` matches the route you want the middleware to intercept:\n\n```js\nconst { RetryStrategy, DestinationRateLimitPeriod } = require('@hookdeck/sdk/api');\n\n/** @type {import(\"@hookdeck/vercel\").HookdeckConfig} */\nconst hookdeckConfig = {\n  match: {\n    '/api/webhooks': {\n      retry: {\n        strategy: RetryStrategy.Linear,\n        count: 5,\n        interval: 1 * 60 * 1000, // in milliseconds\n      },\n      rate: {\n        limit: 10,\n        period: DestinationRateLimitPeriod.Second,\n      },\n    },\n  },\n};\n\nmodule.exports = hookdeckConfig;\n```\n\nThis example configures a retry strategy with a linear back-off and a delivery rate limit of 10 requests per second.\n\n\u003e ℹ️ The Hookdeck Vercel Middleware uses `VERCEL_BRANCH_URL` by default. If you are not deploying your application via source control, set `hookdeckConfig.vercel_url` to a different URL such as `process.env.VERCEL_URL`.\n\nUpdate `middleware.ts` (or `middleware.js`) to add the Hookdeck Vercel Middleware and ensure `config.matcher` has the same (or broader) value as you have in `hookdeck.config.js` (e.g., `/api/webhooks`):\n\n```typescript\nimport { withHookdeck } from '@hookdeck/vercel';\nimport hookdeckConfig from './hookdeck.config';\n\nimport { NextResponse } from 'next/server';\n\nexport const config = {\n  matcher: '/api/webhooks',\n};\n\nfunction middleware(request: Request) {\n  // ... existing or additional your middleware logic\n\n  NextResponse.next();\n}\n\n// wrap the middleware with Hookdeck wrapper\nexport default withHookdeck(hookdeckConfig, middleware);\n```\n\nIf you don't already have a route, create one. For example, `app/api/webhooks/route.ts` for the `/api/webhooks` endpoint in a Next.js app using the app router:\n\n```typescript\nexport async function POST() {\n  const data = { received: true };\n\n  return Response.json(data);\n}\n```\n\nDeploy the application to Vercel.\n\nOnce the deployment has succeeded, make a request to your middleware endpoint:\n\n```bash\ncurl --location 'http://your.vercel.app/api/webhooks' \\\n--header 'Content-Type: application/json' \\\n--data '{\n    \"test\": \"value\"\n}'\n```\n\nCheck the Vercel logs to see that the middleware is processing the events:\n\n![Vercel Logs](img/vercel-logs.png)\n\nCheck the Hookdeck logs to see that the requests are being handled and the events are being processed and delivered:\n\n![Hookdeck events](img/hookdeck-events.png)\n\n## Configuration\n\n## Environment Variables\n\nEnvironment variables used by the middleware. Get the values from the [Hookdeck project secrets](https://dashboard.hookdeck.com/settings/project/secrets?ref=github-hookdeck-vercel).\n\n- `HOOKDECK_API_KEY`: The Hookdeck project API Key used to manage the [connections](https://hookdeck.com/docs/connections?ref=github-hookdeck-vercel) within your project.\n- `HOOKDECK_SIGNING_SECRET`: Optional but recommended. Used to check the signature of the inbound HTTP request when received from Hookdeck. See [webhook signature verification](https://hookdeck.com/docs/authentication#hookdeck-webhook-signature-verification?ref=github-hookdeck-vercel). Get the value from the [Hookdeck project secrets](https://dashboard.hookdeck.com/settings/project/secrets?ref=github-hookdeck-vercel).\n\nYou can also set these values programmatically within `hookdeck.config.js`.\n\n### `middleware.ts`\n\nThe [Vercel Edge Middleware](https://vercel.com/docs/functions/edge-middleware?ref=github-hookdeck-vercel) must be updated as follows:\n\n1. Update the exported `config.matcher` to match the route for the Hookdeck Vercel Middleware\n2. Import and use `withHookdeck` middleware wrapper\n\n```typescript\n// add Hookdeck imports\nimport { withHookdeck } from '@hookdeck/vercel';\nimport hookdeckConfig from './hookdeck.config';\n\nexport const config = {\n  matcher: 'path/to/match',\n};\n\n// the middleware is not exported anymore\nfunction middleware(request: Request) {\n  // ... your middleware logic\n  // return `NextResponse.next()` or `next()` to manage the request with Hookdeck\n}\n\n// wrap the middleware with Hookdeck wrapper\nexport default withHookdeck(hookdeckConfig, middleware);\n```\n\n### `hookdeck.config.js`\n\nThe minimum configuration is the following, with the `match` containing an object with a matching path (`path/to/match`) as the key. This value should be the same as the value exported via `config.matcher` in `middleware.ts`.\n\n```js\n/** @type {import(\"@hookdeck/vercel\").HookdeckConfig} */\nconst hookdeckConfig = {\n  match: {\n    'path/to/match': {},\n  },\n};\n\nmodule.exports = hookdeckConfig;\n```\n\n\u003e IMPORTANT: Ensure `config.matcher` in your `middleware` includes the routes specified in the `hookdeck.config.js` `match` fields. Only routes that match both expressions will trigger the Hookdeck functionality.\n\nFull configuration options:\n\n- `api_key`: The Hookdeck project API Key used to manage the [connections](https://hookdeck.com/docs/connections?ref=github-hookdeck-vercel) within your project. This config value will override the `HOOKDECK_API_KEY` environment variable. Get the value from the [Hookdeck project secrets](https://dashboard.hookdeck.com/settings/project/secrets?ref=github-hookdeck-vercel).\n- `signing_secret`: Used to check the signature of the inbound HTTP request when it is received from Hookdeck. This config value will override the `HOOKDECK_SIGNING_SECRET` environment variable. See [webhook signature verification](https://hookdeck.com/docs/authentication#hookdeck-webhook-signature-verification?ref=github-hookdeck-vercel). Get the value from the [Hookdeck project secrets](https://dashboard.hookdeck.com/settings/project/secrets?ref=github-hookdeck-vercel).\n- `vercel_url`: The Vercel URL that receives the requests. If not specified, the url stored in env var `VERCEL_BRANCH_URL` will be used.\n- `match`: a key-value map of paths for routes and the configuration for each of those routes.\n  - `[path]` - the matching string or regex that will be compared or tested against the pathname of the URL that triggered the middleware. If there is more than one match, then the request is sent to every matching configuration.\n    - `retry`: use the values specified in the [Retry documentation](https://hookdeck.com/docs/api#retry?ref=github-hookdeck-vercel) to configure Hookdeck's retry strategy.\n    - `delay`: the number of milliseconds to hold the event when it arrives at Hookdeck.\n    - `filters`: specify different filters to exclude some events from forwarding. Use the syntax specified in the [Filter documentation](https://hookdeck.com/docs/api#filter?ref=github-hookdeck-vercel).\n    - `rate`: set the delivery rate to be used for the outcoming traffic. Check the syntax in the `rate_limit_period` key in the [Destination documentation](https://hookdeck.com/docs/api#destination-object?ref=github-hookdeck-vercel).\n    - `verification`: the inbound (source) verification mechanism to use. Check all possible values and syntax in the [Source documentation](https://hookdeck.com/docs/api#source-object?ref=github-hookdeck-vercel).\n    - `custom_response`: the custom response to send back the webhook origin. Check the syntax in the [Source documentation](https://hookdeck.com/docs/api#source-object?ref=github-hookdeck-vercel).\n\nHere's an example with all the configuration options:\n\n```javascript\nconst {\n  RetryStrategy,\n  DestinationRateLimitPeriod,\n  SourceCustomResponseContentType,\n} = require('@hookdeck/sdk/api');\n\n/** @type {import(\"@hookdeck/vercel\").HookdeckConfig} */\nconst hookdeckConfig = {\n  // vercel_url: '', // optional. Uses `VERCEL_BRANCH_URL` env var as default.\n  match: {\n    '/api/webhooks': {\n      // all these fields are optional\n      retry: {\n        strategy: RetryStrategy.Linear,\n        count: 5,\n        interval: 1 * 60 * 1000, // in milliseconds\n      },\n      delay: 1 * 60 * 1000, // in milliseconds\n      filters: [\n        {\n          headers: {\n            'x-my-header': 'my-value',\n          },\n          body: {},\n          query: {},\n          path: {},\n        },\n      ],\n      rate: {\n        limit: 10,\n        period: DestinationRateLimitPeriod.Minute,\n      },\n      verification: {\n        type: 'API_KEY',\n        configs: {\n          header_key: 'x-my-api-key',\n          api_key: 'this-is-my-token',\n        },\n      },\n      custom_response: {\n        content_type: SourceCustomResponseContentType.Json,\n        body: '{\"message\": \"Vercel handled the webhook using Hookdeck\"}',\n      },\n    },\n  },\n};\n\nmodule.exports = hookdeckConfig;\n```\n\nThis includes request delay, retry, and a rate of delivery:\n\n```javascript\nconst { RetryStrategy, DestinationRateLimitPeriod } = require('@hookdeck/sdk/api');\n\n/** @type {import(\"@hookdeck/vercel\").HookdeckConfig} */\nconst hookdeckConfig = {\n  vercel_url: 'https://my-vercel-project-eta-five-30.vercel.app',\n  match: {\n    '/api/webhook': {\n      name: 'my-webhook-source-name',\n      retry: {\n        strategy: RetryStrategy.Linear,\n        count: 5,\n        interval: 15000, // in ms\n      },\n      delay: 30000, // in ms\n      rate: {\n        limit: 100,\n        period: DestinationRateLimitPeriod.Minute,\n      },\n    },\n  },\n};\n\nmodule.exports = hookdeckConfig;\n```\n\n## Considerations and Limitations\n\n### Removing the Middleware and Going Directly to Hookdeck\n\nThe Hookdeck Vercel middleware adds a hop to every process request, so if milliseconds are a factor in processing requests, you may want to use Hookdeck directly and not use the middleware.\n\nWith the Hookdeck Vercel Middleware:\n\n1. Request to Vercel URL\n2. Forward request to Hookdeck\n3. Request back to Vercel URL (which the middleware passes through)\n\nWithout the Hookdeck Vercel Middleware:\n\n1. Request to Hookdeck Source URL\n2. Request to Vercel URL\n\nYou can remove the middleware by uninstalling the package and removing any configuration and directly using the [Hookdeck Source](https://hookdeck.com/docs/sources?ref=github-hookdeck-vercel) URL where you previously used the Vercel URL, for example, as your Stripe or Shopify webhook URL.\n\n### Parallel Matching\n\nIf you have multiple entries in the config file with the same `match` path, be aware that the middleware will send the request via `fetch` call once per match and will try to do that in parallel. This heavy use is not a common case, but please check [Edge Middleware Limitations](https://vercel.com/docs/functions/edge-middleware/limitations?ref=github-hookdeck-vercel) if you are in this scenario.\n\n## How the Hookdeck Vercel Middleware Works\n\nThe `@hookdeck/vercel` package is supported in the [Vercel Edge Middleware](https://vercel.com/docs/functions/edge-middleware?ref=github-hookdeck-vercel) and executes before a request is processed on your site. This way, the request can be forwarded to Hookdeck and then received again by your specified endpoint, but with all the extra features you may need from Hookdeck, such as queuing, filters, and retry strategies.\n\nThis Hookdeck Vercel Middleware package is used in two stages:\n\n### Deploy/Build\n\nDuring deployment, a `prebuild`` hook checks a configuration file and dynamically creates and configures a [connection](https://hookdeck.com/docs/connections?ref=github-hookdeck-vercel) in Hookdeck:\n\n![Build time](img/build_time.jpg)\n\nFor example, the following `hookdeck.config.js`:\n\n```typescript\n/** @type {import(\"@hookdeck/vercel\").HookdeckConfig} */\nconst hookdeckConfig = {\n  vercel_url: 'https://hookdeck-vercel-example.vercel.app/',\n  match: {\n    '/api/webhooks': {},\n  },\n};\n\nmodule.exports = hookdeckConfig;\n```\n\nResults in something like the following connection being created in Hookdeck:\n\n![Hookdeck Connection](img/hookdeck-connection.png)\n\n### Runtime\n\nThe package also in runtime by sending to Hookdeck the requests that match your configuration:\n\n![Run time](img/run_time.jpg)\n\nWhen your Edge Middleware is triggered (because your middleware config matches), the `withHookdeck` wrapper acts as follows:\n\n- If there is no config file or none of the entries inside `hookdeck.config.js` matches the route, then your `middleware` function is invoked as is.\n  If there are matches with the entries of `hookdeck.config.js` then the following can happen:\n\n  1.  The received request has not been processed by Hookdeck (yet). In this case, your `middleware` function is invoked to obtain a `response`. If the returned value from your `middleware` is `NextResponse.next()` or `next()`, then the request is bounced back to Hookdeck.\n\n      _NOTE_: If you are not using `next/server` or `@vercel/edge`, return a new `Response` with a header `x-middleware-next` with value `\"1\"` if you want you want Hookdeck to manage your request.\n\n  2.  The received request comes from Hookdeck and has been processed. Then, the request is sent to the final route or URL you specified. Your `middleware` function code will not be executed this time.\n\n## Development\n\n### Build\n\n```sh\nnpm run build\n```\n\n### Release\n\nBump the version according to semver.\n\nCommit the changes.\n\nPush the changes to GitHub.\n\nRelease to NPM\n\n```sh\nnpm run release\n```\n\nRelease on GitHub.\n","funding_links":[],"categories":["JavaScript"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhookdeck%2Fhookdeck-vercel","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhookdeck%2Fhookdeck-vercel","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhookdeck%2Fhookdeck-vercel/lists"}