Skip to content

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

  1. Create a key in Panel › Integrations. Start with a test one (kbk_test_…).
  2. Try it with GET /me:

    curl https://api.kambak.app/api/v1/me \
      -H "Authorization: Bearer $KAMBAK_API_KEY"
  3. 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

PlanAPIRequests/min
FreeNo API—
StarterAPI for your POS: customers, cards, issuing and actions60
ProFull API: plus campaigns, stats and webhooks120
Multi-locationEverything, per-location keys and MCP server600

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=….

  1. Compute HMAC-SHA256 of t + "." + raw body with your whsec_… secret.
  2. Compare it with v1 in constant time.
  3. Reject it if t is 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.json

Account

get/meCurrent business and key

Perfect first call: confirms your key works.

Minimum plan: Starter

Response 200 · Me

merchantobjectrequired
apiKeyobjectrequired
accessobjectrequired
What the plan includes: pos (Starter: POS operations) or full (Pro and Multi-location).
livemodebooleanrequired

Customers

get/customersList or search customers
Minimum plan: StarterScope: customers:read

Parameters

limit (query)integer
Page size (1–100).
cursor (query)string
nextCursor of the previous page.
q (query)string
Search by name, email or phone.
email (query)string (email)
Exact email (case-insensitive).

Response 200 · CustomerList

dataCustomer[]required
nextCursorstring | nullrequired
Pass it as cursor for the next page.
post/customersCreate a customer

Promotions need real consent: send consentSource. Duplicate email → 409 customer_exists.

Errors: customer_exists.

Minimum plan: StarterScope: customers:writeIdempotency-Key

Body CreateCustomerInput

