Handle Xcity webhooks

Subscribe to plan, key, and usage events from xcity-home.

Xcity emits webhooks for Enterprise customers and B2B partners that need to react to plan, key, or usage changes.

Subscribe

Configure the webhook URL via enterprise@xcity.one or — when self-serve is available — /dashboard/webhooks.

Events

EventWhen
user.plan_changedA user’s plan changed (upgrade, downgrade, or expiry)
user.key_createdA new inference key was minted
user.key_revokedA key was revoked
usage.threshold_crossedAn account crossed a configured % of its monthly cap

Payload shape:

{
  "id": "evt_...",
  "type": "user.plan_changed",
  "created": 1747353600,
  "data": {
    "user_id": "uuid",
    "previous_plan": "pro",
    "current_plan": "team"
  }
}

Signatures

Every webhook is signed with X-Xcity-Signature: t=<unix>,v1=<hmac>. Verify with the secret returned at subscription time:

import crypto from 'node:crypto';

function verify(payload: string, header: string, secret: string): boolean {
  const [t, v1] = header.split(',').map((p) => p.split('=')[1]);
  const expected = crypto
    .createHmac('sha256', secret)
    .update(`${t}.${payload}`)
    .digest('hex');
  return crypto.timingSafeEqual(Buffer.from(v1), Buffer.from(expected));
}

Retries

We retry on non-2xx for up to 24h with exponential backoff. Always return 2xx quickly — defer slow work to your own queue.

Idempotency: every event has a unique id. Use it as the idempotency key in your handler.

Last updated: