> 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 in the Fern Definition > Learn how to define webhooks in the Fern Definition Fern Definition isn't recommended for new customers and Fern isn't accepting feature requests for this format. It remains supported for existing users. In Fern, you can specify webhooks in your API definition. The webhooks will be included in both the generated SDKs and the API documentation. ## Webhook definition Each webhook defines: 1. **Method**: The HTTP Method that the webhook will use (either `GET` or `POST`) 2. **Headers**: The headers that the webhook will send 3. **Payload**: The schema of the webhook payload #### webhooks.yml ```yaml {2-10} webhooks: paymentNotification: display-name: Payment Notification docs: Receive a notification when a payment changes status method: POST headers: X-Signature-Primary: type: string docs: An HMAC signature of the payload payload: PaymentNotificationPayload types: PaymentNotificationPayload: discriminant: notificationType union: queued: QueuedPaymentNotification processing: ProcessingPaymentNotification completed: CompletedPaymentNotification ``` ### Inlined payloads You can inline the schema of the payload by doing the following: #### webhooks.yml ```yaml webhooks: paymentNotification: display-name: Payment Notification docs: Receive a notification when a payment changes status method: POST headers: X-Signature-Primary: type: string docs: An HMAC signature of the payload payload: name: PaymentNotificationPayload properties: id: type: string docs: The notification id amount: double currency: Currency ``` ## 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 # Directory containing webhook definition ``` Or you can configure individual documentation pages per webhook event: **`docs.yml`** ```yaml title="docs.yml" navigation: - subpackage_api.newPlantWebhook # Format: subpackage_{name-of-api}.{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). You can configure webhook signature verification directly in your Fern Definition using the `webhook-signature` block. When configured, Fern generates SDK utilities that allow users to verify webhook signatures and ensure events originate from your API. Configuration can be set at the **document level** (applies to all webhooks) or **per-webhook** (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). #### Document-level **`api.yml`** ```yaml title="api.yml" webhook-signature: type: hmac header: x-webhook-signature algorithm: sha256 encoding: hex webhooks: userCreated: method: POST payload: UserCreatedPayload # Inherits document-level signature config orderCompleted: method: POST payload: OrderCompletedPayload # Inherits document-level signature config ``` #### Per-webhook override **`api.yml`** ```yaml title="api.yml" webhook-signature: type: hmac header: x-webhook-signature algorithm: sha256 encoding: hex webhooks: paymentNotification: method: POST payload: PaymentNotificationPayload signature: # Override: use asymmetric instead of HMAC type: asymmetric header: x-payment-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-payment-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 in the Fern Definition