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

  1. POST /api-keys/{id}/rotate with {"grace_hours": 24}. Store token from the reply; no later call returns it.
  2. Put the new token where the old one was and deploy. The service keeps sending throughout, because the old token is still valid.
  3. Read GET /api-keys. Its summary begins "List API keys with 30-day request counts." The row for this key shows last_used_at, request_count_30d and previous_key_expires_at, which is non-null only while the old token still authenticates. GET /logs with api_key_id set to the key lists the requests it is making, so a deploy that reached every host shows as requests that keep succeeding.
  4. Nothing else. At previous_key_expires_at the old token stops. A host you missed then fails with invalid_api_key, whose catalogue message is "API key is invalid or revoked."; GET /logs with error_code=invalid_api_key finds 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"
}
Response

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.

Next