Permanent and immediate. The next proxy request with this token returns 401. The encrypted blob is retained for audit purposes but can no longer be decrypted via the proxy. To restore access, register the key again for a new shield token.

Documentation

Everything you need to integrate ShieldKey. Register an API key, get a shield token, update your base URL, and you're protected.

Quickstart

Get from zero to protected in under 5 minutes.

1. Get your account token

Sign up at shieldkey.io and grab your account token from the dashboard. This token authenticates management API calls -- it's different from your shield tokens.

2. Register your first API key

POST/v1/keys/register
$ curl -X POST https://api.shieldkey.io/v1/keys/register \
  -H "Authorization: Bearer YOUR_ACCOUNT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "provider": "stripe",
    "key": "sk_live_4eC39HqLyjWDarjtT1zdp7dc",
    "label": "Production Stripe",
    "policies": {
      "ip_allowlist": ["203.0.113.0/24", "198.51.100.42"],
      "rate_limit": {"requests": 500, "window": "1m"},
      "geo_restrict": ["US"]
    }
  }'

3. Save your shield token

response
{
  "id": "tok_a1b2c3d4e5f6",
  "shield_token": "sk_shield_7f3a9b2c1d8e5f6a4b0c9d2e",
  "proxy_url": "https://proxy.shieldkey.io/v1/stripe",
  "provider": "stripe",
  "label": "Production Stripe",
  "state": "active",
  "policies": {
    "ip_allowlist": ["203.0.113.0/24", "198.51.100.42"],
    "rate_limit": { "requests": 500, "window": "1m" },
    "geo_restrict": ["US"]
  },
  "created_at": "2026-02-15T12:00:00Z"
}
Important

The shield_token is shown only once at registration. Save it immediately. If lost, you'll need to register the key again to get a new shield token.

4. Update your code

Replace the API key and base URL. That's the entire integration.

javascript
// Before
const stripe = new Stripe('sk_live_4eC39HqLyjWDarjtT1zdp7dc');

// After
const stripe = new Stripe('sk_shield_7f3a9b2c1d8e5f6a4b0c9d2e', {
  host: 'proxy.shieldkey.io/v1/stripe'
});

Authentication

ShieldKey uses two types of tokens. Don't confuse them.

Token typeFormatUsed for
Account tokensk_acct_...Management API -- register keys, update policies, view audit logs
Shield tokensk_shield_...Proxy API -- making proxied requests to destination APIs

Both are passed as Bearer tokens in the Authorization header.

Register a key

POST/v1/keys/register
Encrypts your real API key, stores the blob, and returns a shield token.

Parameters

providerstring reqProvider slug: stripe, openai, aws, etc.
keystring reqYour real API key. Encrypted immediately, never stored in plaintext.
labelstringHuman-readable label for the dashboard.
policiesobjectEnforcement policies. See Enforcement policies.
expires_atdatetimeISO 8601 expiration date. Token auto-transitions to EXPIRED.

List tokens

GET/v1/keys
Returns all shield tokens with metadata. Never returns real keys.

Update policies

PATCH/v1/keys/{token_id}
$ curl -X PATCH https://api.shieldkey.io/v1/keys/tok_a1b2c3d4e5f6 \
  -H "Authorization: Bearer $ACCOUNT_TOKEN" \
  -d '{
    "policies": {
      "ip_allowlist": ["203.0.113.0/24", "10.0.0.0/8"],
      "rate_limit": {"requests": 1000, "window": "1h"}
    }
  }'

Policy changes take effect immediately. No need to regenerate the shield token.

Rotate real key

POST/v1/keys/{token_id}/rotate
$ curl -X POST https://api.shieldkey.io/v1/keys/tok_a1b2c3d4e5f6/rotate \
  -H "Authorization: Bearer $ACCOUNT_TOKEN" \
  -d '{"new_key": "sk_live_NEW_KEY_FROM_STRIPE"}'

The old encrypted blob is replaced with the new one. The shield token stays the same. Your application code doesn't change.

Revoke token

POST/v1/keys/{token_id}/revoke
$ curl -X POST https://api.shieldkey.io/v1/keys/tok_a1b2c3d4e5f6/revoke \
  -H "Authorization: Bearer $ACCOUNT_TOKEN"

Permanent and immediate. The next proxy request with this token returns 401. The encrypted blob is retained for audit purposes but can no longer be decrypted via the proxy. To restore access, register the key again for a new shield token.