namestring
emailstring (email)
phonestring
Phone (WhatsApp), with country code.
birthDatestring (date)
YYYY-MM-DD.
consentMarketingboolean
Only true if 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)required
namestring | nullrequired
emailstring | nullrequired
phonestring | nullrequired
birthDatestring (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" | …required
createdAtstring (date-time)required
updatedAtstring (date-time)required
get/customers/{id}Get a customer
Minimum plan: StarterScope: customers:read

Parameters

id (path)string (uuid)required
Resource id.

Response 200 · Customer

idstring (uuid)required
namestring | nullrequired
emailstring | nullrequired
phonestring | nullrequired
birthDatestring (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" | …required
createdAtstring (date-time)required
updatedAtstring (date-time)required
patch/customers/{id}Update a customer

null clears a field. Granting consent needs consentSource; withdrawing does not.

Errors: email_taken.

Minimum plan: ProScope: customers:writeIdempotency-Key

Parameters

id (path)string (uuid)required
Resource id.

Body UpdateCustomerInput

namestring | null
emailstring (email) | null
phonestring | null
birthDatestring (date) | null
consentMarketingboolean
false withdraws consent.
consentSourcestring
How the customer opted in (e.g. "Checkbox at web checkout"). Required to grant consent.

Response 200 · Customer

idstring (uuid)required
namestring | nullrequired
emailstring | nullrequired
phonestring | nullrequired
birthDatestring (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" | …required
createdAtstring (date-time)required
updatedAtstring (date-time)required
get/customers/{id}/cardsCards of a customer
Minimum plan: StarterScope: cards:read

Parameters

id (path)string (uuid)required
Resource id.

Response 200 · CardList

dataCard[]required
nextCursorstring | nullrequired
Pass it as cursor for the next page.

Cards

get/cardsList cards
Minimum plan: ProScope: cards:read

Parameters

limit (query)integer
Page size (1–100).
cursor (query)string
nextCursor of the previous page.
customerId (query)string (uuid)
programId (query)string (uuid)

Response 200 · CardList

dataCard[]required
nextCursorstring | nullrequired
Pass it as cursor for 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.

Minimum plan: StarterScope: cards:writeIdempotency-Key

Body IssueCardInput

customerIdstring (uuid)required
programIdstring (uuid)required
An active program.

Response 201 · IssueCardResult

cardCardrequired
createdbooleanrequired
false if the card already existed.
walletWalletLinksrequired
get/cards/{id}Get a card

Errors: card_not_found.

Minimum plan: StarterScope: cards:read

Parameters

id (path)string (uuid)required
Resource id.

Response 200 · Card

idstring (uuid)required
programIdstring (uuid)required
customerIdstring (uuid)required
programType"stamps" | "points" | "membership" | "coupon" | "giftcard"required
programNamestringrequired
status"active" | "suspended" | "expired" | "revoked"required
memberNumberstringrequired
Member number shown on the pass.
summarystringrequired
What the pass shows (e.g. "7 of 10").
stateCardStaterequired
walletobjectrequired
canEarnbooleanrequired
blockedReasonstring | nullrequired
createdAtstring (date-time)required
lastUsedAtstring (date-time) | nullrequired
get/cards/by-code/{code}Find by pass QR code

Send what the scanner read (URL-encoded).

Errors: card_not_found.

Minimum plan: StarterScope: cards:read

Parameters

code (path)stringrequired
Content of the pass QR code.

Response 200 · Card

idstring (uuid)required
programIdstring (uuid)required
customerIdstring (uuid)required
programType"stamps" | "points" | "membership" | "coupon" | "giftcard"required
programNamestringrequired
status"active" | "suspended" | "expired" | "revoked"required
memberNumberstringrequired
Member number shown on the pass.
summarystringrequired
What the pass shows (e.g. "7 of 10").
stateCardStaterequired
walletobjectrequired
canEarnbooleanrequired
blockedReasonstring | nullrequired
createdAtstring (date-time)required
lastUsedAtstring (date-time) | nullrequired
get/cards/{id}/eventsCard history
Minimum plan: StarterScope: cards:read

Parameters

id (path)string (uuid)required
Resource id.
limit (query)integer

Response 200 · CardEventList

dataCardEvent[]required
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.

Minimum plan: StarterScope: cards:writeIdempotency-Key

Parameters

id (path)string (uuid)required
Resource id.

Body CardActionInput

One of these shapes:

action: "stamp"

countinteger
confirmRepeatboolean
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"required
deltanumberrequired
Signed: negative subtracts.
reasonstringrequired
confirmRepeatboolean
Confirms it is not a double scan (409 recent_action).
locationIdstring (uuid) | null

Response 200 · CardActionResult

cardCardrequired
eventCardEventrequired
messagestringrequired
rewardAvailablebooleanrequired
replayedbooleanrequired
post/cards/{id}/events/{eventId}/undoUndo the last action

Within 5 minutes.

Errors: undo_expired, not_last_action, already_undone.

Minimum plan: StarterScope: cards:writeIdempotency-Key

Parameters

id (path)string (uuid)required
eventId (path)string (uuid)required

Response 200 · CardActionResult

cardCardrequired
eventCardEventrequired
messagestringrequired
rewardAvailablebooleanrequired
replayedbooleanrequired

Programs

get/programsList programs
Minimum plan: StarterScope: programs:read

Response 200 · ProgramList

dataProgram[]required
get/programs/{id}Get a program
Minimum plan: StarterScope: programs:read

Parameters

id (path)string (uuid)required
Resource id.

Response 200 · Program

idstring (uuid)required
type"stamps" | "points" | "membership" | "coupon" | "giftcard"required
namestringrequired
descriptionstring | nullrequired
termsstring | nullrequired
status"draft" | "active" | "paused" | "archived"required
benefitstringrequired
Short benefit text.
rulesobjectrequired
createdAtstring (date-time)required
updatedAtstring (date-time)required

Campaigns and notices

get/campaignsList campaigns
Minimum plan: ProScope: campaigns:read

Parameters

limit (query)integer
Page size (1–100).
cursor (query)string
nextCursor of the previous page.

Response 200 · CampaignList

dataCampaign[]required
nextCursorstring | nullrequired
Pass it as cursor for the next page.
post/campaignsCreate a notice (draft)
Minimum plan: ProScope: campaigns:writeIdempotency-Key

Body CreateCampaignInput

titlestringrequired
Up to 40 characters.
textstringrequired
Up to 300 characters.
programIdstring (uuid)required
segmentIdstring (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)required
programIdstring (uuid) | nullrequired
segmentIdstring (uuid) | nullrequired
segmentPresetstring | nullrequired
customerIdsstring (uuid)[] | nullrequired
Direct notice to these customers.
titlestring | nullrequired
textstringrequired
status"draft" | "scheduled" | "sending" | "sent" | "cancelled" | "failed"required
origin"manual" | "automation" | "ai" | "mcp" | "api"required
scheduledAtstring (date-time) | nullrequired
sentAtstring (date-time) | nullrequired
createdAtstring (date-time)required
updatedAtstring (date-time)required
get/campaigns/quotaMonthly quota
Minimum plan: ProScope: campaigns:read

Response 200 · CampaignQuota

planstringrequired
monthstringrequired
maxinteger | nullrequired
usedintegerrequired
remaininginteger | nullrequired
timezonestringrequired
get/segmentsAvailable segments
Minimum plan: ProScope: campaigns:read

Response 200 · SegmentList

segmentsobject[]required
presetsobject[]required
get/campaigns/{id}Campaign and report
Minimum plan: ProScope: campaigns:read

Parameters

id (path)string (uuid)required
Resource id.

Response 200 · CampaignDetail

idstring (uuid)required
programIdstring (uuid) | nullrequired
segmentIdstring (uuid) | nullrequired
segmentPresetstring | nullrequired
customerIdsstring (uuid)[] | nullrequired
Direct notice to these customers.
titlestring | nullrequired
textstringrequired
status"draft" | "scheduled" | "sending" | "sent" | "cancelled" | "failed"required
origin"manual" | "automation" | "ai" | "mcp" | "api"required
scheduledAtstring (date-time) | nullrequired
sentAtstring (date-time) | nullrequired
createdAtstring (date-time)required
updatedAtstring (date-time)required
reportobjectrequired
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.

Minimum plan: ProScope: campaigns:writeIdempotency-Key

Parameters

id (path)string (uuid)required
Resource id.

Response 200 · Campaign

idstring (uuid)required
programIdstring (uuid) | nullrequired
segmentIdstring (uuid) | nullrequired
segmentPresetstring | nullrequired
customerIdsstring (uuid)[] | nullrequired
Direct notice to these customers.
titlestring | nullrequired
textstringrequired
status"draft" | "scheduled" | "sending" | "sent" | "cancelled" | "failed"required
origin"manual" | "automation" | "ai" | "mcp" | "api"required
scheduledAtstring (date-time) | nullrequired
sentAtstring (date-time) | nullrequired
createdAtstring (date-time)required
updatedAtstring (date-time)required
post/campaigns/{id}/scheduleSchedule

Errors: invalid_schedule, campaign_limit_reached.

Minimum plan: ProScope: campaigns:writeIdempotency-Key

Parameters

id (path)string (uuid)required
Resource id.

Body ScheduleCampaignInput

sendAtstringrequired
Local time of the business (YYYY-MM-DDTHH:mm).

Response 200 · Campaign

idstring (uuid)required
programIdstring (uuid) | nullrequired
segmentIdstring (uuid) | nullrequired
segmentPresetstring | nullrequired
customerIdsstring (uuid)[] | nullrequired
Direct notice to these customers.
titlestring | nullrequired
textstringrequired
status"draft" | "scheduled" | "sending" | "sent" | "cancelled" | "failed"required
origin"manual" | "automation" | "ai" | "mcp" | "api"required
scheduledAtstring (date-time) | nullrequired
sentAtstring (date-time) | nullrequired
createdAtstring (date-time)required
updatedAtstring (date-time)required
post/campaigns/{id}/cancelCancel a scheduled one

Errors: campaign_not_cancellable.

Minimum plan: ProScope: campaigns:writeIdempotency-Key

Parameters

id (path)string (uuid)required
Resource id.

Response 200 · Campaign

idstring (uuid)required
programIdstring (uuid) | nullrequired
segmentIdstring (uuid) | nullrequired
segmentPresetstring | nullrequired
customerIdsstring (uuid)[] | nullrequired
Direct notice to these customers.
titlestring | nullrequired
textstringrequired
status"draft" | "scheduled" | "sending" | "sent" | "cancelled" | "failed"required
origin"manual" | "automation" | "ai" | "mcp" | "api"required
scheduledAtstring (date-time) | nullrequired
sentAtstring (date-time) | nullrequired
createdAtstring (date-time)required
updatedAtstring (date-time)required

Stats

get/statsPeriod overview
Minimum plan: ProScope: stats:read

Parameters

days (query)number
7, 30 or 90.

Response 200 · Stats

periodobjectrequired
kpisobjectrequired
visitsByDayobject[]required

Webhooks

get/webhook-endpointsList webhooks
Minimum plan: ProScope: webhooks:read

Response 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.

Minimum plan: ProScope: webhooks:writeIdempotency-Key

Body 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" | …[]required
descriptionstring

Response 201 · WebhookEndpointWithSecret

idstring (uuid)required
urlstringrequired
descriptionstring | nullrequired
events"customer.created" | "card.created" | "card.stamped" | "card.points_changed" | "card.balance_changed" | "card.adjusted" | …[]required
enabledbooleanrequired
disabledReason"manual" | "failures" | "key_revoked" | "plan" | nullrequired
manual, failures, key_revoked (its API key was revoked or its owner left) or plan (paused until the plan includes webhooks again).
consecutiveFailuresintegerrequired
lastSuccessAtstring (date-time) | nullrequired
lastFailureAtstring (date-time) | nullrequired
createdAtstring (date-time)required
updatedAtstring (date-time)required
secretstring | nullrequired
Signing secret. Shown only once: null in an idempotent replay (rotate it from the panel).
noticestring
get/webhook-endpoints/{id}Get a webhook
Minimum plan: ProScope: webhooks:read

Parameters

id (path)string (uuid)required
Resource id.

Response 200 · WebhookEndpoint

idstring (uuid)required
urlstringrequired
descriptionstring | nullrequired
events"customer.created" | "card.created" | "card.stamped" | "card.points_changed" | "card.balance_changed" | "card.adjusted" | …[]required
enabledbooleanrequired
disabledReason"manual" | "failures" | "key_revoked" | "plan" | nullrequired
manual, failures, key_revoked (its API key was revoked or its owner left) or plan (paused until the plan includes webhooks again).
consecutiveFailuresintegerrequired
lastSuccessAtstring (date-time) | nullrequired
lastFailureAtstring (date-time) | nullrequired
createdAtstring (date-time)required
updatedAtstring (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.

Minimum plan: ProScope: webhooks:writeIdempotency-Key

Parameters

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 | null
enabledboolean

Response 200 · WebhookEndpoint

idstring (uuid)required
urlstringrequired
descriptionstring | nullrequired
events"customer.created" | "card.created" | "card.stamped" | "card.points_changed" | "card.balance_changed" | "card.adjusted" | …[]required
enabledbooleanrequired
disabledReason"manual" | "failures" | "key_revoked" | "plan" | nullrequired
manual, failures, key_revoked (its API key was revoked or its owner left) or plan (paused until the plan includes webhooks again).
consecutiveFailuresintegerrequired
lastSuccessAtstring (date-time) | nullrequired
lastFailureAtstring (date-time) | nullrequired
createdAtstring (date-time)required
updatedAtstring (date-time)required
delete/webhook-endpoints/{id}Delete a webhook
Minimum plan: ProScope: webhooks:writeIdempotency-Key

Parameters

id (path)string (uuid)required
Resource id.

Response 204

post/webhook-endpoints/{id}/testSend a test event
Minimum plan: ProScope: webhooks:writeIdempotency-Key

Parameters

id (path)string (uuid)required
Resource id.

Response 201 · WebhookDelivery

idstring (uuid)required
endpointIdstring (uuid)required
eventIdstringrequired
eventTypestringrequired
status"pending" | "succeeded" | "failed"required
attemptsintegerrequired
responseStatusinteger | nullrequired
errorstring | nullrequired
livemodebooleanrequired
createdAtstring (date-time)required
lastAttemptAtstring (date-time) | nullrequired
deliveredAtstring (date-time) | nullrequired
get/webhook-endpoints/{id}/deliveriesRecent deliveries
Minimum plan: ProScope: webhooks:read

Parameters

id (path)string (uuid)required
Resource id.
limit (query)integer
Page size (1–100).
cursor (query)string
nextCursor of the previous page.

Response 200 · WebhookDeliveryList

dataWebhookDelivery[]required
nextCursorstring | nullrequired
Pass it as cursor for the next page.
post/webhook-deliveries/{id}/retryResend a delivery
Minimum plan: ProScope: webhooks:writeIdempotency-Key

Parameters

id (path)string (uuid)required
Resource id.

Response 200 · WebhookDelivery

idstring (uuid)required
endpointIdstring (uuid)required
eventIdstringrequired
eventTypestringrequired
status"pending" | "succeeded" | "failed"required
attemptsintegerrequired
responseStatusinteger | nullrequired
errorstring | nullrequired
livemodebooleanrequired
createdAtstring (date-time)required
lastAttemptAtstring (date-time) | nullrequired
deliveredAtstring (date-time) | nullrequired