Skip to Content
Getting StartedWebhooks & Statuses

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

  1. Create an endpoint with a URL and a secret.
  2. Store your secret securely; it’s used to sign each webhook.
  3. Verify signatures on every request (see Security below).
  4. 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 invitation and organization_invitation resource 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: reject

Delivery 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 marked FAILED.
  • Any other 4xx (400, 401, 403, 404, 422, …) is terminal: the delivery is marked FAILED after one attempt with no retry. Fix the endpoint and use the replay endpoint to resend.
  • Return 5xx if you want automatic retries during transient downstream issues. Return 429 to signal throttling — it is treated like other transient errors (retried with backoff) and can still be marked FAILED once 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