Supported events
| Event | Description |
|---|---|
token.created | A new token was issued in your workspace. |
token.revoked | A token was explicitly revoked by a user or via the API. |
token.rotated | A token’s secret was rotated. The token ID remains the same. |
token.expired | A token’s expiration date passed and it is no longer valid. |
token.expiring | A token is approaching its expiration date. Tooken fires this event 7 days and 1 day before expires_at. Use it to trigger alerts or automated rotation. |
token.used | A token was used to authenticate a request. This is a high-volume event — opt in only if your endpoint can handle the throughput. |
Create a webhook
- Dashboard
- API
Open Webhooks settings
In the Tooken dashboard, click Settings in the left sidebar, then select the Webhooks tab.
Enter your endpoint URL
Paste the full HTTPS URL where Tooken should send event payloads. The endpoint must be publicly reachable and able to accept POST requests.
Select events
Check the events you want this webhook to receive. You can subscribe a single endpoint to multiple events, or create separate webhooks for different event types.
Webhook payload
Every event Tooken sends follows the same envelope structure: a top-levelevent name, a timestamp in ISO 8601 UTC, and a data object with the relevant resource fields.
Below is an example payload for a token.revoked event:
data vary by event type. For token.created, data includes id, name, created_by, and expires_at. For token.expired, data includes id, name, and expired_at. Refer to the API reference for full details.
Verify webhook signatures
Tooken signs every webhook request with anX-Tooken-Signature header. The value is an HMAC-SHA256 hex digest of the raw request body, computed using the webhook secret generated when you created the endpoint.
Compare the header value against a signature you compute server-side. If they do not match, reject the request with a 400 status and do not process the payload.
- Node.js
- Python
- Ruby
req.rawBody (the unparsed request body as a Buffer or string), not a parsed JSON object. Parsing the body before hashing changes the byte content and will cause the comparison to fail.Retries
If your endpoint does not return a2xx status within 10 seconds, Tooken marks the delivery as failed and schedules a retry.
Your endpoint must respond with a
2xx status code within 10 seconds. If it times out or returns a non-2xx response, Tooken treats the delivery as failed and will retry according to the schedule below.| Attempt | Delay after previous failure |
|---|---|
| 1st retry | 1 second |
| 2nd retry | 5 seconds |
| 3rd retry | 30 seconds |
| 4th retry | 2 minutes |
| 5th retry | 10 minutes |
How do I make my endpoint idempotent?
How do I make my endpoint idempotent?
Because Tooken retries on failure, your endpoint may receive the same event more than once. Use the payload’s
data.id field (the token ID) and the event name together as a deduplication key. Store processed event IDs in your database and skip any delivery where that combination has already been handled.Can I subscribe one endpoint to all events?
Can I subscribe one endpoint to all events?
Yes. When creating or editing a webhook via the API, pass
"events": ["*"] to subscribe to all current and future event types. In the dashboard, check All events when selecting events for the webhook.How do I test a webhook locally?
How do I test a webhook locally?
Use a tool like ngrok to create a public HTTPS tunnel to your local server, then register that URL as your webhook endpoint. From Settings → Webhooks, you can also click Send test event to push a sample payload to your endpoint without waiting for a real event to occur.
Can I disable a webhook without deleting it?
Can I disable a webhook without deleting it?
Yes. From Settings → Webhooks, toggle the webhook’s status to Inactive. Tooken will stop sending deliveries to the endpoint until you reactivate it. No deliveries are queued while the webhook is inactive.