Pause / Resume

POST/v1/keys/{token_id}/pause
Temporarily disable. Proxy returns 403. Reversible.
POST/v1/keys/{token_id}/resume
Re-enable a paused token. Takes effect immediately.

Audit log

GET/v1/audit/{token_id}?from=...&to=...
{
  "entries": [
    {
      "timestamp": "2026-02-15T14:32:01Z",
      "source_ip": "203.0.113.42",
      "geo": "US-VA",
      "method": "POST",
      "path": "/v1/charges",
      "status": 200,
      "latency_ms": 142,
      "enforcement": "passed"
    }
  ],
  "pagination": { "cursor": "...", "has_more": true }
}

Audit logs never contain API keys or request/response bodies. Metadata only. Retained for 90 days on Pro, configurable on Enterprise.

Teams

Every account belongs to at least one team. Teams are the ownership boundary for tokens, projects, billing, and audit logs.

Create team

POST/v1/teams
$ curl -X POST https://api.shieldkey.io/v1/teams \
  -H "Authorization: Bearer $ACCOUNT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"name": "Backend Team"}'
namestring reqDisplay name for the team.

Get team details

GET/v1/teams/{team_id}
Returns team metadata, member list, pending invitations, and billing status.
response
{
  "id": 42,
  "name": "Backend Team",
  "slug": "backend-team",
  "plan": "pro",
  "members": [
    { "account_id": 1, "email": "alice@example.com", "role": "owner" },
    { "account_id": 2, "email": "bob@example.com", "role": "member" }
  ],
  "pending_invitations": [],
  "billing_status": "active",
  "billing_period_end": "2026-03-15T00:00:00Z"
}

Update team

PATCH/v1/teams/{team_id}
$ curl -X PATCH https://api.shieldkey.io/v1/teams/42 \
  -H "Authorization: Bearer $ACCOUNT_TOKEN" \
  -d '{"name": "Platform Team"}'

Delete team

DELETE/v1/teams/{team_id}
Permanently deletes the team and all associated tokens. This cannot be undone.

Projects

Projects are optional groupings within a team. Use them to organize tokens by service, environment, or client.

Create project

POST/v1/teams/{team_id}/projects
$ curl -X POST https://api.shieldkey.io/v1/teams/42/projects \
  -H "Authorization: Bearer $ACCOUNT_TOKEN" \
  -d '{"name": "Production"}'
namestring reqProject name. Must be unique within the team.

Update project

PATCH/v1/teams/{team_id}/projects/{project_id}
$ curl -X PATCH https://api.shieldkey.io/v1/teams/42/projects/7 \
  -H "Authorization: Bearer $ACCOUNT_TOKEN" \
  -d '{"name": "Staging"}'

Delete project

DELETE/v1/teams/{team_id}/projects/{project_id}
Deletes the project. Tokens in this project become unassigned (not deleted).

Members & roles

Team members have one of three roles. Permissions are enforced on every API call.

RoleRegister keysRevoke / rotateManage membersBilling
ownerYesYesYesYes
adminYesYesYesNo
memberYesOwn tokens onlyNoNo
viewerNoNoNoNo

Invite member

POST/v1/teams/{team_id}/invite
$ curl -X POST https://api.shieldkey.io/v1/teams/42/invite \
  -H "Authorization: Bearer $ACCOUNT_TOKEN" \
  -d '{
    "email": "carol@example.com",
    "role": "member"
  }'
emailstring reqEmail address of the invitee.
rolestring reqOne of viewer, member, or admin.

The invitee receives an email with a link to accept. Pending invitations are visible in the team details response.

Update member role

PATCH/v1/teams/{team_id}/members/{account_id}
$ curl -X PATCH https://api.shieldkey.io/v1/teams/42/members/2 \
  -H "Authorization: Bearer $ACCOUNT_TOKEN" \
  -d '{"role": "admin"}'

Remove member

DELETE/v1/teams/{team_id}/members/{account_id}
Removes the member immediately. Their tokens remain but they lose access to manage them.
Offboarding tip

When someone leaves your team, remove them and revoke or rotate any tokens they had access to. ShieldKey makes this a two-click operation from the dashboard.

Token statistics

GET/v1/keys/{token_id}/stats
{
  "requests_24h": 1284,
  "requests_7d": 8923,
  "requests_30d": 34210,
  "last_seen_at": "2026-02-24T09:15:32Z",
  "policy_hits": {
    "ip_blocked": 12,
    "rate_limited": 3,
    "geo_blocked": 0
  }
}

