For AI agents: a documentation index is available at the root level at /llms.txt and /llms-full.txt. Append /llms.txt to any URL for a page-level index, or .md for the markdown version of any page.
WebsiteDashboardGet API key
  • Get Started
    • Welcome
    • Quickstart
    • Agent onboarding
    • Service keys
    • Core Concepts
  • Guides
    • Hosted Mode
    • Webhook Mode
    • Audio Mode
    • SMS and Conversations
    • Compliance and Consent
    • Billing and Usage
    • Voice zones
    • SMS zones
  • Reference
    • Authentication
    • API Overview
    • Errors and Testing
  • API Reference
      • GETList child API keys
      • POSTMint a child API key
      • GETGet a child API key
      • DELRevoke a child API key
      • PATCHUpdate a child API key
      • POSTAtomically rotate a child API key
  • Changelog
    • Cloudflare Insights CSP
    • Agent-native key management
    • Postpaid auto-charge
    • Cents-honest pricing
    • Stripe payments foundation
    • Hosted/webhook mode rename
    • Upgrading to v0.5.7.0
LogoLogo
WebsiteDashboardGet API key
API ReferenceKeys

Atomically rotate a child API key

POST
https://saperly.com/api/v1/keys/:id/rotate
POST
/api/v1/keys/:id/rotate
1const url = 'https://saperly.com/api/v1/keys/id/rotate';
2const options = {
3 method: 'POST',
4 headers: {'Idempotency-Key': 'Idempotency-Key', Authorization: 'Bearer <token>'}
5};
6
7try {
8 const response = await fetch(url, options);
9 const data = await response.json();
10 console.log(data);
11} catch (error) {
12 console.error(error);
13}
1{
2 "key": {
3 "id": "string",
4 "key_prefix": "sk_live_abc",
5 "environment": "live",
6 "name": "string",
7 "agent_label": "string",
8 "line_id": "string",
9 "permissions": "full",
10 "monthly_cap_cents": 1,
11 "monthly_spend_cents": 1,
12 "created_at": "2024-01-15T09:30:00Z",
13 "revoked_at": "2024-01-15T09:30:00Z",
14 "last_used_at": "2024-01-15T09:30:00Z",
15 "rotated_from": "string",
16 "created_by_service_key_id": "string",
17 "plaintext_key": "sk_live_abc123def456..."
18 }
19}
Atomically revokes a child API key and mints a replacement that inherits its configuration (`name`, `agent_label`, `line_id`, `permissions`, `monthly_cap_cents`). The new key's `rotated_from` field references the OLD key's id. Old and new rotation happen inside one SQL transaction — partial rotations are impossible. The plaintext of the new key is returned in `plaintext_key` EXACTLY ONCE. Idempotency replays within 12 hours return the redacted row (no `plaintext_key`). Reusing the same `Idempotency-Key` for a rotation on a DIFFERENT child key returns 409 `idempotency_key_reused`. Rate-limited to 30 requests per hour per service key. 429 responses carry `Retry-After: 120`.
Was this page helpful?
Previous

List all lines

Next
Built with

Atomically revokes a child API key and mints a replacement that inherits its configuration (name, agent_label, line_id, permissions, monthly_cap_cents). The new key’s rotated_from field references the OLD key’s id. Old and new rotation happen inside one SQL transaction — partial rotations are impossible.

The plaintext of the new key is returned in plaintext_key EXACTLY ONCE. Idempotency replays within 12 hours return the redacted row (no plaintext_key). Reusing the same Idempotency-Key for a rotation on a DIFFERENT child key returns 409 idempotency_key_reused.

Rate-limited to 30 requests per hour per service key. 429 responses carry Retry-After: 120.

Authentication

AuthorizationBearer

Service keys (sk_svc_*) authenticate the /v1/keys/* management plane. Send as Authorization: Bearer <service-key>. Service keys are minted only from the portal (Settings → Service Keys); there is no API path to mint another service key.

Path parameters

idstringRequiredformat: "uuid"
Child API key ID

Headers

Idempotency-KeystringRequired

Required. Sticky-cached for 12 hours per (service key, Idempotency-Key) pair.

Response

Child API key rotated
keyobject

Returned by POST /v1/keys and POST /v1/keys/{id}/rotate on the FIRST call only. Idempotency replays within the 12-hour TTL return the same row WITHOUT the plaintext_key field — the plaintext is never re-disclosable.

Errors

400
Bad Request Error
401
Unauthorized Error
404
Not Found Error
409
Conflict Error
429
Too Many Requests Error