> ## Documentation Index
> Fetch the complete documentation index at: https://docs.lerian.studio/llms.txt
> Use this file to discover all available pages before exploring further.

# Create a Webhook Registration

> Use this endpoint to register a tenant-scoped webhook endpoint that receives transfer event notifications. The registration is scoped to the caller's tenant, derived from the bearer JWT (`tenantId` claim), never from a request header.

The server generates the `signingSecret` and returns it **exactly once** in this response. Store it securely — it is never returned again. Use it to verify the signature on every delivered event. To obtain a new secret, call the rotate endpoint.

Use the `X-Idempotency` header for guaranteed deduplication. Repeated calls with the same key replay the cached response.



## OpenAPI

````yaml /pt/openapi/v3-current/ted.yaml post /v1/webhooks
openapi: 3.0.3
info:
  title: Bank Transfer (TED) Plugin API
  description: >-
    Complete API for Brazilian bank transfers (TED OUT, TED IN, P2P) through the
    Lerian platform, including transfer initiation, processing, status tracking,
    cancellation, and returns.
  version: 3.4.0
servers:
  - url: https://api.example.com
    description: >-
      Replace the example host with the URL provided during environment
      onboarding.
security:
  - BearerAuth: []
  - OAuth2ClientCredentials:
      - api
  - OAuth2Password:
      - api
tags:
  - name: Transfers API
    description: >-
      Endpoints for initiating, processing, tracking, cancelling, and returning
      transfers.
  - name: Webhooks
    description: >-
      Endpoints for registering and managing tenant-scoped webhook subscriptions
      for transfer events.
  - name: Webhook DLQ
    description: Endpoints for inspecting and retrying webhook dead-letter queue messages.
paths:
  /v1/webhooks:
    post:
      tags:
        - Webhooks
      summary: Create a Webhook Registration
      description: >-
        Use this endpoint to register a tenant-scoped webhook endpoint that
        receives transfer event notifications. The registration is scoped to the
        caller's tenant, derived from the bearer JWT (`tenantId` claim), never
        from a request header.


        The server generates the `signingSecret` and returns it **exactly once**
        in this response. Store it securely — it is never returned again. Use it
        to verify the signature on every delivered event. To obtain a new
        secret, call the rotate endpoint.


        Use the `X-Idempotency` header for guaranteed deduplication. Repeated
        calls with the same key replay the cached response.
      operationId: createWebhook
      parameters:
        - $ref: '#/components/parameters/XIdempotencyKey'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateWebhookRequest'
            examples:
              create:
                summary: Subscribe to completed transfers
                value:
                  name: Operations webhook
                  endpointUrl: https://hooks.example.com/transfer-events
                  enabled: true
                  eventTypes:
                    - transfer.completed
                    - transfer.rejected
      responses:
        '201':
          description: >-
            Indicates that the webhook registration was created. The
            `signingSecret` is returned only in this response.


            Repeated calls with the same `X-Idempotency` key replay the cached
            response.


            See [Retries and idempotency](/pt/reference/retries-idempotency) for
            more details.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CreateWebhookResponse'
              examples:
                created:
                  summary: Registration created with signing secret
                  value:
                    id: 550e8400-e29b-41d4-a716-446655440000
                    name: Operations webhook
                    endpointUrl: https://hooks.example.com/transfer-events
                    enabled: true
                    eventTypes:
                      - transfer.completed
                      - transfer.rejected
                    signingSecret: whsec_example_not_a_real_secret
                    createdAt: '2026-02-01T15:30:00Z'
                    updatedAt: '2026-02-01T15:30:00Z'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '409':
          $ref: '#/components/responses/WebhookConflict'
        '422':
          $ref: '#/components/responses/WebhookValidationError'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
