Skip to content
Ledgerline Help

Restricted keys and scopes

Updated 27 August 20263 min read

On this page

A restricted key carries only the permissions you grant it. Use one wherever a service needs a slice of the API: a reporting job that only reads balances, a checkout service that only creates payouts, a webhook manager that only edits endpoints. If the key leaks, the damage is limited to what its scopes allow.

Scopes

Scopes are granted per key when you create it. They are additive: a key can do anything covered by at least one of its scopes and nothing else.

Scope Allows
ledgers:read Read ledgers, accounts, transactions, entries and balances.
ledgers:write Create and update ledgers and accounts; create, post, void and reverse transactions.
transfers:read Read transfers.
transfers:write Create transfers between accounts and FX conversions.
payouts:read Read payouts, counterparties and bank accounts.
payouts:write Create counterparties and payouts; cancel payouts; verify bank accounts.
webhooks:manage Create, update, delete and roll the secret of webhook endpoints; redeliver events.
reports:read Read statements and reconciliation results; create exports.

A write scope does not include the matching read scope. A key that creates payouts and also needs to look them up should have both payouts:write and payouts:read.

What a restricted key cannot do

Some operations are reserved for secret keys and the dashboard regardless of scopes:

  • Creating, rolling or revoking API keys.
  • Changing plan, billing details or team members.
  • Submitting or editing business verification.
  • Changing the organization's data region.

These calls fail with HTTP 403 and the code permission_denied when made with a restricted key.

Creating a restricted key

In the dashboard, choose Create key, select Restricted and tick the scopes. Through the API, a secret key can create one:

curl https://api.ledgerline.dev/v1/api_keys \
  -H "Authorization: Bearer ll_live_sk_replace_me" \
  -H "Idempotency-Key: 4b9d3a4f-2a8c-4f7e-a3a1-9a0d6c0b7e21" \
  -d type=restricted \
  -d name="nightly-reporting" \
  -d "scopes[]=ledgers:read" \
  -d "scopes[]=reports:read" \
  -d expires_at=2027-03-31T00:00:00Z

The response contains the new key once, with the prefix ll_live_rk_.

What happens without the scope

A request that needs a scope the key does not have is rejected before it runs:

{
  "error": {
    "type": "permission_error",
    "code": "scope_missing",
    "message": "This API key lacks the required scope: payouts:write.",
    "param": "payouts:write",
    "request_id": "req_01JA4B2XNE"
  }
}

The HTTP status is 403. The param field names the missing scope, so the fix is to create a new key with that scope. Scopes cannot be edited on an existing key. Create a replacement, deploy it and revoke the old one.

IP allowlists

On Growth and Scale plans you can pin a key to a set of IPv4 or IPv6 ranges in CIDR notation. Requests from any other address fail with 403 and the code ip_not_allowed. Combine an allowlist with a restricted key for the strongest setup. More in Security overview.

Expiry

Every key can have an expires_at timestamp. After that moment the key behaves as revoked and returns api_key_expired. The dashboard lists keys by expiry date so you can renew them before they stop working.

Choosing scopes: examples

Service Suggested scopes
Finance dashboard that shows balances ledgers:read
Payroll service that pays contractors payouts:write, payouts:read, ledgers:read
Reconciliation worker ledgers:read, reports:read
Deployment tooling that registers webhooks webhooks:manage

See API keys for how keys are issued, rolled and revoked.