Webhook Endpoints

The TapTree Webhook Endpoints API gives you full programmatic control over the static webhook endpoints registered to your organization, scoped to the environment bound to the API key you authenticate with. Use these endpoints to provision receivers from your infrastructure-as-code pipeline, rotate signing secrets on a schedule, or surface endpoint state in your own dashboards.

The same surface is available via the TapTree Dashboard under Entwickler → Webhooks — see Static Webhook Endpoints for the signing-secret design and signature-verification recipe. API and dashboard are interchangeable: every endpoint created here shows up in the dashboard immediately and vice versa.

Discover the Webhook Endpoints resource using Postman:

TapTree Postman Collection

Endpoints

Create a webhook endpoint

POST/v1/webhooks

Register a new static webhook endpoint and receive the one-shot signing-secret reveal.

List webhook endpoints

GET/v1/webhooks

Retrieve every webhook endpoint configured for the api-key’s environment.

Retrieve a webhook endpoint

GET/v1/webhooks/:id

Fetch a single webhook endpoint by id.

Update a webhook endpoint

PATCH/v1/webhooks/:id

Patch mutable fields (name, description, url, event_types, state). Uses OCC via If-Match.

Rotate a webhook endpoint signing secret

POST/v1/webhooks/:id/rotate-secret

Generate a new signing secret with optional grace window and receive the one-shot reveal.

Delete a webhook endpoint

DELETE/v1/webhooks/:id

Soft-delete a webhook endpoint. No future events are delivered; audit history is retained.

Authentication

All endpoints use v2 API keys. Required scopes:

  • Name
    webhooks:read
    Type
    scope
    Description

    Required for GET /v1/webhooks (list) and GET /v1/webhooks/:id (retrieve).

  • Name
    webhooks:write
    Type
    scope
    Description

    Required for POST /v1/webhooks (create), PATCH /v1/webhooks/:id (update) and DELETE /v1/webhooks/:id.

  • Name
    webhooks:rotate_secret
    Type
    scope
    Description

    Required for POST /v1/webhooks/:id/rotate-secret. Separate from webhooks:write so an automation key can rotate secrets without being able to also change url or event_types.

Mint a key with the relevant scopes in the dashboard under Entwickler → API-Schlüssel before calling.

Authentication header

Authorization: Bearer tt_live_pri_…

A key bound to the Live environment can only see and mutate live endpoints; a key bound to a Sandbox environment is scoped to that sandbox. There is no env query parameter and no fallback — the environment is server-bound at mint time. If you need both, mint one key per environment.

The webhook endpoint model

The webhook endpoint model describes a static destination registered for your organization plus the operational state we track for it (failure counter, circuit-breaker state, last successful delivery timestamp).

Core attributes

  • Name
    id
    Type
    string
    Description

    Unique identifier for the webhook endpoint.

  • Name
    environment_id
    Type
    string
    Description

    Identifier for the environment the endpoint is scoped to. Matches the environment bound to the calling API key.

  • Name
    acceptor_id
    Type
    string
    Description

    Identifier for the payment acceptor the endpoint is scoped to, or null if the endpoint receives events for every acceptor in your organization.

  • Name
    name
    Type
    string
    Description

    Operator-supplied label for the endpoint. 1–255 characters.

  • Name
    description
    Type
    string
    Description

    Optional longer description of what the endpoint is for. Up to 2000 characters; empty string when unset.

  • Name
    url
    Type
    string
    Description

    HTTPS URL the endpoint delivers events to. http:// URLs are rejected at create time outside of explicit dev environments — see URL requirements.

  • Name
    transport
    Type
    string
    Description

    Transport channel used to deliver the event. Currently always http — payloads are sent over HTTPS via a standard POST to the endpoint's url. The field is reserved for future transports (e.g. queue-based fan-out).

  • Name
    event_types
    Type
    array
    Description

    Event-type subscriptions for the endpoint. Each entry is either a concrete event-type token (transactions.payment.paid) or one of the wildcard forms (transactions.payment.*, transactions.*, *) documented in Static Endpoints → Configure step 3. 1–64 entries, each up to 128 characters.

  • Name
    state
    Type
    string
    Description

    Current lifecycle state of the endpoint.

    Possible values: active paused auto_disabled

    auto_disabled indicates the delivery circuit breaker has tripped after consecutive failures — events are paused until tripped_until passes or the endpoint is re-enabled. paused is a manual operator action and is the only value that can be set via the API (alongside active). Soft-deleted endpoints are filtered out of every response.

  • Name
    signing_algo
    Type
    string
    Description

    Algorithm used to sign delivered payloads. Currently always hmac-sha256-v2. See Webhook Signing Secrets for the verification recipe.

  • Name
    consecutive_failures
    Type
    integer
    Description

    Count of consecutive delivery failures since the last successful 2xx. Resets to 0 on success.

  • Name
    last_success_at
    Type
    datetime
    Description

    Timestamp of the most recent successful (2xx) delivery, in ISO 8601 format. null until the first successful delivery.

  • Name
    tripped_until
    Type
    datetime
    Description

    Timestamp until which the circuit breaker keeps deliveries paused. null when state is not auto_disabled.

  • Name
    row_version
    Type
    integer
    Description

    Optimistic-concurrency counter incremented on every mutation. Send the current value in the If-Match header on PATCH, DELETE and rotate-secret calls to guarantee you’re modifying the row you think you are.

  • Name
    created_at
    Type
    datetime
    Description

    Timestamp of when the endpoint was created, in ISO 8601 format.

  • Name
    updated_at
    Type
    datetime
    Description

    Timestamp of the most recent mutation (configuration change, state transition, signing-secret rotation), in ISO 8601 format.

