Webhooks
Webhooks let your server react to events from your OAuth app's users in real time - a user authorizes your app, disconnects it, updates their display name, or your app signs a file through the REST signing endpoints - your endpoint gets an HTTP POST from Flowsta within seconds.
Webhooks are available on paid developer tiers only (Spark, Pro, Enterprise). Free-tier apps cannot register webhooks.
Quickstart
1. Register a webhook endpoint
Send a POST to /api/v1/webhooks with your developer session token (the bearer token dev.flowsta.com holds after you sign in) and the app_id of an app you own. A token that already carries an app (an app-scoped token) may omit app_id; any other token without it gets 403 app_required, and an app_id for an app you do not own gets 403 forbidden.
curl -X POST "https://auth-api.flowsta.com/api/v1/webhooks?app_id=<app-uuid>" \
-H "Authorization: Bearer <your-developer-token>" \
-H "Content-Type: application/json" \
-d '{
"url": "https://yourapp.com/hooks/flowsta",
"events": ["oauth.authorized", "oauth.token.revoked"]
}'URL requirements: https:// only, on a public hostname. localhost, *.local, *.internal, private and link-local IP ranges, and IPv6 local addresses are rejected with 400 invalid_url. To test from a development machine, put a public tunnel in front of it.
The response is HTTP 201 with the webhook, a human-readable message, and the secret used to HMAC-sign every payload. Store the secret securely - it is only returned on create.
{
"webhook": {
"id": "3f9c2a4e-7b1d-4e8a-9c0f-5d6e7a8b9c0d",
"url": "https://yourapp.com/hooks/flowsta",
"events": ["oauth.authorized", "oauth.token.revoked"],
"filters": {},
"secret": "a1b2c3...64 hex characters",
"created_at": "2026-04-13T10:00:00Z"
},
"message": "Webhook registered. Use the secret to verify payloads (HMAC-SHA256 of the body in X-Flowsta-Signature header)."
}You can also add and delete webhooks on the app's page at dev.flowsta.com (OAuth apps only). Editing and re-enabling are API-only.
2. Receive and verify the event
Flowsta sends a POST with Content-Type: application/json and two custom headers:
| Header | Value |
|---|---|
X-Flowsta-Event | The event type, e.g. oauth.authorized |
X-Flowsta-Signature | Hex-encoded HMAC-SHA256 of the raw request body, keyed by your webhook secret |
Always verify X-Flowsta-Signature before trusting the payload. See Verification.
// Express example - see /webhooks/verification for full code
app.post('/hooks/flowsta', express.raw({ type: 'application/json' }), (req, res) => {
const valid = verifyFlowstaSignature(req.body, req.header('X-Flowsta-Signature'), secret);
if (!valid) return res.status(401).end();
const event = JSON.parse(req.body.toString());
console.log(event.event, event); // e.g. "oauth.authorized"
res.status(200).end();
});3. Respond quickly
Return a 2xx status within the 10-second delivery timeout. Non-2xx responses count as a delivery failure. See Delivery & Failures for the exact policy.
What you can subscribe to
Every event is delivered only to the webhooks of the app it belongs to.
| Event | When it fires |
|---|---|
oauth.authorized | A user grants consent to your app on the consent screen (first authorization, or new scopes). Repeat sign-ins that skip the consent screen do not fire it |
oauth.token.revoked | A refresh token for your app is revoked through POST /oauth/revoke (a user disconnecting your app). Access tokens cannot be revoked, so nothing fires for them |
user.profile.updated | A user changes their display name. Delivered to the apps that hold an unrevoked refresh token for that user |
sign.created | Your app signs a file through POST /api/v1/sign-it/sign or /sign-batch with an OAuth token for your app. Signatures made in the user's Vault (the SDK's Vault path) raise no webhook |
sign.revoked | Your app revokes a signature through POST /api/v1/sign-it/revoke. Revocations made in the Vault raise no webhook |
Full payload shapes are documented in Event Types. subscription.* and user.2fa.* event names are accepted by the API but nothing fires them today.
Managing webhooks
GET /api/v1/webhooks/events- the event catalog (public, no token)GET /api/v1/webhooks?app_id=<uuid>- list webhooks for an appPUT /api/v1/webhooks/:id- updateurl,events,filters, or re-enable (active: true)DELETE /api/v1/webhooks/:id- delete
Creating a webhook (POST) is rate-limited to 30 requests per minute. The other management endpoints carry no rate limit.
Tier limits
Webhooks are counted per organization, across all apps.
| Tier | Webhooks |
|---|---|
| Free | 0 (not available) |
| Spark | 10 |
| Pro | 100 |
| Enterprise | Unlimited |
Creating a webhook on the Free tier returns 402 Payment Required with error: "tier_required"; an 11th webhook on Spark returns 402 with error: "limit_reached".