Developers
The Kambak API
Add stamps from your POS, create customers from your store and receive webhooks. REST, JSON and OpenAPI 3.1.
From the Starter plan (API for your POS). Full API and webhooks from Pro.
Quickstart
- Create a key in Panel › Integrations. Start with a test one (
kbk_test_…). Try it with
GET /me:curl https://api.kambak.app/api/v1/me \ -H "Authorization: Bearer $KAMBAK_API_KEY"Add a stamp. Every write carries an
Idempotency-Key:curl -X POST https://api.kambak.app/api/v1/cards/CARD_ID/actions \ -H "Authorization: Bearer $KAMBAK_API_KEY" \ -H "Idempotency-Key: venta-1042" \ -H "Content-Type: application/json" \ -d '{"action": "stamp", "count": 1}'
Base: https://api.kambak.app/api/v1
What each plan includes
| Plan | API | Requests/min |
|---|---|---|
| Free | No API | — |
| Starter | API for your POS: customers, cards, issuing and actions | 60 |
| Pro | Full API: plus campaigns, stats and webhooks | 120 |
| Multi-location | Everything, per-location keys and MCP server | 600 |
If you downgrade, what the plan no longer includes returns 403 plan_upgrade_required. Each operation states its minimum plan in x-kambak-plan.
Authentication
Send the key in the Authorization: Bearer kbk_live_… header.
The key is shown only once. Keep it on your server, never in a browser or app.
It acts with the permissions of the owner who created it. If they stop being an owner, it stops working.
Revoking it cuts access instantly.
Permissions (scopes)
- customers:read
- Read customers
- customers:write
- Create and update customers
- cards:read
- Read cards and history
- cards:write
- Add, subtract and redeem; issue cards
- programs:read
- Read your programs
- campaigns:read
- Read campaigns and quota
- campaigns:write
- Create and send notices (plan quota applies)
- stats:read
- Read stats
- webhooks:read
- Read webhooks and deliveries
- webhooks:write
- Create and delete webhooks
Test mode
kbk_test_… keys read your real business data.
Writes are validated and simulated: you get what would happen, but nothing is saved.
Wallet isn’t updated, no notice is sent and no webhook fires.
Every response has Kambak-Mode: test; /me returns livemode: false.
Idempotency
Every write (POST, PATCH, DELETE) needs an Idempotency-Key: a unique value per operation.
If your POS retries with the same key, it gets the same response and nothing is added twice (Idempotent-Replayed: true).
The same key with a different body returns 422 idempotency_key_reused.
Keys are remembered for 24 h. If the operation failed, you can retry with the same key.
Errors
Always the same shape. Use code in your code; message is in Spanish.
{
"error": {
"code": "insufficient_scope",
"message": "Esta clave no tiene el permiso cards:write",
"details": { "required": "cards:write" }
}
}- validation_error
- 400 · invalid data (field by field in details)
- idempotency_key_required
- 400 · missing Idempotency-Key
- invalid_api_key
- 401 · invalid, revoked or inactive key
- insufficient_scope
- 403 · the key lacks that permission
- plan_upgrade_required
- 403 · your plan doesn’t include that operation (details.requiredPlan)
- merchant_inactive
- 403 · the business is suspended or closed
- not_found
- 404 · not found in your business
- recent_action
- 409 · same action less than 2 min ago: confirm with confirmRepeat
- rate_limited
- 429 · per-minute limit exceeded
Pagination
Lists return data and nextCursor. Pass it as ?cursor= until it is null.
limit goes from 1 to 100 (default 20).
Limits
Per key: 60 requests per minute on Starter, 120 on Pro and 600 on Multi-location. There is also a per-business cap.
Every response has RateLimit-Limit, RateLimit-Remaining and RateLimit-Reset.
On 429, wait for Retry-After.
Notices respect the plan’s campaign quota and Google’s cap of 3 per pass every 24 h.
Webhooks
Register a URL and pick events. We send you a POST with signed JSON.
Create webhooks in Integrations or with POST /webhook-endpoints (great for Zapier).
Reply 2xx within 5 s. Otherwise we retry 8 times with growing delays (~4 h).
After 10 failed deliveries in a row, or many timeouts in a row, we pause the webhook and email you.
Via the API, each event needs its read permission: customer.* → customers:read; the rest → cards:read.
Only https URLs on public servers.
They arrive in seconds; some (like Wallet) up to 1 minute later.
Events
- customer.created
- New customer
- card.created
- New card
- card.stamped
- Stamps added
- card.points_changed
- Points earned
- card.balance_changed
- Gift card balance used
- card.adjusted
- Manual adjustment
- card.action_undone
- Action undone
- reward.redeemed
- Reward or coupon redeemed
- membership.checked
- Membership checked
- membership.payment_received
- Membership paid
- membership.payment_reverted
- Payment reverted
- membership.cancelled
- Membership cancelled
- pass.saved
- Pass saved to Wallet
- pass.removed
- Pass removed from Wallet
Every event looks like this:
{
"id": "evt_3f9c1b2a7d4e5f60a1b2c3d4",
"type": "card.stamped",
"createdAt": "2026-10-13T15:04:05.000Z",
"livemode": true,
"merchantId": "6c0f…",
"data": {
"card": { "id": "…", "programId": "…", "programType": "stamps", "customerId": "…", "memberNumber": "3F2A91BC" },
"event": { "id": "…", "kind": "stamp", "delta": "1", "before": 6, "after": 7, "origin": "api" }
}
}Verify signatures
The Kambak-Signature header has t=…,v1=….
- Compute HMAC-SHA256 of
t + "." + raw bodywith yourwhsec_…secret. - Compare it with
v1in constant time. - Reject it if
tis older than 5 minutes (replay protection).
Use the event id to ignore duplicates.
import crypto from 'node:crypto';
import express from 'express';
const app = express();
const SECRET = process.env.KAMBAK_WEBHOOK_SECRET; // whsec_…
// The RAW body: the signature covers the exact bytes received
app.post('/webhooks/kambak', express.raw({ type: 'application/json' }), (req, res) => {
const parts = Object.fromEntries(
(req.get('Kambak-Signature') ?? '').split(',').map((p) => p.split('=')),
);
const expected = crypto
.createHmac('sha256', SECRET)
.update(`${parts.t}.${req.body}`)
.digest('hex');
const fresh = Math.abs(Date.now() / 1000 - Number(parts.t)) < 300;
const valid =
fresh &&
typeof parts.v1 === 'string' &&
parts.v1.length === expected.length &&
crypto.timingSafeEqual(Buffer.from(parts.v1), Buffer.from(expected));
if (!valid) return res.status(400).send('invalid signature');
const event = JSON.parse(req.body);
// Store event.id to ignore duplicates
if (event.type === 'reward.redeemed') {
// …
}
res.sendStatus(200);
});Reference
Generated from the same OpenAPI that validates the API.
openapi.jsonAccount
get/meCurrent business and key
Perfect first call: confirms your key works.
Response 200 · Me
merchantobjectrequiredapiKeyobjectrequiredaccessobjectrequired- What the plan includes:
pos(Starter: POS operations) orfull(Pro and Multi-location). livemodebooleanrequired
Customers
get/customersList or search customers
customers:readParameters
limit (query)integer- Page size (1–100).
cursor (query)stringnextCursorof the previous page.q (query)string- Search by name, email or phone.
email (query)string (email)- Exact email (case-insensitive).
Response 200 · CustomerList
dataCustomer[]requirednextCursorstring | nullrequired- Pass it as
cursorfor the next page.
post/customersCreate a customer
Promotions need real consent: send consentSource. Duplicate email → 409 customer_exists.
Errors: customer_exists.
customers:writeIdempotency-KeyBody CreateCustomerInput
namestringemailstring (email)phonestring- Phone (WhatsApp), with country code.
birthDatestring (date)- YYYY-MM-DD.
consentMarketingboolean- Only
trueif the customer actively opted in to promotions. consentSourcestring- How the customer opted in (e.g. "Checkbox at web checkout"). Required to grant consent.
Response 201 · Customer
idstring (uuid)requirednamestring | nullrequiredemailstring | nullrequiredphonestring | nullrequiredbirthDatestring (date) | nullrequired- YYYY-MM-DD.
consentMarketingbooleanrequired- Opted in to promotions.
consentMarketingAtstring (date-time) | nullrequired- When they opted in.
createdVia"qr" | "nfc" | "link" | "panel" | "import" | "api" | …requiredcreatedAtstring (date-time)requiredupdatedAtstring (date-time)required
get/customers/{id}Get a customer
customers:readParameters
id (path)string (uuid)required- Resource id.
Response 200 · Customer
idstring (uuid)requirednamestring | nullrequiredemailstring | nullrequiredphonestring | nullrequiredbirthDatestring (date) | nullrequired- YYYY-MM-DD.
consentMarketingbooleanrequired- Opted in to promotions.
consentMarketingAtstring (date-time) | nullrequired- When they opted in.
createdVia"qr" | "nfc" | "link" | "panel" | "import" | "api" | …requiredcreatedAtstring (date-time)requiredupdatedAtstring (date-time)required
patch/customers/{id}Update a customer
null clears a field. Granting consent needs consentSource; withdrawing does not.
Errors: email_taken.
customers:writeIdempotency-KeyParameters
id (path)string (uuid)required- Resource id.
Body UpdateCustomerInput
namestring | nullemailstring (email) | nullphonestring | nullbirthDatestring (date) | nullconsentMarketingbooleanfalsewithdraws consent.consentSourcestring- How the customer opted in (e.g. "Checkbox at web checkout"). Required to grant consent.
Response 200 · Customer
idstring (uuid)requirednamestring | nullrequiredemailstring | nullrequiredphonestring | nullrequiredbirthDatestring (date) | nullrequired- YYYY-MM-DD.
consentMarketingbooleanrequired- Opted in to promotions.
consentMarketingAtstring (date-time) | nullrequired- When they opted in.
createdVia"qr" | "nfc" | "link" | "panel" | "import" | "api" | …requiredcreatedAtstring (date-time)requiredupdatedAtstring (date-time)required
get/customers/{id}/cardsCards of a customer
cards:readParameters
id (path)string (uuid)required- Resource id.
Response 200 · CardList
dataCard[]requirednextCursorstring | nullrequired- Pass it as
cursorfor the next page.
Cards
get/cardsList cards
cards:readParameters
limit (query)integer- Page size (1–100).
cursor (query)stringnextCursorof the previous page.customerId (query)string (uuid)programId (query)string (uuid)
Response 200 · CardList
dataCard[]requirednextCursorstring | nullrequired- Pass it as
cursorfor the next page.
post/cardsIssue a card
Creates the customer card in an active program and returns the Wallet links. If it exists, returns it (200).
Errors: program_not_active, customer_not_found.
cards:writeIdempotency-KeyBody IssueCardInput
customerIdstring (uuid)requiredprogramIdstring (uuid)required- An active program.
Response 201 · IssueCardResult
cardCardrequiredcreatedbooleanrequiredfalseif the card already existed.walletWalletLinksrequired
get/cards/{id}Get a card
Errors: card_not_found.
cards:readParameters
id (path)string (uuid)required- Resource id.
Response 200 · Card
idstring (uuid)requiredprogramIdstring (uuid)requiredcustomerIdstring (uuid)requiredprogramType"stamps" | "points" | "membership" | "coupon" | "giftcard"requiredprogramNamestringrequiredstatus"active" | "suspended" | "expired" | "revoked"requiredmemberNumberstringrequired- Member number shown on the pass.
summarystringrequired- What the pass shows (e.g. "7 of 10").
stateCardStaterequiredwalletobjectrequiredcanEarnbooleanrequiredblockedReasonstring | nullrequiredcreatedAtstring (date-time)requiredlastUsedAtstring (date-time) | nullrequired
get/cards/by-code/{code}Find by pass QR code
Send what the scanner read (URL-encoded).
Errors: card_not_found.
cards:readParameters
code (path)stringrequired- Content of the pass QR code.
Response 200 · Card
idstring (uuid)requiredprogramIdstring (uuid)requiredcustomerIdstring (uuid)requiredprogramType"stamps" | "points" | "membership" | "coupon" | "giftcard"requiredprogramNamestringrequiredstatus"active" | "suspended" | "expired" | "revoked"requiredmemberNumberstringrequired- Member number shown on the pass.
summarystringrequired- What the pass shows (e.g. "7 of 10").
stateCardStaterequiredwalletobjectrequiredcanEarnbooleanrequiredblockedReasonstring | nullrequiredcreatedAtstring (date-time)requiredlastUsedAtstring (date-time) | nullrequired
get/cards/{id}/eventsCard history
cards:readParameters
id (path)string (uuid)required- Resource id.
limit (query)integer
Response 200 · CardEventList
dataCardEvent[]required
get/cards/{id}/wallet-linksAdd-to-Wallet links
cards:readParameters
id (path)string (uuid)required- Resource id.
Response 200 · WalletLinks
applestring | nullrequired- Apple Wallet .pkpass URL.
googlestring | nullrequired- "Save to Google Wallet" URL.
errorsobjectrequired
post/cards/{id}/actionsAdd, subtract or redeem
Same rules as the scanner: history, Wallet and undo. Subtract = adjust with a negative delta.
Errors: recent_action, card_inactive, reward_pending, reward_not_available, not_enough_points, insufficient_balance, coupon_used, max_stamps_per_visit.
cards:writeIdempotency-KeyParameters
id (path)string (uuid)required- Resource id.
Body CardActionInput
One of these shapes:
action: "stamp"
countintegerconfirmRepeatboolean- Confirms it is not a double scan (409
recent_action). locationIdstring (uuid) | null
action: "redeem_stamps"
confirmRepeatboolean- Confirms it is not a double scan (409
recent_action). locationIdstring (uuid) | null
action: "add_points"
amountnumberrequired- Purchase amount.
confirmRepeatboolean- Confirms it is not a double scan (409
recent_action). locationIdstring (uuid) | null
action: "redeem_points"
rewardPointsintegerrequired- Cost of the reward.
confirmRepeatboolean- Confirms it is not a double scan (409
recent_action). locationIdstring (uuid) | null
action: "giftcard_debit"
amountnumberrequired- Amount in currency units, up to 2 decimals.
confirmRepeatboolean- Confirms it is not a double scan (409
recent_action). locationIdstring (uuid) | null
action: "membership_check"
confirmRepeatboolean- Confirms it is not a double scan (409
recent_action). locationIdstring (uuid) | null
action: "coupon_use"
purchaseAmountnumber- Amount in currency units, up to 2 decimals.
confirmRepeatboolean- Confirms it is not a double scan (409
recent_action). locationIdstring (uuid) | null
action: "adjust"
field"stamps" | "points" | "balance" | "uses"requireddeltanumberrequired- Signed: negative subtracts.
reasonstringrequiredconfirmRepeatboolean- Confirms it is not a double scan (409
recent_action). locationIdstring (uuid) | null
Response 200 · CardActionResult
cardCardrequiredeventCardEventrequiredmessagestringrequiredrewardAvailablebooleanrequiredreplayedbooleanrequired
post/cards/{id}/events/{eventId}/undoUndo the last action
Within 5 minutes.
Errors: undo_expired, not_last_action, already_undone.
cards:writeIdempotency-KeyParameters
id (path)string (uuid)requiredeventId (path)string (uuid)required
Response 200 · CardActionResult
cardCardrequiredeventCardEventrequiredmessagestringrequiredrewardAvailablebooleanrequiredreplayedbooleanrequired
Programs
get/programsList programs
programs:readResponse 200 · ProgramList
dataProgram[]required
get/programs/{id}Get a program
programs:readParameters
id (path)string (uuid)required- Resource id.
Response 200 · Program
idstring (uuid)requiredtype"stamps" | "points" | "membership" | "coupon" | "giftcard"requirednamestringrequireddescriptionstring | nullrequiredtermsstring | nullrequiredstatus"draft" | "active" | "paused" | "archived"requiredbenefitstringrequired- Short benefit text.
rulesobjectrequiredcreatedAtstring (date-time)requiredupdatedAtstring (date-time)required
Campaigns and notices
get/campaignsList campaigns
campaigns:readParameters
limit (query)integer- Page size (1–100).
cursor (query)stringnextCursorof the previous page.
Response 200 · CampaignList
dataCampaign[]requirednextCursorstring | nullrequired- Pass it as
cursorfor the next page.
post/campaignsCreate a notice (draft)
campaigns:writeIdempotency-KeyBody CreateCampaignInput
titlestringrequired- Up to 40 characters.
textstringrequired- Up to 300 characters.
programIdstring (uuid)requiredsegmentIdstring (uuid)- A saved segment.
segmentPreset"inactive_30" | "one_stamp_left" | "birthday_month" | "new_this_week" | "vip_10" | "wallet_removed_30"customerIdsstring (uuid)[]- Direct notice to these customers (1–500). Counts as one campaign.
Response 201 · Campaign
idstring (uuid)requiredprogramIdstring (uuid) | nullrequiredsegmentIdstring (uuid) | nullrequiredsegmentPresetstring | nullrequiredcustomerIdsstring (uuid)[] | nullrequired- Direct notice to these customers.
titlestring | nullrequiredtextstringrequiredstatus"draft" | "scheduled" | "sending" | "sent" | "cancelled" | "failed"requiredorigin"manual" | "automation" | "ai" | "mcp" | "api"requiredscheduledAtstring (date-time) | nullrequiredsentAtstring (date-time) | nullrequiredcreatedAtstring (date-time)requiredupdatedAtstring (date-time)required
get/campaigns/quotaMonthly quota
campaigns:readResponse 200 · CampaignQuota
planstringrequiredmonthstringrequiredmaxinteger | nullrequiredusedintegerrequiredremaininginteger | nullrequiredtimezonestringrequired
get/segmentsAvailable segments
campaigns:readResponse 200 · SegmentList
segmentsobject[]requiredpresetsobject[]required
get/campaigns/{id}Campaign and report
campaigns:readParameters
id (path)string (uuid)required- Resource id.
Response 200 · CampaignDetail
idstring (uuid)requiredprogramIdstring (uuid) | nullrequiredsegmentIdstring (uuid) | nullrequiredsegmentPresetstring | nullrequiredcustomerIdsstring (uuid)[] | nullrequired- Direct notice to these customers.
titlestring | nullrequiredtextstringrequiredstatus"draft" | "scheduled" | "sending" | "sent" | "cancelled" | "failed"requiredorigin"manual" | "automation" | "ai" | "mcp" | "api"requiredscheduledAtstring (date-time) | nullrequiredsentAtstring (date-time) | nullrequiredcreatedAtstring (date-time)requiredupdatedAtstring (date-time)requiredreportobjectrequired
post/campaigns/{id}/sendSend now
Goes through the reviewer, consent, the plan quota and the 3-per-pass-per-24h cap.
Errors: campaign_review_failed, campaign_no_recipients, campaign_limit_reached.
campaigns:writeIdempotency-KeyParameters
id (path)string (uuid)required- Resource id.
Response 200 · Campaign
idstring (uuid)requiredprogramIdstring (uuid) | nullrequiredsegmentIdstring (uuid) | nullrequiredsegmentPresetstring | nullrequiredcustomerIdsstring (uuid)[] | nullrequired- Direct notice to these customers.
titlestring | nullrequiredtextstringrequiredstatus"draft" | "scheduled" | "sending" | "sent" | "cancelled" | "failed"requiredorigin"manual" | "automation" | "ai" | "mcp" | "api"requiredscheduledAtstring (date-time) | nullrequiredsentAtstring (date-time) | nullrequiredcreatedAtstring (date-time)requiredupdatedAtstring (date-time)required
post/campaigns/{id}/scheduleSchedule
Errors: invalid_schedule, campaign_limit_reached.
campaigns:writeIdempotency-KeyParameters
id (path)string (uuid)required- Resource id.
Body ScheduleCampaignInput
sendAtstringrequired- Local time of the business (YYYY-MM-DDTHH:mm).
Response 200 · Campaign
idstring (uuid)requiredprogramIdstring (uuid) | nullrequiredsegmentIdstring (uuid) | nullrequiredsegmentPresetstring | nullrequiredcustomerIdsstring (uuid)[] | nullrequired- Direct notice to these customers.
titlestring | nullrequiredtextstringrequiredstatus"draft" | "scheduled" | "sending" | "sent" | "cancelled" | "failed"requiredorigin"manual" | "automation" | "ai" | "mcp" | "api"requiredscheduledAtstring (date-time) | nullrequiredsentAtstring (date-time) | nullrequiredcreatedAtstring (date-time)requiredupdatedAtstring (date-time)required
post/campaigns/{id}/cancelCancel a scheduled one
Errors: campaign_not_cancellable.
campaigns:writeIdempotency-KeyParameters
id (path)string (uuid)required- Resource id.
Response 200 · Campaign
idstring (uuid)requiredprogramIdstring (uuid) | nullrequiredsegmentIdstring (uuid) | nullrequiredsegmentPresetstring | nullrequiredcustomerIdsstring (uuid)[] | nullrequired- Direct notice to these customers.
titlestring | nullrequiredtextstringrequiredstatus"draft" | "scheduled" | "sending" | "sent" | "cancelled" | "failed"requiredorigin"manual" | "automation" | "ai" | "mcp" | "api"requiredscheduledAtstring (date-time) | nullrequiredsentAtstring (date-time) | nullrequiredcreatedAtstring (date-time)requiredupdatedAtstring (date-time)required
Stats
get/statsPeriod overview
stats:readParameters
days (query)number- 7, 30 or 90.
Response 200 · Stats
periodobjectrequiredkpisobjectrequiredvisitsByDayobject[]required
Webhooks
get/webhook-endpointsList webhooks
webhooks:readResponse 200 · WebhookEndpointList
dataWebhookEndpoint[]required
post/webhook-endpointsCreate a webhook
Returns the secret to verify signatures (only once). Each event needs its read scope: customer.* → customers:read; the rest → cards:read.
Errors: webhook_url_not_allowed, webhook_limit_reached.
webhooks:writeIdempotency-KeyBody CreateWebhookEndpointInput
urlstring (uri)required- HTTPS URL on a public host.
events"customer.created" | "card.created" | "card.stamped" | "card.points_changed" | "card.balance_changed" | "card.adjusted" | …[]requireddescriptionstring
Response 201 · WebhookEndpointWithSecret
idstring (uuid)requiredurlstringrequireddescriptionstring | nullrequiredevents"customer.created" | "card.created" | "card.stamped" | "card.points_changed" | "card.balance_changed" | "card.adjusted" | …[]requiredenabledbooleanrequireddisabledReason"manual" | "failures" | "key_revoked" | "plan" | nullrequiredmanual,failures,key_revoked(its API key was revoked or its owner left) orplan(paused until the plan includes webhooks again).consecutiveFailuresintegerrequiredlastSuccessAtstring (date-time) | nullrequiredlastFailureAtstring (date-time) | nullrequiredcreatedAtstring (date-time)requiredupdatedAtstring (date-time)requiredsecretstring | nullrequired- Signing secret. Shown only once:
nullin an idempotent replay (rotate it from the panel). noticestring
get/webhook-endpoints/{id}Get a webhook
webhooks:readParameters
id (path)string (uuid)required- Resource id.
Response 200 · WebhookEndpoint
idstring (uuid)requiredurlstringrequireddescriptionstring | nullrequiredevents"customer.created" | "card.created" | "card.stamped" | "card.points_changed" | "card.balance_changed" | "card.adjusted" | …[]requiredenabledbooleanrequireddisabledReason"manual" | "failures" | "key_revoked" | "plan" | nullrequiredmanual,failures,key_revoked(its API key was revoked or its owner left) orplan(paused until the plan includes webhooks again).consecutiveFailuresintegerrequiredlastSuccessAtstring (date-time) | nullrequiredlastFailureAtstring (date-time) | nullrequiredcreatedAtstring (date-time)requiredupdatedAtstring (date-time)required
patch/webhook-endpoints/{id}Update or re-enable a webhook
Events need the same read scope as on create.
Errors: webhook_url_not_allowed.
webhooks:writeIdempotency-KeyParameters
id (path)string (uuid)required- Resource id.
Body UpdateWebhookEndpointInput
urlstring (uri)- HTTPS URL on a public host.
events"customer.created" | "card.created" | "card.stamped" | "card.points_changed" | "card.balance_changed" | "card.adjusted" | …[]descriptionstring | nullenabledboolean
Response 200 · WebhookEndpoint
idstring (uuid)requiredurlstringrequireddescriptionstring | nullrequiredevents"customer.created" | "card.created" | "card.stamped" | "card.points_changed" | "card.balance_changed" | "card.adjusted" | …[]requiredenabledbooleanrequireddisabledReason"manual" | "failures" | "key_revoked" | "plan" | nullrequiredmanual,failures,key_revoked(its API key was revoked or its owner left) orplan(paused until the plan includes webhooks again).consecutiveFailuresintegerrequiredlastSuccessAtstring (date-time) | nullrequiredlastFailureAtstring (date-time) | nullrequiredcreatedAtstring (date-time)requiredupdatedAtstring (date-time)required
delete/webhook-endpoints/{id}Delete a webhook
webhooks:writeIdempotency-KeyParameters
id (path)string (uuid)required- Resource id.
Response 204
post/webhook-endpoints/{id}/testSend a test event
webhooks:writeIdempotency-KeyParameters
id (path)string (uuid)required- Resource id.
Response 201 · WebhookDelivery
idstring (uuid)requiredendpointIdstring (uuid)requiredeventIdstringrequiredeventTypestringrequiredstatus"pending" | "succeeded" | "failed"requiredattemptsintegerrequiredresponseStatusinteger | nullrequirederrorstring | nullrequiredlivemodebooleanrequiredcreatedAtstring (date-time)requiredlastAttemptAtstring (date-time) | nullrequireddeliveredAtstring (date-time) | nullrequired
get/webhook-endpoints/{id}/deliveriesRecent deliveries
webhooks:readParameters
id (path)string (uuid)required- Resource id.
limit (query)integer- Page size (1–100).
cursor (query)stringnextCursorof the previous page.
Response 200 · WebhookDeliveryList
dataWebhookDelivery[]requirednextCursorstring | nullrequired- Pass it as
cursorfor the next page.
post/webhook-deliveries/{id}/retryResend a delivery
webhooks:writeIdempotency-KeyParameters
id (path)string (uuid)required- Resource id.
Response 200 · WebhookDelivery
idstring (uuid)requiredendpointIdstring (uuid)requiredeventIdstringrequiredeventTypestringrequiredstatus"pending" | "succeeded" | "failed"requiredattemptsintegerrequiredresponseStatusinteger | nullrequirederrorstring | nullrequiredlivemodebooleanrequiredcreatedAtstring (date-time)requiredlastAttemptAtstring (date-time) | nullrequireddeliveredAtstring (date-time) | nullrequired