FRAGMENT sends an HTTP POST to your server when a Payment event occurs, such as settlement or refund. Create a subscription to register your receiving URL.
Subscriptions
#Subscription operations follow the API's standard error handling.
Call createWebhookSubscription with an HTTPS URL, eventTypes: ["*"], and an idempotency key (IK). The authenticated API client determines the workspace.
mutation CreateWebhookSubscription($ik: SafeString!, $input: CreateWebhookSubscriptionInput!) {
createWebhookSubscription(ik: $ik, input: $input) {
__typename
... on CreateWebhookSubscriptionResult {
subscription { id webhookVersion }
signingSecret
}
... on Error { code message retryable }
}
}The following subscription receives all event types from every Ledger in its workspace.
{
"ik": "payment-events-webhook",
"input": {
"url": "https://example.com/webhooks/fragment",
"eventTypes": ["*"]
}
}Save signingSecret securely on your backend. The API returns it only when the subscription is first created.
| Argument | GraphQL type | Rule |
|---|---|---|
ik | SafeString! | Creation idempotency key, unique within the workspace. |
input.url | String! | Receiving HTTPS URL. |
input.eventTypes | [WebhookEventType!]! | Must be ["*"]; named event filters are unsupported. |
input.webhookVersion (optional) | String! = "1" | Defaults to the latest version at creation. |
On success, the mutation returns:
| Result field | GraphQL type | Meaning |
|---|---|---|
subscription | WebhookSubscription! | The created or existing subscription. |
signingSecret | String | Secret on first creation; null on replay. |
isIkReplay | Boolean! | Whether the request repeats an earlier creation. |
Creation retries
Follow the API's idempotency rules, with these webhook-specific differences:
- Creation keys belong to the workspace.
- Reusing a key with a different URL or webhook version returns
BadRequestError. - Successful retries return the existing subscription with
isIkReplay: trueandsigningSecret: null. - Deleted subscriptions keep their creation keys reserved. Reusing those keys returns
BadRequestError.
Call webhookSubscriptions to list active subscriptions in the authenticated workspace. Deleted subscriptions are excluded.
query ListWebhookSubscriptions($first: Int, $after: String) {
webhookSubscriptions(first: $first, after: $after) {
nodes {
id
url
eventTypes
webhookVersion
created
}
pageInfo { endCursor hasNextPage hasPreviousPage startCursor }
}
}Pass endCursor as after while hasNextPage is true. Each node has the fields below.
| Subscription field | GraphQL type |
|---|---|
id | ID! |
url | String! |
eventTypes | [WebhookEventType!]! |
webhookVersion | String! |
created | DateTime! |
Call deleteWebhookSubscription with the subscription ID. Repeating deletion returns success: true.
mutation DeleteWebhookSubscription($id: ID!) {
deleteWebhookSubscription(id: $id) {
__typename
... on DeleteWebhookSubscriptionResult { success }
... on Error { code message retryable }
}
}Deletion stops queued deliveries and future retries. A request already in flight may finish.
- The creation IK stays reserved: reusing it returns
BadRequestError, so creating another subscription requires a new IK.
On success, the mutation returns:
| Result field | GraphQL type | Meaning |
|---|---|---|
success | Boolean! | True when the subscription is deleted, including repeated deletion. |
Event payload
#Fragment posts one event per request to the subscription URL. This example shows a settlement notification.
{
"version": "1",
"type": "payment.settled",
"id": "example-event-id",
"occurredAt": "2026-10-27T18:30:00.000Z",
"data": {
"workspace": { "id": "example-workspace-id" },
"ledger": { "id": "example-ledger-id", "ik": "customer-42" },
"schema": { "key": "invoicing" },
"payment": { "id": "example-payment-id", "ik": "invoice-1024" },
"event": {
"paymentStatus": "settled",
"ledgerEntry": { "id": "example-entry-id" }
}
}
}Each event contains these fields.
| Field | JSON type | Meaning |
|---|---|---|
id | String. | Payment event ID; deduplicate within the workspace. |
type | String. | Event name from the catalog below. |
version | String, exactly "1". | Envelope and event-data format version. |
occurredAt | ISO 8601 string. | Source event time, independent of delivery time. |
data.workspace | { id: string } | Owning workspace. |
data.ledger | { id: string, ik: string } | Ledger ID and its customer-supplied key. |
data.schema | { key: string } | Owning Ledger's schema key. |
data.payment | { id: string, ik: string } | Payment ID and its idempotency key. |
data.event | Object. | Event-specific fields from the catalog below. |
Payment events
#Fragment sends webhook notifications for the following Payment events. All include paymentStatus in data.event.
| Event type | Additional fields |
|---|---|
payment.created | None. |
payment.checkout | attempt: { id: string } or null, attemptStatus: PaymentAttemptStatus or null. |
payment.retry | attempt: { id: string }, attemptStatus: PaymentAttemptStatus. |
payment.card_captured | attempt: { id: string } or null, attemptStatus: PaymentAttemptStatus or null, ledgerEntry: { id: string } or null. |
payment.card_declined | attempt: { id: string }, attemptStatus: PaymentAttemptStatus, declineCode: string or null. |
payment.card_3ds_canceled | None. |
payment.settled | ledgerEntry: { id: string }. |
payment.refund_initiated | refund: { id: string, ik: string }, refundStatus: PaymentRefundStatus, ledgerEntry: { id: string }. |
payment.refund_settled | refund: { id: string, ik: string }, refundStatus: PaymentRefundStatus. |
payment.refund_failed | refund: { id: string, ik: string }, refundStatus: PaymentRefundStatus, ledgerEntry: { id: string }. |
Respond to events
#Return HTTP 2xx after saving the event or finishing processing. Fragment retries requests after a network error, timeout, or non-2xx response.
- Events can arrive more than once or out of order.
- Use the workspace ID and event
idto avoid processing duplicates. - Retries contain the same event body, including its
idandoccurredAt. - Return HTTP
2xxfor event types your application does not handle.