Questions · Updated 2026-09-28
How do I rotate an API key without downtime?
Rotate an API key without downtime with POST /api-keys/{id}/rotate and a grace window in grace_hours; the new token is returned once, and the token it replaces keeps working until previous_key_expires_at. Deploy the new token inside that window and there is nothing else to do. GET /api-keys shows the key's activity.
Rotate an API key without downtime by calling POST /api-keys/{id}/rotate with {"grace_hours": 24}. The operation summary is "Rotate an API key. The new token is returned once; the token it replaces keeps working for grace_hours (0, 1 or 24)." The reply carries token, previous_key_expires_at and rotated_at, and the key's id, budget_per_period, permission and scopes are the same as before, so nothing that refers to the key by id changes. Deploy the new token before previous_key_expires_at; both tokens authenticate until then.
The procedure
POST /api-keys/{id}/rotatewith{"grace_hours": 24}. Storetokenfrom the reply; no later call returns it.- Put the new token where the old one was and deploy. The service keeps sending throughout, because the old token is still valid.
- Read
GET /api-keys. Its summary begins "List API keys with 30-day request counts." The row for this key showslast_used_at,request_count_30dandprevious_key_expires_at, which is non-null only while the old token still authenticates.GET /logswithapi_key_idset to the key lists the requests it is making, so a deploy that reached every host shows as requests that keep succeeding. - Nothing else. At
previous_key_expires_atthe old token stops. A host you missed then fails withinvalid_api_key, whose catalogue message is "API key is invalid or revoked.";GET /logswitherror_code=invalid_api_keyfinds it.
curl -sS -X POST https://api.agentisend.com/api-keys/9c8f8f0e-3d1a-4d3f-9a1e-2b7c1a0f5e42/rotate \
-H "Authorization: Bearer $AGENTISEND_API_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{"grace_hours":1}'201
{
"budget_per_period": 1,
"created_at": "2026-09-04T09:14:00Z",
"domain_scope": "string",
"expires_at": "2026-09-04T09:14:00Z",
"id": "9c8f8f0e-3d1a-4d3f-9a1e-2b7c1a0f5e42",
"last_used_at": "2026-09-04T09:14:00Z",
"name": "yourdomain.com",
"period": "hourly"
}Choosing the window
grace_hours takes only the three values in the summary. With 0 the old token stops on this call and previous_key_expires_at is null, which is the choice for a token you believe has leaked. With 1 the window covers one deploy. With 24 it covers a day, which is the choice when the token lives in more than one place. Idempotency-Key applies to the rotate call, so a retried request does not mint a second token.
Revoke and rename are different calls
DELETE /api-keys/{id} is "Revoke an API key immediately." There is no grace, and the catalogue fix for invalid_api_key says deleted keys cannot be restored, so revoke is for a key that should not exist, and rotate is for a key that should keep its budget and its history. PATCH /api-keys/{id} is "Rename a key or change its domain scope and scopes. The token is unchanged — use POST /api-keys/:id/rotate for that." The budget lives on PATCH /limits/keys/{id} and survives a rotation, which is what makes rotating an agent's key safe: the ceiling does not reset.
Webhook secrets rotate separately
A webhook endpoint's signing secret is not an API key. POST /webhooks/{id}/rotate-secret mints a new one, and its summary says "The previous secret keeps verifying for 24 hours, and deliveries in that window are signed with both." How do I verify a webhook signature? shows the header that carries two signatures.