Mint and revoke API keys, register webhook endpoints, rotate signing secrets, send test deliveries and read the delivery log.
GEThttps://api.spirestock.com/api/v1/developer/api-keys
List the API keys issued for your workspace. The secret itself is never returned — only the prefix, so you can identify a key you already saved. Workspace administrators only.
Example request
curl https://api.spirestock.com/api/v1/developer/api-keys \
-H "Authorization: Bearer YOUR_TOKEN"
Example response
{
"response_code": 200,
"data": [
{
"id": 3,
"name": "Warehouse sync",
"key_prefix": "df_9f3a1c",
"scopes": "read",
"status": 1,
"last_used_at": "2026-08-08T11:02:41.000Z",
"expires_at": null,
"created_at": "2026-07-30T09:15:00.000Z"
}
]
}POSThttps://api.spirestock.com/api/v1/developer/api-keys
Issue a new API key. The plaintext key is returned once, in this response only — it is stored as a SHA-256 hash and cannot be retrieved again. Send it as X-API-Key on subsequent requests. Workspace administrators only; requires a session token, not an API key.
Request body
name (string)required — Label to identify the key laterscopes (string) — Comma-separated. Actions: read (GET/HEAD), write (all methods, implies read). Optional resource scopes confine the key to those route groups, e.g. 'read,orders'. Use '*' for full access.expires_in_days (integer) — 1-3650. Omit for a key that never expires
Example request
curl -X POST https://api.spirestock.com/api/v1/developer/api-keys \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "Warehouse sync",
"scopes": "read,orders",
"expires_in_days": 90
}'Example response
{
"response_code": 201,
"message": "API key created. Save this key — it won't be shown again.",
"data": {
"id": 3,
"key": "df_9f3a1c7e2b...",
"name": "Warehouse sync",
"key_prefix": "df_9f3a1c",
"scopes": "read,orders",
"expires_at": "2026-11-08T00:00:00.000Z"
}
}DELETEhttps://api.spirestock.com/api/v1/developer/api-keys/{id}
Revoke an API key. The record is kept for audit purposes and its status is set to 0. Workspace administrators only.
Parameters
id (integer)required — API key ID
Example request
curl -X DELETE https://api.spirestock.com/api/v1/developer/api-keys/3 \
-H "Authorization: Bearer YOUR_TOKEN"
Example response
{
"response_code": 200,
"message": "API key revoked"
}GEThttps://api.spirestock.com/api/v1/developer/webhooks
List the webhook endpoints registered for your workspace, including delivery health via last_triggered_at and failure_count. Signing secrets are never included — rotate if you lost one. The response also carries supported_events.
Example request
curl https://api.spirestock.com/api/v1/developer/webhooks \
-H "Authorization: Bearer YOUR_TOKEN"
Example response
{
"response_code": 200,
"data": [
{
"id": 1,
"organization_id": 5,
"name": "Order events",
"url": "https://example.com/hooks/spirestock",
"events": "order.created,order.delivered",
"status": 1,
"last_triggered_at": "2026-08-09T18:40:12.000Z",
"failure_count": 0
}
],
"supported_events": ["order.created", "order.delivered", "user.created"]
}POSThttps://api.spirestock.com/api/v1/developer/webhooks
Register a webhook endpoint. A signing secret is generated and returned in this response only — store it and use it to verify deliveries. The URL must be HTTPS and resolve to a public address; private, loopback and link-local targets are rejected. Workspace administrators only.
Request body
name (string)required — Label to identify the endpointurl (string)required — HTTPS URL that will receive the POST. Must resolve to a public addressevents (string[] | string) — Any of order.created, order.delivered, user.created — as an array or comma-separated string. Unknown events are rejected
Example request
curl -X POST https://api.spirestock.com/api/v1/developer/webhooks \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "Order events",
"url": "https://example.com/hooks/spirestock",
"events": ["order.created", "order.delivered"]
}'Example response
{
"response_code": 201,
"message": "Webhook created. Save the signing secret — it won't be shown again.",
"data": {
"id": 1,
"organization_id": 5,
"name": "Order events",
"url": "https://example.com/hooks/spirestock",
"secret": "6f1c0e0b8a9d...",
"events": "order.created,order.delivered",
"status": 1,
"failure_count": 0
}
}PUThttps://api.spirestock.com/api/v1/developer/webhooks/{id}
Update a webhook endpoint. Omitted fields are left unchanged. Send status 0 to pause deliveries without deleting the endpoint or rotating its secret — pausing also cancels deliveries already queued for it. Workspace administrators only.
Parameters
id (integer)required — Webhook ID
Request body
name (string) — Label to identify the endpointurl (string) — HTTPS URL that will receive the POSTevents (string[] | string) — Events to subscribe to, as an array or comma-separated stringstatus (integer) — 1 to deliver, 0 to pause
Example request
curl -X PUT https://api.spirestock.com/api/v1/developer/webhooks/1 \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"events": ["order.created", "order.delivered", "user.created"],
"status": 1
}'Example response
{
"response_code": 200,
"message": "Webhook updated",
"data": {
"id": 1,
"name": "Order events",
"url": "https://example.com/hooks/spirestock",
"events": "order.created,order.delivered,user.created",
"status": 1
}
}DELETEhttps://api.spirestock.com/api/v1/developer/webhooks/{id}
Delete a webhook endpoint permanently. Deliveries stop immediately, any queued deliveries are cancelled, and the signing secret is discarded. Workspace administrators only.
Parameters
id (integer)required — Webhook ID
Example request
curl -X DELETE https://api.spirestock.com/api/v1/developer/webhooks/1 \
-H "Authorization: Bearer YOUR_TOKEN"
Example response
{
"response_code": 200,
"message": "Webhook deleted"
}POSThttps://api.spirestock.com/api/v1/developer/webhooks/{id}/rotate-secret
Issue a new signing secret for an endpoint. The only way to recover a secret lost after creation, and the correct response to one that leaked. Deliveries are signed with the new secret immediately, with no grace period — deploy it to your endpoint first. Workspace administrators only.
Parameters
id (integer)required — Webhook ID
Example request
curl -X POST https://api.spirestock.com/api/v1/developer/webhooks/1/rotate-secret \
-H "Authorization: Bearer YOUR_TOKEN"
Example response
{
"response_code": 200,
"message": "Signing secret rotated. Deliveries are signed with the new secret from now on — update your endpoint.",
"data": {
"id": 1,
"secret": "4b8e2c0a6f1d9e3b7a5c1f0d8e2b6a4c9f3e1d7b5a0c2e8f4d6b0a2c8e4f6d0b"
}
}POSThttps://api.spirestock.com/api/v1/developer/webhooks/{id}/test
Send a webhook.test payload, signed exactly like a real event, so you can confirm your endpoint is reachable and your signature check works before real events fire. Never retried. A delivery failure is reported in the body rather than as an error status — you asked whether the endpoint is reachable, and the answer 'no' is still a successful answer.
Parameters
id (integer)required — Webhook ID
Example request
curl -X POST https://api.spirestock.com/api/v1/developer/webhooks/1/test \
-H "Authorization: Bearer YOUR_TOKEN"
Example response
{
"response_code": 200,
"message": "Webhook test delivered — endpoint returned 200",
"data": {
"delivered": true,
"event_id": "evt_9f3a1c7e2b8d4a6f0c5e1b7a3d9f2e4c",
"response_status": 200,
"duration_ms": 218
}
}GEThttps://api.spirestock.com/api/v1/developer/webhook-deliveries
Recent delivery attempts, newest first — what was sent, what your endpoint returned, and what is still queued for retry. The first place to look when an endpoint is not receiving what you expect.
Parameters
webhook_id (integer) — Limit to a single endpointstatus (string) — One of pending, sending, sent, deadlimit (integer) — 1-200
Example request
curl "https://api.spirestock.com/api/v1/developer/webhook-deliveries?webhook_id=1&status=dead" \
-H "Authorization: Bearer YOUR_TOKEN"
Example response
{
"response_code": 200,
"data": [
{
"id": 4821,
"webhook_id": 1,
"event_id": "evt_9f3a1c7e2b8d4a6f0c5e1b7a3d9f2e4c",
"event_type": "order.created",
"status": "dead",
"attempts": 12,
"max_attempts": 12,
"next_attempt_at": null,
"last_attempt_at": "2026-08-18T04:11:07.000Z",
"sent_at": null,
"response_status": 500,
"response_body": "Internal Server Error",
"duration_ms": 812,
"last_error": "Internal Server Error",
"created_at": "2026-08-17T14:02:55.000Z"
}
]
}