Webhook
The Webhook object represents an endpoint configured to receive Event notifications.
A Webhook object represents an endpoint you've configured to receive Event notifications — payment successes, refunds, subscription changes, and more. Each webhook is subscribed to one or more event types and receives an HTTP POST for every matching event, signed with its secret.
A workspace can have up to 5 webhooks configured at once; create returns an error once that limit is reached. Archiving a webhook frees a slot; setting one to inactive does not.
A webhook URL must be a publicly reachable http:// or https:// address. Anything else is rejected, and the error tells you why.
A domain that isn't live yet — or a tunnel that has already expired — counts as unreachable, so save the webhook once the endpoint is actually serving.
Endpoints
| Method | Endpoint | Description |
|---|---|---|
GET | /v0/webhooks/list | List all configured webhooks |
POST | /v0/webhooks/create | Create a new webhook |
POST | /v0/webhooks/sendTestEvent | Send a synthetic test event to subscribed webhooks |
GET | /v0/webhooks/{webhookId} | Retrieve a webhook |
PATCH | /v0/webhooks/{webhookId}/update | Update a webhook |
PATCH | /v0/webhooks/{webhookId}/archive | Archive a webhook |
GET | /v0/webhooks/{webhookId}/attempts | List a webhook's delivery attempts |
The Webhook object
objectstringObject type identifier. Always "webhook" for Webhook objects.
idstringrequiredUnique identifier (UUID) for this webhook.
urlstringrequiredThe endpoint that receives event deliveries.
statusstringrequiredCurrent webhook status. Possible values: active, inactive
secretstringrequiredSigning secret used to verify the x-fngs-signature header on each delivery.
list and get return the secret masked (••••••••cdef, last four characters only) —
they only need the read-tier public key. create and update return it in full; both
require the secret key. If you lose a secret, set a new one by sending secret on update.
eventsarrayrequiredEvent types this webhook is subscribed to.
consecutiveFailuresintegerHow many events in a row have failed to reach this endpoint. Resets to 0 on the next success.
See Automatic disabling. Defaults to 0.
failingSinceinteger | nullUnix timestamp (milliseconds) of the first failure in the current streak. null while the webhook
is healthy.
lastBlockReasonstring | nullSet when the configured url cannot currently be used for delivery — it must be an http:// or
https:// address that resolves publicly. null otherwise. Possible values: malformed_url,
disallowed_scheme, blocked_host, unresolvable_host, blocked_resolved_address.
lastBlockedAtinteger | nullUnix timestamp (milliseconds) of the most recent delivery skipped for the reason above. null if
that has never happened.
createdAtintegerUnix timestamp (milliseconds) when the webhook was created.
deletedAtinteger | nullUnix timestamp (milliseconds) when the webhook was archived. null if not archived.
Delivery and retries
Each event is delivered on its own. Fungies waits up to 25 seconds for your endpoint to respond,
and treats anything outside 2xx — or a timeout, or a connection error — as a failure. A 307 or
308 redirect is followed, up to 3 hops. Any other redirect, or one that cannot be followed, is a
failed delivery recorded with its status code. A failed delivery is retried up to 5 times,
roughly 5 minutes apart.
consecutiveFailures counts events, not attempts: it only increments once a delivery has used up
all its retries.
Automatic disabling
When consecutiveFailures reaches 10, the webhook's status is set to inactive and it stops
receiving events. It does not re-enable itself — set it back to active with update once your
endpoint is healthy.
You are emailed twice: once when consecutiveFailures reaches 3, and again when the webhook is
disabled at 10. There is no email when a failing endpoint recovers — a streak resetting to 0
is silent, so do not wait for an all-clear that never arrives.
Poll consecutiveFailures and failingSince on list or get to spot a degrading endpoint before
it is disabled, and use GET /v0/webhooks/{webhookId}/attempts to see the status code and response
body for each attempt.
Deliveries skipped because the URL itself cannot be used are tracked separately — see
lastBlockReason above. Those do email you when they start and again when they clear.
The Webhook Attempt object
Each delivery attempt — success or failure — is recorded and available via the attempts endpoint.
objectstringObject type identifier. Always "webhook_attempt" for Webhook Attempt objects.
idstringrequiredUnique identifier (UUID) for this attempt.
webhookIdstringrequiredThe Webhook this attempt belongs to.
eventTypestring | nullThe Event type that was delivered.
sequenceintegerrequiredRetry sequence number for this delivery. 0 is the first try.
statusCodeinteger | nullHTTP status code returned by the receiving endpoint. null if the request itself failed (timeout, connection error, blocked URL).
requestobject | nullThe request body that was sent.
responseobject | nullThe parsed JSON response body, if any.
createdAtintegerUnix timestamp (milliseconds) when the attempt was made.
Example response
{
"status": "success",
"data": {
"webhook": {
"object": "webhook",
"id": "660e8400-e29b-41d4-a716-446655440001",
"url": "https://example.com/webhooks/fungies",
"status": "active",
"secret": "your-webhook-signing-secret",
"events": ["payment_success", "subscription_cancelled"],
"consecutiveFailures": 0,
"failingSince": null,
"lastBlockReason": null,
"lastBlockedAt": null,
"createdAt": 1717200000000,
"deletedAt": null
}
}
}Related resources
Last updated