Define & Validate APIsOpenAPI Extensions

Webhook and Callback Extensions

Group webhooks and callbacks, route incoming events by a discriminator, and describe how to verify their signatures with x-webhooks and x-callbacks.

OpenAPI 3.x describes the requests your API sends to clients as webhooks (the root webhooks object) and callbacks (an operation's callbacks). The x-webhooks and x-callbacks extensions, at the root of your definition, add what a client needs to handle these requests:

  • Groups of related webhooks or callbacks.
  • A discriminator that tells which webhook or callback an incoming request is.
  • Signature verification that tells how to check that a request came from your API.

x-webhooks and x-callbacks work the same way. Each takes one of two shapes: a single group written directly under the extension, or several named groups. You can't mix the two shapes in one extension.

For which SDK languages support webhooks and callbacks, see Languages & Features.

Use a single group

When all your webhooks share the same discriminator and signature, put description, discriminator, and signatureVerification directly under the extension. APIMatic imports them as one group named default, and every webhook or callback without a group belongs to it.

x-webhooks:
  description: Payment status events
  discriminator:
    propertyPointer: $request.body#/event_type
    mapping:
      payment.created: paymentCreated
      payment.updated: paymentUpdated
  signatureVerification:
    signatureHeader: X-Webhook-Signature
    timestampHeader: X-Webhook-Timestamp
    replayTolerance: 300
    signatureTemplate: "t={$request.header.X-Webhook-Timestamp},sha256=hex(hmacSha256({$request.header.X-Webhook-Timestamp}.{$request.body}))"

webhooks:
  paymentCreated:
    post:
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/PaymentEvent"
  paymentUpdated:
    post:
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/PaymentEvent"
PropertyTypeDescription
descriptionstringDescription of the group
discriminatorDiscriminatorHow to tell the webhooks or callbacks apart
signatureVerificationSignature verificationHow to verify the signature of a request

In this shape, the discriminator's propertyPointer can point to a top-level property of the request body, such as $request.body#/event_type, or to a request header, such as $request.header.X-Event-Type.

Signature verification

PropertyTypeDescription
signatureHeaderstringRequired. Request header that carries the signature, for example X-Webhook-Signature
signatureTemplatestringRequired. Template of the full value of the signature header. See below.
timestampHeaderstringRequest header that carries the time the request was sent, in Unix seconds. Set it together with replayTolerance.
replayToleranceintegerAllowed clock difference, in seconds, for replay protection. A positive number, set together with timestampHeader.
descriptionstringDescription of the verification

The signatureTemplate contains at least one digest block of the form encoding(algorithm(message)):

  • encoding is hex, base64, or base64url.
  • algorithm is hmacSha256 or hmacSha512.
  • message is the signed content. It can't be empty.

The message and the text around the digest block can contain the placeholders {$request.body} (the raw request body) and {$request.header.Name} (the value of request header Name). Placeholders inside the digest block are signed; text and placeholders outside it are only part of the header's format.

TemplateHeader value
sha512=base64(hmacSha512({$request.body}))sha512= followed by the Base64 HMAC-SHA512 of the body
t={$request.header.X-Timestamp},v1=hex(hmacSha256({$request.header.X-Timestamp}.{$request.body}))t= and the timestamp, then ,v1= and the hex HMAC-SHA256 of the timestamp, a period, and the body

Use named groups

When your webhooks or callbacks need different discriminators or signatures, define several groups. Each key under the extension is a group name.

x-webhooks:
  rides:
    description: Ride lifecycle events
    discriminator:
      propertyPointer: $request.body#/event_type
      mapping:
        ride.status.updated: rideStatusUpdated
        driver.assigned: driverAssigned
    payloadVerification:
      signatureHeader: X-Signature
      algorithm: HMAC-SHA256
      digestEncoding: hex
      messageTemplate: "{$request.body}"
      signatureValueTemplate: "sha256={digest}"
PropertyTypeDescription
descriptionstringDescription of the group
discriminatorDiscriminatorHow to tell the group's webhooks or callbacks apart. The propertyPointer must point into the request body.
payloadVerificationPayload verificationHow to verify the signature of a request. See below.

Because description, discriminator, signatureVerification, and payloadVerification mark the single-group shape, you can't use them as group names. A named group uses payloadVerification, not signatureVerification.

Payload verification

PropertyTypeDescription
signatureHeaderstringRequired. Request header that carries the signature
algorithmHMAC-SHA256 or HMAC-SHA512Required. Signing algorithm
digestEncodinghex, base64, or base64urlEncoding of the digest
messageTemplatestringTemplate of the signed message. See below.
signatureValueTemplatestringTemplate of the signature header's value. Must contain {digest}, for example sha256={digest}.
descriptionstringDescription of the verification

messageTemplate can contain these placeholders, separated by exactly one character, such as a period:

PlaceholderValue
{$request.body}Raw request body
{$method}HTTP method
{$request.header.Name}Value of request header Name
{$request.body#/path}Value at a JSON pointer in the request body

Assign webhooks and callbacks to a group

With named groups, assign each webhook or callback to its group by setting x-webhook-group or x-callback-group in its Operation Object. The value must be the name of a group in x-webhooks or x-callbacks.

webhooks:
  rideStatusUpdated:
    post:
      x-webhook-group: rides
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/RideStatusEvent"

paths:
  /rides:
    post:
      callbacks:
        rideStatusUpdatedCallback:
          "{$request.body#/callback_url}":
            post:
              x-callback-group: rideUpdates
              requestBody:
                content:
                  application/json:
                    schema:
                      $ref: "#/components/schemas/RideStatusEvent"

With a single group, you don't need these extensions: webhooks and callbacks without one belong to the default group.

Discriminator

The discriminator tells which webhook or callback an incoming request is.

PropertyTypeDescription
propertyPointerstringWhere the event type is in the request, for example $request.body#/event_type
mappingmap of stringsMaps each event type value to the name of a webhook (a key of webhooks) or callback (a key of an operation's callbacks)

Validation

The rules for these extensions are in the OpenAPI Webhooks, OpenAPI Callbacks, and OpenAPI Webhook and Callback Signature Verification sections of OpenAPI v3 APIMatic Linting, and in the Webhooks section of APIMatic CodeGen Validation.

On this page