All pages

Developer docs

Add a webhook endpoint

View as Markdown

Ask to send the account's transfer events to an HTTPS address: your own receiver, or a Slack or Microsoft Teams incoming webhook, which gets a readable message. The endpoint starts pending: it receives only test events, on a sample transfer, until the account owner confirms it on the website, and the owner is normally notified by email. The signing secret is returned once, here; deliveries carry Standard Webhooks headers signed with it. Only the account owner's API keys and connected apps can add endpoints.

POSThttps://uetr.ai/api/v1/webhooks
  • MCP tool: create_webhook_endpoint
  • Access: a key or connection with read and write access
  • Only the account owner's keys and connections

Request body

FieldTypeRequiredDescription
urlstring (at most 2048 characters)YesThe full HTTPS address. It must use a domain name and the standard port.
eventsarray of status_changed, final_state, checks_ended (at least 1 item, at most 3 items)NoThe events to send. Defaults to all of them.

Response

FieldTypeRequiredDescription
statusstringYes
endpointobjectYes
endpoint.idstring (uuid)Yes
endpoint.urlstringYesThe address's host and a masked path. The full address is never shown.
endpoint.destinationjson, slack, teamsYesjson: signed JSON. slack and teams: a readable message for a Slack or Microsoft Teams incoming webhook.
endpoint.eventsarray of status_changed, final_state, checks_endedYes
endpoint.statuspending, active, pausedYespending: waiting for the account owner to confirm it on the website; until then it receives test events only. active: receiving events. paused: deliveries stopped after sustained failures; a test event that succeeds resumes it.
endpoint.paused_atstring or nullYes
endpoint.created_atstringYes
endpoint.created_bywebsite, apiYeswebsite: added on the website. api: added by an API key or a connected app.
endpoint.api_versionstringYes
signing_secretstringYesThe secret that signs every delivery, starting whsec_. It is shown only now: store it in the receiver's secret settings.
requestobjectYes
request.idstring (uuid)Yes
request.kindteam_invite, record_share, webhook_endpointYesteam_invite: an invitation to the team. record_share: a payment record link. webhook_endpoint: a webhook endpoint that receives status changes.
request.statuspending, confirmed, declined, expiredYespending: waiting for the account owner. confirmed: the owner approved it and it took effect. declined: the owner refused it. expired: nobody answered within seven days, or a later request for the same transfer with different settings replaced it.
request.created_atstringYes
request.expires_atstringYes
request.decided_atstring or nullYes
request.invite_emailstring or nullYesFor a team invite: the address to invite.
request.uetrstring or nullYesFor a record share: the transfer's UETR.
request.record_urlstring or nullYesFor a confirmed record share: the payment record link, while the record still has that link. Null otherwise.
request.endpoint_urlstring or nullYesFor a webhook endpoint: its host and a masked path. Null otherwise.
detailstringYesPlain English to pass on to the person behind the request.

Example

curl -X POST "https://uetr.ai/api/v1/webhooks" \
  -H "Authorization: Bearer $UETR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url":"https://hooks.slack.com/services/T000/B000/XXXX","events":["status_changed"]}'

The answer:

{
  "status": "pending_owner_confirmation",
  "request": {
    "id": "4c7e1a3b-8d2f-4b6e-a9c5-3f6b9e2d5a8c",
    "kind": "webhook_endpoint",
    "status": "pending",
    "created_at": "2026-10-14T09:35:00.000Z",
    "expires_at": "2026-10-21T09:35:00.000Z",
    "decided_at": null,
    "invite_email": null,
    "uetr": null,
    "record_url": null,
    "endpoint_url": "hooks.slack.com/services/••••"
  },
  "detail": "The account owner must confirm the webhook endpoint hooks.slack.com/services/•••• on the website before it takes effect. They have been notified by email.",
  "endpoint": {
    "id": "3b1f8c2e-6a4d-4f5e-9c7b-2d8e1a0f4b6c",
    "url": "hooks.slack.com/services/••••",
    "destination": "slack",
    "events": [
      "status_changed"
    ],
    "status": "pending",
    "paused_at": null,
    "created_at": "2026-10-14T09:35:00.000Z",
    "created_by": "api",
    "api_version": "2026-10-14"
  },
  "signing_secret": "whsec_AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="
}

Refusals

Besides the access refusals every call can meet, this call can answer: