> For clean Markdown content of this page, append .md to this URL. For the complete documentation index, see https://buildwithfern.com/learn/llms.txt. # Webhooks > Learn how to define webhooks using OpenAPI 3.1 native support or Fern's extensions. Generate webhook docs and SDK verification utilities. Fern supports two methods for defining webhooks in your OpenAPI specification: 1. Using OpenAPI 3.1's native webhook support (recommended) 2. Using Fern's `x-fern-webhook` extension ## OpenAPI 3.1 webhooks For OpenAPI 3.1 specifications, use the `webhooks` top-level field to define your webhook operations. Each webhook requires an `operationId` to be properly processed by Fern. **`openapi.yml`** ```yaml openapi.yml {4, 7-8, 42-48} webhooks: newPlant: post: operationId: newPlantWebhook # Defines webhook summary: New Plant Added description: Information about a new plant that was added to the store tags: - Plants # Creates dedicated page requestBody: description: The plant data when a new plant is added content: application/json: schema: description: The Webhook payload for when a new plant is added to the store properties: triggerType: description: The type of event that triggered the request type: string example: "new_plant" payload: type: object description: The payload of data sent from the plant store properties: plantId: type: string description: The unique identifier for the plant example: "64f1a2b3c5d6e7f8a9b0c1d2" name: type: string description: The name of the plant example: "Monstera Deliciosa" price: type: number format: float description: The price of the plant in dollars example: 29.99 addedAt: type: string format: date-time description: The timestamp when the plant was added example: "2024-01-15T10:30:00.000Z" example: # Full payload example for docs triggerType: "new_plant" payload: plantId: "64f1a2b3c5d6e7f8a9b0c1d2" name: "Monstera Deliciosa" price: 29.99 addedAt: "2024-01-15T10:30:00.000Z" responses: '200': description: Return a 200 status to indicate that the data was received successfully ``` ## Fern webhook extension For OpenAPI 3.0, use the `x-fern-webhook: true` extension to define webhooks. Fern will treat the `requestBody` as the webhook payload. **`openapi.yml`** ```yaml openapi.yml {6-8, 23-25} paths: /payment/updated/: post: summary: Payment Initiated operationId: initiatePayment tags: - Payments # Creates dedicated page x-fern-webhook: true # Defines webhooks requestBody: content: application/json: schema: type: object properties: amount: type: number example: 99.99 currency: $ref: '#/components/schemas/Currency' required: - amount - currency example: # Full payload example for docs amount: 99.99 currency: "USD" ``` The path that you choose when defining a webhook can be arbitrary. Since webhooks can be sent to any server, Fern just ignores the path. ## Generate webhook reference Fern Docs can automatically generate your webhook reference documentation from your definition. Set this up in your `docs.yml` file. Your webhook reference can be a single documentation page: **`docs.yml`** ```yml docs.yml navigation: - api: Webhook Reference # Display name for this page api-name: webhooks-v1 # Name of webhook definition directory ``` Or you can configure individual documentation pages per webhook event: **`docs.yml`** ```yaml title="docs.yml" navigation: - subpackage_plants.newPlantWebhook # subpackage_{tag}.{webhook-event-name} ``` For more information on how to configure your webhook reference in `docs.yml`, see [Generate your webhook reference](/learn/docs/api-references/generate-webhook-ref). ## SDK signature verification #### Enterprise feature for SDKs Using this feature in generated SDKs requires the [Enterprise plan](https://buildwithfern.com/pricing). To get started, reach out to [support@buildwithfern.com](mailto:support@buildwithfern.com). Use the `x-fern-webhook-signature` extension to configure webhook signature verification. When configured, Fern generates a [`WebhooksHelper` class](/learn/sdks/deep-dives/webhook-signature-verification) in the TypeScript, Python, Java, Go, PHP, Ruby, and C# SDKs that allows users to verify webhook signatures and ensure events originate from your API. Configuration can be set at the **document level** (applies to all webhook endpoints) or **per-endpoint** (overrides the document-level default). Both levels accept the same configuration options. Fern supports two verification methods: **HMAC** (symmetric key verification using shared secrets) and **Asymmetric** (public key verification using RSA, ECDSA, or Ed25519 keys). Providers that sign the notification URL rather than the body transmit a hash of the body as a query parameter on that URL; declare that parameter under `body-hash-binding` so the generated helper verifies the hash and the signature. #### Document-level **`openapi.yml`** ```yaml title="openapi.yml" x-fern-webhook-signature: type: hmac header: x-webhook-signature algorithm: sha256 encoding: hex paths: /webhooks/payment: post: x-fern-webhook: true # Inherits document-level signature config /webhooks/order: post: x-fern-webhook: true # Inherits document-level signature config ``` #### Per-endpoint override **`openapi.yml`** ```yaml title="openapi.yml" x-fern-webhook-signature: type: hmac header: x-webhook-signature algorithm: sha256 encoding: hex paths: /webhooks/payment: post: x-fern-webhook: true # Inherits document-level config /webhooks/refund: post: x-fern-webhook: true x-fern-webhook-signature: # Override with asymmetric type: asymmetric header: x-refund-signature asymmetric-algorithm: rsa-sha256 encoding: base64 jwks-url: https://api.example.com/.well-known/jwks.json payload-format: components: [timestamp, body] delimiter: "." timestamp: header: x-refund-timestamp format: unix-seconds tolerance: 300 ``` ### Configuration options #### Common fields These fields apply to both HMAC and asymmetric verification. **`type`** `'hmac' | 'asymmetric'` — required The signature verification method. Use `hmac` for symmetric key verification with shared secrets, or `asymmetric` for public key verification. --- **`header`** `string` — required The HTTP header containing the signature. For example, `x-webhook-signature` or `x-hub-signature-256`. --- **`encoding`** `'base64' | 'hex'` — default: base64 The encoding format of the signature value in the header. --- **`signature-prefix`** `string` A prefix to strip from the signature header value before verification. For example, `"sha256="` or `"rsa="`. --- **`timestamp.header`** `string` HTTP header containing the delivery timestamp. Required when `timestamp` is configured. --- **`timestamp.format`** `'unix-seconds' | 'unix-millis' | 'iso8601'` — default: unix-seconds Format of the timestamp value in the header. --- **`timestamp.tolerance`** `integer` — default: 300 Allowed clock skew in seconds. Requests with timestamps outside this window are rejected. --- #### HMAC fields These fields apply when `type` is set to `hmac`. **`algorithm`** `'sha256' | 'sha1' | 'sha384' | 'sha512'` — default: sha256 The HMAC hash algorithm for signature computation. `sha256` is recommended. `sha1` is deprecated and should only be used for legacy compatibility. --- **`payload-format.components`** `list of strings` Ordered list of payload components to concatenate before hashing. When omitted, only the raw request body is signed. Available components: | Component | Description | | ------------------ | ------------------------------------- | | `body` | Raw request body | | `timestamp` | Timestamp value from timestamp header | | `notification-url` | The webhook/callback URL | | `message-id` | Provider-assigned message identifier | --- **`payload-format.delimiter`** `string` String used to join the components. Use `"."` for timestamp-prefixed payloads or `""` for direct concatenation. Required when `payload-format.components` is set. --- **`body-hash-binding.algorithm`** `'sha256' | 'sha1' | 'sha384' | 'sha512'` — required Hash algorithm applied to the raw request body. Independent of `algorithm`, which applies to the signature itself. Set `body-hash-binding` when the provider transmits a hash of the body alongside a signature computed over the notification URL. --- **`body-hash-binding.encoding`** `'base64' | 'hex'` — default: base64 Encoding of the transmitted body hash. --- **`body-hash-binding.location.type`** `'query-parameter'` — required Where the body hash is transmitted. Query parameters on the notification URL are the only supported location. --- **`body-hash-binding.location.name`** `string` — required Name of the query parameter carrying the body hash. --- #### Asymmetric fields These fields apply when `type` is set to `asymmetric`. **`asymmetric-algorithm`** `'rsa-sha256' | 'rsa-sha384' | 'rsa-sha512' | 'ecdsa-sha256' | 'ecdsa-sha384' | 'ecdsa-sha512' | 'ed25519'` — required The asymmetric signing algorithm. `rsa-sha256` and `ecdsa-sha256` are widely supported defaults. `ed25519` is a modern, efficient option. --- **`payload-format.components`** `list of strings` Ordered list of payload components to concatenate before signing. When omitted, only the raw request body is signed. Available components: | Component | Description | | ------------------ | ------------------------------------- | | `body` | Raw request body | | `timestamp` | Timestamp value from timestamp header | | `notification-url` | The webhook/callback URL | | `message-id` | Provider-assigned message identifier | Without `timestamp` in the components list, the `timestamp.tolerance` check can't protect against replay attacks because the timestamp is unauthenticated. Include `timestamp` to ensure replay protection. --- **`payload-format.delimiter`** `string` String used to join the components. Use `"."` for timestamp-prefixed payloads or `""` for direct concatenation. Required when `payload-format.components` is set. --- **`jwks-url`** `string` JSON Web Key Set (JWKS) endpoint URL of the key retrieval service. Required when using JWKS-based key rotation; omit for static key verification. --- **`key-id-header`** `string` HTTP header containing the key ID used to select the correct key from the JWKS endpoint. --- > Learn how to define webhooks using OpenAPI 3.1 native support or Fern's extensions. Generate webhook docs and SDK verification utilities.