Skip to main content

Emergency Key Revoke

Immediately invalidate a leaked or compromised API key.

If you have any reason to believe an API key has been exposed (a public commit, a security alert from your monitoring, a former employee with credentials), use emergency revoke instead of standard rotation. Emergency revoke is destructive: there is no 24-hour grace window. The old key dies the moment the request returns, and any integration still using it will start failing.

When to use this vs. rotation

  • Rotation is for routine key hygiene (~every 90 days). The old key remains valid for 24 hours so you can deploy the new one without downtime. Rotation requires a fresh two-factor step-up and is rate-limited.
  • Emergency revoke is for suspected compromise. The old key dies immediately. The cooldown is bypassed. Use this only when you have reason to believe the key is in the wrong hands.

If you are not sure which to use, prefer rotation; it is the safe default.

Request

POST /v1/api-keys/{id}/emergency-revoke

This endpoint can only be triggered from the merchant dashboard with a signed-in operator session. API keys cannot call this endpoint, even on themselves: a compromised key must not be able to rotate itself silently.

Body

{
"confirmation": "Acme Inc.",
"reason_note": "Discovered key in a public GitHub commit at 14:32 UTC"
}
FieldTypeRequiredNotes
confirmationstringyesMust equal your merchant account name exactly (case-sensitive). Same friction pattern as AWS IAM destructive operations.
reason_notestringnoFree-text incident note, up to 280 characters. Recorded in your audit log only; never included in webhook payloads.

Response

200: Success

{
"merchant_id": 1,
"key_id": "prd_<new>",
"new_plaintext_key": "rail_full_live_<random64>",
"revoked_key_id": "prd_<old>",
"revoked_at": "2026-05-11T15:00:00.000Z",
"reason": "suspected_compromise"
}

The new_plaintext_key is returned once in this response. There is no way to retrieve it again: copy it immediately, update your integration, and discard the dashboard tab. The dashboard's modal displays the same value via copy-to-clipboard for convenience.

4xx / 5xx: Errors

CodeHTTPCause
ERR_1011401No merchant session. Sign in to the dashboard first.
ERR_1012403The request was authenticated with an API key. Emergency revoke is dashboard-session only.
ERR_2002400Malformed key id in the path.
ERR_2003400reason_note exceeds 280 characters.
ERR_3010422Your merchant account is not provisioned. Complete provisioning from the dashboard.
ERR_3012404Key not found for your merchant. Check the id path parameter.
ERR_3022409Another operator on your team already emergency-revoked this key. The response includes the current active key state.
ERR_3023422The confirmation field is missing, empty, or does not match your merchant name exactly.
ERR_5005503Partial failure: a new key was issued but the old key was not killed in time. Retry the endpoint to complete the revoke.
ERR_5099500Internal server error. Contact support if it persists.

ERR_3008 rotation_cooldown_active is explicitly NOT emitted by this endpoint. The cooldown applies only to the standard POST /v1/api-keys/{id}/rotate flow; emergency mode unconditionally bypasses it.

Webhook event

A successful emergency revoke triggers a key_emergency_revoked event delivered to every webhook endpoint you have registered. The payload:

{
"key_id": "prd_<old>",
"new_key_id": "prd_<new>",
"key_prefix": "rail_full_live_",
"revoked_at": "2026-05-11T15:00:00.000Z",
"revoked_by": {
"actor_type": "merchant",
"actor_id": "<16-char opaque hash>"
},
"reason": "suspected_compromise"
}

The revoked_by.actor_id field is a stable opaque identifier, useful for correlating multiple actions from the same operator across events. The new key's plaintext is never in the webhook payload; only the new key id and prefix appear. Your reason_note (if you provided one) is also never in the webhook payload; it lives only in your audit log.

The webhook is signed with TensorRail-Signature (HMAC-SHA512) like every other event TensorRail emits. See Webhooks for the verification pattern.

Audit log

Every emergency revoke, successful or rejected, is recorded in your merchant audit log. Visit the Audit tab in the dashboard to see the full history. Each entry captures:

  • The operator who triggered the request (the signed-in dashboard operator).
  • IP address, user agent, request ID.
  • The key revoked and the new key issued.
  • Your optional reason_note.
  • The outcome (success, confirmation mismatch, race lost to another operator).

Race conditions

If two operators on your team trigger emergency revoke on the same key within milliseconds of each other:

  1. One request returns 200 with the new key.
  2. The other returns 409 ERR_3022 key_already_revoked with the current active key id in the response.
  3. Only one webhook event is emitted.
  4. Both attempts are recorded in your audit log.

This is the correct semantic: there is one revoke event, two operators witnessed it.

How to trigger it

Emergency revoke is a dashboard action, not an API-key call. In your dashboard, go to Developers → API Keys, find the compromised key, and click the red Emergency revoke button. You will be asked to type your merchant account name to confirm, and you can attach an optional incident note. The dashboard handles the operator session and confirmation flow for you, then displays the new key once via copy-to-clipboard.

Because this requires a signed-in operator session and cannot be authenticated with an API key, there is no integration curl recipe: a compromised key must not be able to revoke itself. The endpoint, body, and responses documented above describe what the dashboard sends on your behalf.

See also

  • Authentication: API key prefixes and scopes
  • Webhooks: signature verification and delivery semantics
  • Idempotency: Idempotency-Key header (note: emergency revoke does NOT respect idempotency; each call is processed fresh)