Skip to main content

Integrations & Reliability

Real-time SSE for clients, provider webhooks, error model, and polite API usage.

C
Written by Catalin Fetean
Updated over 3 weeks ago

Audience: Developers, Support
Outcomes: Real-time UX; robust back-office sync; resilient clients

Events & notifications

SSE (client)

const es = new EventSource('/api/events/stream', { withCredentials: true }); ['order.status.changed','payment.succeeded','contract.message','dispute.opened'].forEach(name => { es.addEventListener(name, e => console.log(name, JSON.parse(e.data))); });

Common events

  • Orders: order.created, order.status.changed

  • Contracts: contract.signed, contract.change_request

  • Payments: payment.intent.created, payment.succeeded, payment.failed

  • Escrow: escrow.released

  • Disputes: dispute.opened, dispute.resolved

Webhooks (providers)

  • Stripe route uses raw body + signature verification.

  • Bank route uses HMAC.

  • Handlers are idempotent; store processed event IDs.

Error model, idempotency & retries

Error format

{ "code":"VALIDATION_ERROR", "message":"Invalid payload", "issues":[{"path":["currency"],"message":"Must be a 3-letter code"}] }

Common codes

  • UNAUTHORIZED (401), FORBIDDEN (403 incl. KYC), NOT_FOUND (404),
    VALIDATION_ERROR (400), INTERNAL_ERROR (500).

Idempotency

  • Provide a stable reference (header or body).

  • Webhook handlers must dedupe by event ID.

Retry strategy

  • Network/5xx → exponential backoff.

  • 4xx → fix payload/permissions first.

Rate limits, pagination & filtering

  • Default rate limit: 100 req/min per org (plan-dependent).

  • Pagination: ?limit=50&cursor=... with nextCursor in responses.

  • Filtering: ?status=InProgress&from=2025-01-01&to=2025-12-31.

  • Back off on 429; reuse cached reads.

QA checklist

  • Sending same webhook twice doesn’t duplicate side effects.

  • Client respects 429 with backoff; resumes from nextCursor.

  • SSE stream reconnects and resumes without message loss (at-least-once semantics).

Did this answer your question?