Response object

{
 "object": "webhook_endpoint",
 "id": "1252416694177497000",
 "environment_id": "8419223344005061000",
 "acceptor_id": "5028111769322011000",
 "name": "Orders production",
 "description": "Routes payment + refund events to order-service.",
 "url": "https://api.example.com/webhooks/taptree",
 "transport": "http",
 "event_types": [
   "transactions.payment.*",
   "transactions.refund.refunded"
 ],
 "state": "active",
 "signing_algo": "hmac-sha256-v2",
 "consecutive_failures": 0,
 "last_success_at": "2026-05-19T09:14:02.118Z",
 "tripped_until": null,
 "row_version": 3,
 "created_at": "2026-04-12T11:02:33.001Z",
 "updated_at": "2026-05-04T16:42:11.044Z"
}

POST/v1/webhooks

Create a webhook endpoint

Register a new webhook endpoint and receive a one-shot reveal of the freshly minted plaintext signing secret. The response is the only place the plaintext ever leaves our infrastructure — capture plaintext_secret and public_secret_id immediately. The secret itself is stored envelope-encrypted at rest and cannot be re-fetched. If you lose it, rotate.

Requires the webhooks:write scope.

Request body

  • Name
    name
    Type
    string
    Description

    Display label, 1–255 characters. Shown in the dashboard list view.

  • Name
    url
    Type
    string
    Description

    Destination URL. Must be https:// (or http:// only in explicitly-enabled dev environments). 1–2048 characters.

  • Name
    event_types
    Type
    array
    Description

    Non-empty array of event-type tokens or wildcards. 1–64 entries.

  • Name
    description
    Type
    string
    Description

    Optional, up to 2000 characters. Omit or pass an empty string when unused.

  • Name
    acceptor_id
    Type
    string
    Description

    Optional bigint string. Required only if the calling API key is not bound to a specific acceptor; otherwise the bound acceptor is used and supplying a different value rejects with 400.

  • Name
    signing_algo
    Type
    string
    Description

    Optional. Currently must be omitted or hmac-sha256-v2 — kept explicit so future algorithm bumps stay opt-in.

Possible response statuses

  • Name
    201 Created
    Type
    status
    Description

    The endpoint was created. Body is the endpoint object plus plaintext_secret and public_secret_id for the one-shot reveal.

  • Name
    400 Bad Request
    Type
    status
    Description

    Body validation failed (missing field, value out of range, malformed URL, etc.). The response detail field carries a human-readable reason; tokens, secrets and PII are never echoed.

  • Name
    401 Unauthorized
    Type
    status
    Description

    The bearer token is missing, malformed, or not active.

  • Name
    403 Forbidden
    Type
    status
    Description

    The key authenticated but does not carry the webhooks:write scope.

  • Name
    409 Conflict
    Type
    status
    Description

    An endpoint with the same url already exists in this environment. Either reuse it, choose a different URL, or delete the conflicting endpoint first.