components:
  parameters:
    XIdempotencyKey:
      name: X-Idempotency
      in: header
      required: true
      description: >-
        Required idempotency key for safe retries. Use a UUID v4 or a unique
        business identifier, made of letters, digits, `.`, `_`, and `-`. If the
        same key is sent again and the original request was already processed,
        the cached response is returned.


        See [Retries and idempotency](/pt/reference/retries-idempotency) for
        details.
      schema:
        type: string
        maxLength: 255
        pattern: ^[a-zA-Z0-9._-]+$
      example: 019c96a0-aa10-7abc-d1e2-8c9d0e1f2a3b
  schemas:
    CreateWebhookRequest:
      type: object
      required:
        - name
        - endpointUrl
      properties:
        name:
          type: string
          description: A human-readable name for the registration.
          example: Operations webhook
        endpointUrl:
          type: string
          format: uri
          pattern: ^https://
          description: The endpoint that receives event deliveries. Must be an HTTPS URL.
          example: https://hooks.example.com/transfer-events
        enabled:
          type: boolean
          description: Whether the registration is active. Defaults to true when omitted.
          example: true
        eventTypes:
          type: array
          maxItems: 64
          description: >-
            The event types this endpoint subscribes to. When omitted, the
            registration receives every event type. Use the List Webhook Event
            Types endpoint for the accepted values.
          items:
            type: string
          example:
            - transfer.completed
            - transfer.rejected
    CreateWebhookResponse:
      type: object
      allOf:
        - $ref: '#/components/schemas/WebhookRegistrationResponse'
        - type: object
          required:
            - signingSecret
          properties:
            signingSecret:
              type: string
              description: >-
                The server-generated signing secret, returned **only** in this
                response. Store it securely and use it to verify the signature
                on delivered events.
              example: whsec_example_not_a_real_secret
    WebhookRegistrationResponse:
      type: object
      required:
        - id
        - name
        - endpointUrl
        - enabled
        - createdAt
        - updatedAt
      properties:
        id:
          type: string
          format: uuid
          description: The unique identifier of the webhook registration.
          example: 550e8400-e29b-41d4-a716-446655440000
        name:
          type: string
          description: The human-readable name of the registration.
          example: Operations webhook
        endpointUrl:
          type: string
          format: uri
          description: The HTTPS endpoint that receives event deliveries.
          example: https://hooks.example.com/transfer-events
        enabled:
          type: boolean
          description: Whether the registration is active.
          example: true
        eventTypes:
          type: array
          description: >-
            The event types this endpoint subscribes to. Absent when the
            registration receives every event type.
          items:
            type: string
          example:
            - transfer.completed
        createdAt:
          type: string
          format: date-time
          description: The timestamp when the registration was created.
          example: '2026-02-01T15:30:00Z'
        updatedAt:
          type: string
          format: date-time
          description: The timestamp of the last update.
          example: '2026-02-01T15:30:00Z'
    ProblemDocument:
      type: object
      description: >-
        The RFC 9457 problem document that the service answers every error with,
        on `application/problem+json`. Route-specific members (for example
        `refusalCode`, `transactionId`, `ledgerStatus`, `systemplaneKey`) appear
        flat at the top level beside these.
      additionalProperties: true
      required:
        - type
        - title
        - status
        - detail
        - code
        - requestId
        - service
        - category
      properties:
        type:
          type: string
          description: >-
            A URI that names the error code:
            `https://errors.lerian.studio/v1/<code>`.
          example: https://errors.lerian.studio/v1/BTF-0200
        title:
          type: string
          description: The HTTP status text.
          example: Not Found
        status:
          type: integer
          description: The HTTP status code.
          example: 404
        detail:
          type: string
          description: A human-readable explanation of this occurrence.
          example: transfer not found
        instance:
          type: string
          description: The trace ID of this request, when one was recorded.
          example: 4bf92f3577b34da6a3ce929d0e0e4736
        errors:
          type: array
          description: Each rejected field. Present on field validation errors only.
          items:
            type: object
            properties:
              message:
                type: string
                description: Why the value was rejected.
                example: transferId must be a valid UUID
              location:
                type: string
                description: 'Where the value sits: `body.<field>` or `query.<field>`.'
                example: body.senderAccountId
        code:
          type: string
          description: The stable BTF error code.
          example: BTF-0200
        upstream:
          type: object
          description: >-
            The error that an upstream provider (JD SPB, Midaz) reported. Absent
            unless surfaced.
          properties:
            code:
              type: string
              description: The provider's own error code, verbatim.
              example: AAC90
            message:
              type: string
              description: The provider's own error message, bounded.
              example: Assinatura invalida
        requestId:
          type: string
          description: The request correlation ID. Present even when empty.
          example: 6d3e2a68-1f2b-4c3d-9e4f-5a6b7c8d9e0f
        service:
          type: string
          description: The system that produced the error.
          example: plugin
        category:
          type: string
          description: The machine-readable error category.
          example: deterministic
  responses:
    BadRequest:
      description: Indicates that the request contains invalid input.
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/ProblemDocument'
          examples:
            invalidInput:
              summary: Validation error
              value:
                type: https://errors.lerian.studio/v1/BTF-0001
                title: Bad Request
                status: 400
                detail: invalid request body
                code: BTF-0001
                category: deterministic
                requestId: 6d3e2a68-1f2b-4c3d-9e4f-5a6b7c8d9e0f
                service: plugin
    Unauthorized:
      description: Indicates that the request is missing a valid authentication token.
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/ProblemDocument'
          examples:
            unauthorized:
              summary: Missing authorization
              value:
                type: https://errors.lerian.studio/v1/BTF-0401
                title: Unauthorized
                status: 401
                detail: Missing Token
                code: BTF-0401
                category: plugin
                requestId: 6d3e2a68-1f2b-4c3d-9e4f-5a6b7c8d9e0f
                service: plugin
    Forbidden:
      description: >-
        Indicates that the caller is authenticated but lacks permission for this
        operation.
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/ProblemDocument'
          examples:
            permissionDenied:
              summary: Caller lacks permission
              value:
                type: https://errors.lerian.studio/v1/BTF-0405
                title: Forbidden
                status: 403
                detail: >-
                  the credential is not allowed to perform transfers:create on
                  this request
                code: BTF-0405
                category: plugin
                requestId: 6d3e2a68-1f2b-4c3d-9e4f-5a6b7c8d9e0f
                service: plugin
    WebhookConflict:
      description: >-
        Indicates that a webhook registration with the same endpoint already
        exists for this tenant.
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/ProblemDocument'
          examples:
            duplicate:
              summary: Endpoint already registered
              value:
                type: https://errors.lerian.studio/v1/BTF-0012
                title: Conflict
                status: 409
                detail: webhook registration already exists
                code: BTF-0012
                category: deterministic
                requestId: 6d3e2a68-1f2b-4c3d-9e4f-5a6b7c8d9e0f
                service: plugin
    WebhookValidationError:
      description: >-
        Indicates that the webhook payload violated a domain constraint, such as
        an invalid endpoint URL or an unsupported event type.
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/ProblemDocument'
          examples:
            invalidEventType:
              summary: Unsupported event type
              value:
                type: https://errors.lerian.studio/v1/BTF-0002
                title: Unprocessable Entity
                status: 422
                detail: >-
                  create webhook registration: webhook registration event type
                  is unsupported: transfer.unknown
                code: BTF-0002
                category: deterministic
                requestId: 6d3e2a68-1f2b-4c3d-9e4f-5a6b7c8d9e0f
                service: plugin
    ServiceUnavailable:
      description: >-
        Indicates that a dependency of this service is unavailable or is not
        configured in this deployment.
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/ProblemDocument'
          examples:
            repositoryUnavailable:
              summary: Repository unavailable
              value:
                type: https://errors.lerian.studio/v1/BTF-9008
                title: Service Unavailable
                status: 503
                detail: transfer repository unavailable
                code: BTF-9008
                category: transient
                requestId: 6d3e2a68-1f2b-4c3d-9e4f-5a6b7c8d9e0f
                service: plugin
            dlqInspectorUnavailable:
              summary: DLQ inspector not configured
              value:
                type: https://errors.lerian.studio/v1/BTF-9005
                title: Service Unavailable
                status: 503
                detail: DLQ inspector is not configured
                code: BTF-9005
                category: deterministic
                requestId: 6d3e2a68-1f2b-4c3d-9e4f-5a6b7c8d9e0f
                service: plugin
  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: >-
        JWT Bearer token authentication. The tenantId is derived from the bearer
        token or authenticated request context and is not supplied through
        X-Organization-Id.
    OAuth2ClientCredentials:
      type: oauth2
      flows:
        clientCredentials:
          tokenUrl: /v1/login/oauth/access_token
          scopes:
            api: TED transfer API access
    OAuth2Password:
      type: oauth2
      flows:
        password:
          tokenUrl: /v1/login/oauth/access_token
          scopes:
            api: TED transfer API access

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.