diff --git a/public/index.html b/public/index.html index cb22962..9022f02 100644 --- a/public/index.html +++ b/public/index.html @@ -231,6 +231,31 @@ ul li, ol li { margin-bottom: 0.5rem; } + + .scope-table { + border-collapse: collapse; + width: 100%; + margin: 1rem 0 1.5rem; + font-size: 0.95rem; + } + + .scope-table th, .scope-table td { + text-align: left; + padding: 0.6rem 0.9rem; + border-bottom: 1px solid #e1e1e1; + } + + .scope-table th { + background-color: #f5f5f5; + color: var(--color-secondary); + font-weight: 600; + } + + .scope-table td code { + background-color: #f5f5f5; + padding: 2px 6px; + border-radius: 4px; + }
@@ -254,6 +279,7 @@API keys let server-side integrations and third-party developers call the Flash API without a user session — a payment processor accepting Bitcoin, an analytics job reading balances, or a bot creating invoices. Unlike a short-lived login token, a key is long-lived, scoped to specific permissions, and managed by the account owner.
+ +A key has the format fk_<keyId>_<secret>. Only a hash of the secret is ever stored, so the full key is shown once at creation and can never be retrieved again — store it securely.
Keys are created from an authenticated user session (an API key cannot create or manage keys — this prevents a leaked key from minting more). Call apiKeyCreate with a name, the scopes it needs, and optionally an expiry and a per-key rate limit:
mutation {
+ apiKeyCreate(input: {
+ name: "BTCPayServer integration"
+ scopes: [read_user, read_wallet, write_wallet]
+ expiresIn: 7776000 # optional — seconds until expiry (here, 90 days). Omit for no expiry.
+ rateLimitPerMinute: 300 # optional — omit to use the platform default.
+ }) {
+ apiKey {
+ keyId
+ apiKey # the raw key — returned once, copy it now
+ scopes
+ expiresAt
+ }
+ errors { message }
+ }
+}
+ Send the key in the X-API-KEY header — not the Authorization header, which carries user session tokens:
curl -X POST https://api.flashapp.me/graphql \
+ -H 'Content-Type: application/json' \
+ -H "X-API-KEY: fk_<keyId>_<secret>" \
+ -d '{"query":"query { me { defaultAccount { wallets { walletCurrency balance } } } }"}'
+ An invalid, revoked, or expired key — or one used from a disallowed IP — is rejected with 401 Unauthorized.
Access is deny-by-default: a key can only reach the operations covered by the scopes it was granted. Grant the minimum an integration needs.
+| Scope | Grants |
|---|---|
read_user | Read profile and account details |
write_user | Modify profile and account settings |
read_wallet | Read wallet balances and details |
write_wallet | Move funds — send and receive |
read_transactions | Read transaction history |
write_transactions | Create transactions |
admin | Full account access |
write_* implies the matching read_*, and admin implies every scope. A request outside a key's scopes is rejected with a GraphQL error naming the missing scope. Sensitive operations — login, two-factor, and API-key management itself — are never available to API keys, only to user sessions.
Each key has a requests-per-minute budget (its rateLimitPerMinute, or the platform default). When the budget is exhausted, requests are rejected with a GraphQL error carrying extensions.code = "TOO_MANY_REQUESTS" and a retryAfterSeconds hint — back off for that long before retrying:
{
+ "data": null,
+ "errors": [
+ {
+ "message": "API key rate limit exceeded",
+ "extensions": {
+ "code": "TOO_MANY_REQUESTS",
+ "retryAfterSeconds": 42,
+ "rateLimit": { "limit": 300, "remaining": 0 }
+ }
+ }
+ ]
+}
+ From a user session (not from a key), you can list, rotate, and revoke:
+apiKeys — list the account's keys with their scopes, status, last-used and expiry. Never returns secret material.apiKeyRotate(input: { id }) — issue a fresh secret for a key and retire the old one in a single step. The new raw key is returned once.apiKeyRevoke(input: { id }) — permanently disable a key; it stops authenticating on the next request.Fetch account details and wallet balances (requires a valid auth token):
API keys let server-side integrations and third-party developers call the Flash API without a user session — a payment processor accepting Bitcoin, an analytics job reading balances, or a bot creating invoices. Unlike a short-lived login token, a key is long-lived, scoped to specific permissions, and managed by the account owner.
+ +A key has the format fk_<keyId>_<secret>. Only a hash of the secret is ever stored, so the full key is shown once at creation and can never be retrieved again — store it securely.
Keys are created from an authenticated user session (an API key cannot create or manage keys — this prevents a leaked key from minting more). Call apiKeyCreate with a name, the scopes it needs, and optionally an expiry and a per-key rate limit:
mutation {
+ apiKeyCreate(input: {
+ name: "BTCPayServer integration"
+ scopes: [read_user, read_wallet, write_wallet]
+ expiresIn: 7776000 # optional — seconds until expiry (here, 90 days). Omit for no expiry.
+ rateLimitPerMinute: 300 # optional — omit to use the platform default.
+ }) {
+ apiKey {
+ keyId
+ apiKey # the raw key — returned once, copy it now
+ scopes
+ expiresAt
+ }
+ errors { message }
+ }
+}
+ Send the key in the X-API-KEY header — not the Authorization header, which carries user session tokens:
curl -X POST https://api.flashapp.me/graphql \
+ -H 'Content-Type: application/json' \
+ -H "X-API-KEY: fk_<keyId>_<secret>" \
+ -d '{"query":"query { me { defaultAccount { wallets { walletCurrency balance } } } }"}'
+ An invalid, revoked, or expired key — or one used from a disallowed IP — is rejected with 401 Unauthorized.
Access is deny-by-default: a key can only reach the operations covered by the scopes it was granted. Grant the minimum an integration needs.
+| Scope | Grants |
|---|---|
read_user | Read profile and account details |
write_user | Modify profile and account settings |
read_wallet | Read wallet balances and details |
write_wallet | Move funds — send and receive |
read_transactions | Read transaction history |
write_transactions | Create transactions |
admin | Full account access |
write_* implies the matching read_*, and admin implies every scope. A request outside a key's scopes is rejected with a GraphQL error naming the missing scope. Sensitive operations — login, two-factor, and API-key management itself — are never available to API keys, only to user sessions.
Each key has a requests-per-minute budget (its rateLimitPerMinute, or the platform default). When the budget is exhausted, requests are rejected with a GraphQL error carrying extensions.code = "TOO_MANY_REQUESTS" and a retryAfterSeconds hint — back off for that long before retrying:
{
+ "data": null,
+ "errors": [
+ {
+ "message": "API key rate limit exceeded",
+ "extensions": {
+ "code": "TOO_MANY_REQUESTS",
+ "retryAfterSeconds": 42,
+ "rateLimit": { "limit": 300, "remaining": 0 }
+ }
+ }
+ ]
+}
+ From a user session (not from a key), you can list, rotate, and revoke:
+apiKeys — list the account's keys with their scopes, status, last-used and expiry. Never returns secret material.apiKeyRotate(input: { id }) — issue a fresh secret for a key and retire the old one in a single step. The new raw key is returned once.apiKeyRevoke(input: { id }) — permanently disable a key; it stops authenticating on the next request.Fetch account details and wallet balances (requires a valid auth token):