Request

POST
/v1/webhooks
curl -X POST https://api.taptree.org/v1/webhooks \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Orders production",
    "url": "https://api.example.com/webhooks/taptree",
    "event_types": ["transactions.payment.*", "transactions.refund.refunded"],
    "description": "Routes payment + refund events to order-service."
  }'

Example response

{
  "object": "webhook_endpoint",
  "id": "1252416694177497000",
  "environment_id": "8419223344005061000",
  "acceptor_id": "5028111769322011000",
  "name": "Orders production",
  "description": "Routes payment + refund events to order-service.",
  "url": "https://api.example.com/webhooks/taptree",
  "transport": "http",
  "event_types": [
    "transactions.payment.*",
    "transactions.refund.refunded"
  ],
  "state": "active",
  "signing_algo": "hmac-sha256-v2",
  "consecutive_failures": 0,
  "last_success_at": null,
  "tripped_until": null,
  "row_version": 1,
  "created_at": "2026-05-19T12:02:33.001Z",
  "updated_at": "2026-05-19T12:02:33.001Z",
  "public_secret_id": "whsec_id_3a8b29",
  "plaintext_secret": "whsec_aa11bb22cc33dd44ee55ff66aa77bb88cc99dd00ee11ff2233445566778899"
}

GET/v1/webhooks

List webhook endpoints

Retrieve every webhook endpoint configured for the environment bound to your API key. There is no pagination today because organizations rarely operate more than a handful of static endpoints; if your operating model changes, contact support.

Requires the webhooks:read scope. Soft-deleted endpoints are filtered out at the server. Results are returned sorted by created_at descending, with id as a stable tie-breaker. An environment with no configured endpoints returns { "object": "list", "data": [] }.

Possible response statuses

  • Name
    200 OK
    Type
    status
    Description

    The list was returned successfully. data is an array (possibly empty) of endpoint objects.

  • Name
    401 Unauthorized
    Type
    status
    Description

    Missing or invalid bearer token.

  • Name
    403 Forbidden
    Type
    status
    Description

    The key authenticated but does not carry the webhooks:read scope.

  • Name
    503 Service Unavailable
    Type
    status
    Description

    Resolver not yet provisioned (transient during a rolling deploy). Retry with exponential backoff.

Request

GET
/v1/webhooks
curl https://api.taptree.org/v1/webhooks \
  -H "Authorization: Bearer {token}"

Example response

{
  "object": "list",
  "data": [
    {
      "id": "1252416694177497000",
      "environment_id": "8419223344005061000",
      "acceptor_id": "5028111769322011000",
      "name": "Orders production",
      "description": "Routes payment + refund events to order-service.",
      "url": "https://api.example.com/webhooks/taptree",
      "transport": "http",
      "event_types": [
        "transactions.payment.*",
        "transactions.refund.refunded"
      ],
      "state": "active",
      "signing_algo": "hmac-sha256-v2",
      "consecutive_failures": 0,
      "last_success_at": "2026-05-19T09:14:02.118Z",
      "tripped_until": null,
      "row_version": 3,
      "created_at": "2026-04-12T11:02:33.001Z",
      "updated_at": "2026-05-04T16:42:11.044Z"
    }
  ]
}

GET/v1/webhooks/:id

Retrieve a webhook endpoint

Fetch a single webhook endpoint by its id. Returns the same shape as the list response, plus the current row_version you’ll need to pass back in If-Match for subsequent mutations.

Requires the webhooks:read scope.

Possible response statuses

  • Name
    200 OK
    Type
    status
    Description

    The endpoint object.

  • Name
    401 Unauthorized
    Type
    status
    Description

    Missing or invalid bearer token.

  • Name
    403 Forbidden
    Type
    status
    Description

    Scope missing.

  • Name
    404 Not Found
    Type
    status
    Description

    No endpoint with that id exists in the calling key’s environment, or the endpoint was soft-deleted. The 404 also covers "exists-in-another-environment" cases so existence across environment boundaries is not leaked.

Request

