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
| Event | When |
|---|---|
user.plan_changed | A user’s plan changed (upgrade, downgrade, or expiry) |
user.key_created | A new inference key was minted |
user.key_revoked | A key was revoked |
usage.threshold_crossed | An 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: