Tools
Webhooks and triggers
Get events sent to your server, and check that they came from Setu.
Events
- setu.approval.requested, setu.approval.approved, setu.approval.denied
- setu.execution.succeeded, setu.execution.failed
- setu.connection.connected, setu.connection.failed, setu.connection.revoked, setu.connection.attention_required
- setu.spend.threshold_reached
- setu.trigger.fired
Check the signature
Each delivery has x-supreme-timestamp and x-supreme-signature headers. The signature is v1= followed by the HMAC-SHA256 of "timestamp.rawBody" with your webhook secret. Reject deliveries older than 5 minutes. Failed deliveries can be replayed.
Triggers
A trigger subscription sends an app event for one user, such as a new Gmail message (GMAIL_NEW_EMAIL). Needs triggers:write, a key bound to an environment, a plan that includes triggers, and the user’s connection to that app.
# Send a webhook when customer_42 gets a new email.
curl https://setu.supremeai.services/api/setu/v1/trigger-subscriptions \
-H "Authorization: Bearer $SETU_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "trigger": "GMAIL_NEW_EMAIL", "userId": "customer_42" }'import { createHmac, timingSafeEqual } from 'node:crypto';
// Check the raw body before you parse it.
export function isFromSetu(rawBody: string, timestamp: string, signature: string, secret: string) {
if (!signature.startsWith('v1=')) return false;
if (Math.abs(Date.now() / 1000 - Number(timestamp)) > 300) return false; // 5-minute window
const expected = createHmac('sha256', secret).update(`${timestamp}.${rawBody}`).digest('hex');
const given = signature.slice(3);
return given.length === expected.length && timingSafeEqual(Buffer.from(given), Buffer.from(expected));
}
// timestamp = request header "x-supreme-timestamp", signature = "x-supreme-signature"