GET
/v1/webhooks/:id
curl https://api.taptree.org/v1/webhooks/1252416694177497000 \
  -H "Authorization: Bearer {token}"

Example response

{
  "object": "webhook_endpoint",
  "id": "1252416694177497000",
  "environment_id": "8419223344005061000",
  "acceptor_id": "5028111769322011000",
  "name": "Orders production",
  "description": "Routes payment + refund events to order-service.",
  "url": "https://api.example.com/webhooks/taptree",
  "transport": "http",
  "event_types": [
    "transactions.payment.*",
    "transactions.refund.refunded"
  ],
  "state": "active",
  "signing_algo": "hmac-sha256-v2",
  "consecutive_failures": 0,
  "last_success_at": "2026-05-19T09:14:02.118Z",
  "tripped_until": null,
  "row_version": 3,
  "created_at": "2026-04-12T11:02:33.001Z",
  "updated_at": "2026-05-04T16:42:11.044Z"
}

PATCH/v1/webhooks/:id

Update a webhook endpoint

Patch mutable fields on an existing endpoint. Send only the fields you want to change. Uses optimistic concurrency: pass the endpoint’s current row_version in If-Match; a stale value rejects with 409.

Requires the webhooks:write scope.

Request headers

  • Name
    If-Match
    Type
    header
    Description

    The current row_version of the endpoint as a quoted strong ETag, e.g. If-Match: "3". Missing → 428 Precondition Required. Stale → 409 Conflict with the current value in the response body so you can refetch + retry.

Mutable fields

  • Name
    name
    Type
    string
    Description

    1–255 characters.

  • Name
    description
    Type
    string
    Description

    Up to 2000 characters.

  • Name
    url
    Type
    string
    Description

    HTTPS URL, 1–2048 characters.

  • Name
    event_types
    Type
    array
    Description

    Non-empty array, 1–64 entries, each ≤128 characters.

  • Name
    state
    Type
    string
    Description

    active or paused. The breaker-driven auto_disabled state is server-managed and cannot be set directly.

acceptor_id, signing_algo and identifiers are not patchable — create a new endpoint if you need a different acceptor binding.

Possible response statuses

  • Name
    200 OK
    Type
    status
    Description

    The patched endpoint object with the new row_version value.

  • Name
    400 Bad Request
    Type
    status
    Description

    Body validation failed, or no mutable field was supplied.

  • Name
    401 Unauthorized
    Type
    status
    Description

    Missing or invalid bearer token.

  • Name
    403 Forbidden
    Type
    status
    Description

    Scope missing.

  • Name
    404 Not Found
    Type
    status
    Description

    Endpoint id not visible to this key.

  • Name
    409 Conflict
    Type
    status
    Description

    row_version mismatch — somebody else mutated the row between your read and write. Body carries current_row_version for the retry.

  • Name
    428 Precondition Required
    Type
    status
    Description

    If-Match header missing.

Request

PATCH
/v1/webhooks/:id
curl -X PATCH https://api.taptree.org/v1/webhooks/1252416694177497000 \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  -H 'If-Match: "3"' \
  -d '{"event_types": ["transactions.payment.*"], "state": "paused"}'

Example response

{
  "object": "webhook_endpoint",
  "id": "1252416694177497000",
  "environment_id": "8419223344005061000",
  "acceptor_id": "5028111769322011000",
  "name": "Orders production",
  "description": "Routes payment + refund events to order-service.",
  "url": "https://api.example.com/webhooks/taptree",
  "transport": "http",
  "event_types": ["transactions.payment.*"],
  "state": "paused",
  "signing_algo": "hmac-sha256-v2",
  "consecutive_failures": 0,
  "last_success_at": "2026-05-19T09:14:02.118Z",
  "tripped_until": null,
  "row_version": 4,
  "created_at": "2026-04-12T11:02:33.001Z",
  "updated_at": "2026-05-19T13:45:08.221Z"
}

POST/v1/webhooks/:id/rotate-secret

Rotate a webhook endpoint signing secret

Mint a fresh signing secret for an endpoint and receive the one-shot reveal. The previous secret stays valid for grace_hours after the rotation so receivers can deploy the new secret without dropped events. After the grace window expires the old secret is permanently invalidated.