Returns request counts across three time windows and a breakdown of policy enforcement hits. Use policy_hits to understand how often your enforcement rules are triggering.

Usage analytics

GET/v1/usage/team/{team_id}/summary
{
  "this_month": 142850,
  "today": 4231
}

Aggregated request count across all tokens in the team. Use this to track usage against your plan limits.

Anomaly detection

ShieldKey monitors proxy traffic and flags unusual patterns -- sudden spikes, requests from new geographies, or access outside normal hours.

GET/v1/anomalies/{team_id}?acknowledged=false&limit=20
[
  {
    "id": 891,
    "token_id": "tok_a1b2c3d4e5f6",
    "type": "geo_anomaly",
    "severity": "high",
    "message": "Requests from BR (previously only US, GB)",
    "detected_at": "2026-02-24T03:12:00Z",
    "acknowledged": false
  }
]

Query parameters

acknowledgedbooleanFilter by acknowledgment status. false returns only unreviewed anomalies.
limitintegerMaximum results to return. Default 20.

Anomalies are surfaced on the dashboard overview and can trigger email alerts if notifications are enabled.

Team audit log

The team audit log captures all management actions across the team -- token creation, policy changes, member invitations, revocations, and more.

GET/v1/audit/team/{team_id}?limit=50&action=revoke&from=...&to=...
{
  "entries": [
    {
      "timestamp": "2026-02-23T16:45:00Z",
      "actor_email": "alice@example.com",
      "action": "token.revoke",
      "target": "tok_a1b2c3d4e5f6",
      "metadata": { "label": "Contractor Stripe key" }
    }
  ],
  "pagination": { "cursor": "...", "has_more": true }
}

Query parameters

limitintegerResults per page. Default 50.
cursorstringPagination cursor from previous response.
actionstringFilter by action type: register, revoke, rotate, pause, resume, policy_update, member_invite, member_remove.
fromdatetimeStart of date range (ISO 8601).
todatetimeEnd of date range (ISO 8601).

This is separate from the per-token audit log, which tracks proxy request metadata. The team audit log tracks management operations.

Live activity

The dashboard's live view shows proxy requests in real time. The underlying endpoint returns the most recent audit entries for a specific token, polled at short intervals.

GET/v1/audit/{token_id}?limit=30
Returns the most recent proxy request entries for the token. Same schema as the audit log.

In the dashboard, this powers the live activity table with source IP, geography, HTTP method, path, status, latency, and enforcement result for each request.

Dead man's switch

If you stop checking in, ShieldKey auto-pauses all your tokens. This protects against compromised accounts or abandoned credentials.

Configure

PATCH/v1/auth/deadman
$ curl -X PATCH https://api.shieldkey.io/v1/auth/deadman \
  -H "Authorization: Bearer $ACCOUNT_TOKEN" \
  -d '{"checkin_required_days": 30}'
checkin_required_daysintegerNumber of days between required check-ins. Set to null to disable.

When enabled, if you don't check in within the configured window, all tokens across all your teams are automatically paused. You'll receive warning emails before the deadline.

Check in

POST/v1/auth/checkin
$ curl -X POST https://api.shieldkey.io/v1/auth/checkin \
  -H "Authorization: Bearer $ACCOUNT_TOKEN"

Resets the countdown. Logging into the dashboard also counts as a check-in.

When to use this

The dead man's switch is especially useful for solo founders and small teams. If you're the only person who knows about the API keys and something happens to you, the tokens auto-pause instead of remaining active indefinitely.

Notifications

Configure which email alerts you receive. All notifications are opt-in.

PATCH/v1/auth/notifications
$ curl -X PATCH https://api.shieldkey.io/v1/auth/notifications \
  -H "Authorization: Bearer $ACCOUNT_TOKEN" \
  -d '{
    "rotation_reminder": true,
    "anomaly_detected": true,
    "usage_threshold": true,
    "key_revoked": true,
    "deadman_switch": true,
    "rotation_days": 90
  }'

Parameters

rotation_reminderbooleanRemind you to rotate keys on a schedule.
anomaly_detectedbooleanAlert when unusual traffic patterns are detected.
usage_thresholdbooleanAlert when a token approaches its usage threshold.
key_revokedbooleanAlert when a token is revoked by any team member.
deadman_switchbooleanWarnings before the dead man's switch triggers.
rotation_daysintegerDays between rotation reminders (e.g. 90 for quarterly).

