Webhooks overview
- Webhooks notify organizations in near real time about changes to related entities (orders, contacts, merchants, invitations).
- You can configure multiple endpoints per organization; all active endpoints receive all events.
- Event status can be inspected via the API.
Getting started
- Create an endpoint with a URL and a secret.
- Store your secret securely; it’s used to sign each webhook.
- Verify signatures on every request (see Security below).
- Use Ping to test your integration before going live.
Managing endpoints (Org‑scoped)
- Create: POST /organizations/:organizationId/webhooks
- List/get: GET /organizations/:organizationId/webhooks[/ :webhookId]
- Rotate secret: POST /organizations/:organizationId/webhooks/:webhookId/rotate-secret
- Pause/resume: POST /organizations/:organizationId/webhooks/:webhookId/(pause|resume)
- Delete: DELETE /organizations/:organizationId/webhooks/:webhookId (soft delete)
- Ping: POST /organizations/:organizationId/webhooks/:webhookId/ping
Secrets are write‑only and never returned after creation/rotation.
Events (read APIs)
- List: GET /organizations/:organizationId/webhook-events
- Filters: type, from, to, merchantId, resourceType, resourceId, page, limit
- Get: GET /organizations/:organizationId/webhook-events/:eventId
- Deliveries (lean status): GET /organizations/:organizationId/webhook-events/:eventId/deliveries
- Returns per-endpoint deliveries with deliveryStatus, retryCount, lastRetryAt, lastStatusCode, lastRespondedAt
Replay (Org-scoped, internal use by ops or via permissions):
- Replay an event: POST /organizations/:organizationId/webhook-events/:eventId/replay
- Re-enqueues to all active endpoints (or a single endpoint internally)
Event types
Grouped by resource family. See Webhooks Deep Dive → Event Types for a description of each event and when it fires.
- Orders:
order.created,order.approved,order.processing,order.paid,order.completed,order.failed,order.expired,order.canceled,order.refunded,order.updated - Merchants:
merchant.created - KYB:
merchant.kyb.in_progress,merchant.kyb.approved,merchant.kyb.rejected - Invitations (fired for both
invitationandorganization_invitationresource types):invitation.created,invitation.accepted,invitation.expired,invitation.failed,invitation.assigned - Policy approvals:
policy.approval.requested,policy.approval.received,policy.approval.approved,policy.approval.rejected - Policy execution (dynamic per resource type):
policy.order.executed,policy.account.executed,policy.deal.executed,policy.user_invite.executed,policy.passkey_enrollment.executed,policy.wallet_access_policy.executed,policy.policy.executed,policy.policy_rule.executed - Bank income:
bank_income.received - System:
webhook.ping
Subject to expansion; breaking changes roll out via the payload version field.
Payload and headers
- Content type: application/json
- Body skeleton
{
"id": "evt_...",
"type": "order.paid",
"version": "v1",
"occurred_at": "2025-08-16T21:52:14.292Z",
"source": "koywe.api",
"environment": "production",
"organization_id": "org_...",
"merchant_id": "mrc_...",
"data": { /* type-specific */ },
"relationships": { "self": { "type": "order", "id": "ord_..." } }
}- Headers (set by Koywe):
- Koywe-Event-Id, Koywe-Event-Type, Koywe-Event-Version
- Koywe-Organization-Id, Koywe-Merchant-Id (if applicable)
- Koywe-Environment
- Koywe-Webhook-Id
- Koywe-Signature: HMAC-SHA256 (hex) over the raw request body using your endpoint secret
- Koywe-Integrity-Signature: added by the delivery service to protect in-flight integrity
Environment is one of: local | qa | sandbox | production.
Security (signature verification)
- Compute HMAC-SHA256 of the exact request body using your saved endpoint secret.
- Compare your digest (hex) with Koywe-Signature. If they don’t match, reject the webhook.
- Replay-safe: use idempotency by event id (id is stable across replays).
Minimal pseudo-verification:
expected = hex(hmac_sha256(secret, raw_body))
if header["Koywe-Signature"] != expected: rejectDelivery behavior and retries
- On event creation, Koywe persists the event and enqueues a delivery per active endpoint.
- Each delivery receives a unique task id; you can fetch lean status via the deliveries endpoint.
- If an endpoint fails, other endpoints still receive their deliveries.
- You can request a replay to resend an event.
Retry rules:
- Request timeout is 30 seconds.
5xx,429, and network errors / timeouts are retried with backoff. After the retry budget is exhausted, the delivery is markedFAILED.- Any other
4xx(400,401,403,404,422, …) is terminal: the delivery is markedFAILEDafter one attempt with no retry. Fix the endpoint and use the replay endpoint to resend. - Return
5xxif you want automatic retries during transient downstream issues. Return429to signal throttling — it is treated like other transient errors (retried with backoff) and can still be markedFAILEDonce the retry budget is exhausted.
Best practices
- Respond 2xx quickly (< 5s); process asynchronously on your side.
- Validate Koywe-Signature on every request.
- Treat webhooks as at-least-once delivery; deduplicate using event id.
- Use the ping endpoint to verify connectivity after configuration or secret rotation.
Permissions (org-scoped)
- organization_webhooks.manage: create/update/pause/resume/delete/rotate
- organization_webhooks.view: list/get endpoints
- organization_webhook_events.view: list/get events, view deliveries
- organization_webhook_events.replay: replay events
This summary complements the OpenAPI docs with usage guidance, security expectations, and event taxonomy.
Last updated on