Capture plaintext_secret and public_secret_id from the response — they are not retrievable later.

Requires the webhooks:rotate_secret scope (deliberately separate from webhooks:write so an automation key can rotate without being able to also change URLs or event subscriptions).

Request headers

  • Name
    If-Match
    Type
    header
    Description

    Current row_version. Same semantics as PATCH.

Request body

The body is optional; an empty body uses the defaults.

  • Name
    grace_hours
    Type
    integer
    Description

    How long (in hours) the previous secret remains valid alongside the new one. Range 0..168 (one week). Default 24.

  • Name
    rotation_reason
    Type
    string
    Description

    Free-form label captured in the audit log. 1–64 characters. Default manual. Useful values: scheduled, compromise, staff-leaver.

Possible response statuses

  • Name
    200 OK
    Type
    status
    Description

    The endpoint object with the new row_version plus the one-shot reveal block (plaintext_secret, public_secret_id, rotation.previous_expires_at).

  • Name
    400 Bad Request
    Type
    status
    Description

    Body validation failed (out-of-range grace_hours, etc.).

  • Name
    401 Unauthorized
    Type
    status
    Description

    Missing or invalid bearer token.

  • Name
    403 Forbidden
    Type
    status
    Description

    Scope missing.

  • Name
    404 Not Found
    Type
    status
    Description

    Endpoint id not visible to this key.

  • Name
    409 Conflict
    Type
    status
    Description

    Stale If-Match.

  • Name
    428 Precondition Required
    Type
    status
    Description

    If-Match header missing.

Request

POST
/v1/webhooks/:id/rotate-secret
curl -X POST https://api.taptree.org/v1/webhooks/1252416694177497000/rotate-secret \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  -H 'If-Match: "4"' \
  -d '{"grace_hours": 48, "rotation_reason": "scheduled"}'

Example response

{
  "object": "webhook_endpoint_secret",
  "id": "1252416694177497000",
  "environment_id": "8419223344005061000",
  "acceptor_id": "5028111769322011000",
  "name": "Orders production",
  "description": "Routes payment + refund events to order-service.",
  "url": "https://api.example.com/webhooks/taptree",
  "transport": "http",
  "event_types": ["transactions.payment.*"],
  "state": "paused",
  "signing_algo": "hmac-sha256-v2",
  "consecutive_failures": 0,
  "last_success_at": "2026-05-19T09:14:02.118Z",
  "tripped_until": null,
  "row_version": 5,
  "created_at": "2026-04-12T11:02:33.001Z",
  "updated_at": "2026-05-19T14:01:00.000Z",
  "rotation": {
    "new_version_id": "9981334467728802000",
    "previous_version": 1,
    "previous_expires_at": "2026-05-21T14:01:00.000Z"
  },
  "public_secret_id": "whsec_id_8c14a2",
  "plaintext_secret": "whsec_ab99ee77dd66cc55bb44aa33ee22dd11cc00bb99aa88..."
}

DELETE/v1/webhooks/:id

Delete a webhook endpoint

Soft-delete an endpoint. No future events are delivered and the endpoint disappears from list/retrieve responses, but the audit history is retained for compliance. The endpoint id is permanently retired — you cannot reuse it.

Requires the webhooks:write scope.

Request headers

  • Name
    If-Match
    Type
    header
    Description

    Current row_version. Same semantics as PATCH.

Possible response statuses

  • Name
    204 No Content
    Type
    status
    Description

    The endpoint has been soft-deleted. No response body.

  • Name
    401 Unauthorized
    Type
    status
    Description

    Missing or invalid bearer token.

  • Name
    403 Forbidden
    Type
    status
    Description

    Scope missing.

  • Name
    404 Not Found
    Type
    status
    Description

    Endpoint id not visible to this key.

  • Name
    409 Conflict
    Type
    status
    Description

    Stale If-Match.

  • Name
    428 Precondition Required
    Type
    status
    Description

    If-Match header missing.

Request

DELETE
/v1/webhooks/:id
curl -X DELETE https://api.taptree.org/v1/webhooks/1252416694177497000 \
  -H "Authorization: Bearer {token}" \
  -H 'If-Match: "5"'

Example response

HTTP/1.1 204 No Content

Was this page helpful?