Billing

Billing is managed per team through Stripe. ShieldKey provides two endpoints to initiate checkout and access the billing portal.

Start checkout

POST/v1/billing/checkout
$ curl -X POST https://api.shieldkey.io/v1/billing/checkout \
  -H "Authorization: Bearer $ACCOUNT_TOKEN" \
  -d '{
    "tier": "pro",
    "interval": "annual",
    "team_id": 42
  }'
tierstring reqPlan tier: starter, pro, or enterprise.
intervalstring reqBilling interval: monthly or annual.
team_idinteger reqThe team to subscribe.

Returns a checkout_url that redirects the user to Stripe's hosted checkout page.

Billing portal

GET/v1/billing/portal
Returns a { "portal_url": "..." } with a link to Stripe's billing portal.

The billing portal lets you update payment methods, view invoices, and change or cancel your subscription.

Proxy routing

The proxy uses URL-based routing. Your request to ShieldKey mirrors the destination API's path structure.

pattern
https://proxy.shieldkey.io/v1/{provider}/{destination_path}

The proxy strips the /v1/{provider} prefix and forwards the remaining path to the provider's base URL. All headers (except Authorization, which is rewritten), body, query parameters, and HTTP method are forwarded unchanged. Note: proxied requests go through proxy.shieldkey.io, not the management API at api.shieldkey.io.

examples
# Stripe
POST proxy.shieldkey.io/v1/stripe/v1/charges
  → POST api.stripe.com/v1/charges

# OpenAI
POST proxy.shieldkey.io/v1/openai/v1/chat/completions
  → POST api.openai.com/v1/chat/completions

# AWS S3
GET proxy.shieldkey.io/v1/aws-s3/my-bucket/object.json
  → GET s3.amazonaws.com/my-bucket/object.json

Supported providers

Provider slugDestination base URLAuth method
stripeapi.stripe.comBearer token
openaiapi.openai.comBearer token
anthropicapi.anthropic.comx-api-key header
twilioapi.twilio.comBasic auth
sendgridapi.sendgrid.comBearer token
aws-s3s3.amazonaws.comAWS Signature V4
githubapi.github.comBearer token
customConfigured per tokenConfigured per token

Need a provider that's not listed? Use the custom slug and specify the base URL and auth method during registration.

Token lifecycle

StateProxy behaviorTransitions to
activeAccepts and forwards requests (subject to enforcement policies)paused, revoked, expired
pausedReturns 403. Reversible.active, revoked
revokedReturns 401. Permanent.Terminal state
expiredReturns 401. Auto-transitioned at expiry time.Terminal state

Enforcement policies

Policies are set per shield token and enforced on every proxy request before decryption.

ip_allowlist

Array of IP addresses or CIDR ranges. Supports IPv4 and IPv6. If set, only requests from these IPs are accepted. This is the most important policy to configure.

example
"ip_allowlist": ["203.0.113.0/24", "198.51.100.42", "2001:db8::/32"]

rate_limit

Sliding-window rate limit. requests is the max count, window is the time period (1s, 1m, 1h, 1d).

example
"rate_limit": { "requests": 1000, "window": "1h" }

geo_restrict

Array of ISO 3166-1 alpha-2 country codes. Requests from other countries are rejected.

example
"geo_restrict": ["US", "GB", "DE"]

Error codes

HTTP statusMeaningCause
401UnauthorizedInvalid, revoked, or expired shield token
403ForbiddenIP not in allowlist, geo restriction, or token is paused
429Rate limitedToken rate limit exceeded. Check Retry-After header.
502Bad gatewayDestination API returned an error or is unreachable
504Gateway timeoutDestination API did not respond within timeout window

All error responses include a JSON body with error and message fields. The X-ShieldKey-Enforcement header indicates which policy rejected the request.

example error response
HTTP/1.1 403 Forbidden
X-ShieldKey-Enforcement: ip_allowlist

{
  "error": "ip_not_allowed",
  "message": "Source IP 45.33.32.156 is not in the allowlist for this token",
  "token_id": "tok_a1b2c3d4e5f6"
}
Need help?

Join the ShieldKey community on Discord or email support@shieldkey.io. For Enterprise, reach out to sales@shieldkey.io for dedicated onboarding.