Authentication

Two separate things: signing in to the dashboard, and calling the REST API.

The owner operations report also includes a Plaid credential check when authenticated with the operations token. It reads the free institution directory without connecting an account or creating an Item. Results, including errors, are stored across Worker instances. Health responses return the last result immediately and start one background refresh when it is older than ten minutes. Before the first check finishes, status is pending and checked_at is null. Errors include validated Plaid error_type and error_code, http_status and request_id when available for support. Redirects are never followed and report UNEXPECTED_REDIRECT with the HTTP status. Network failures report NETWORK_ERROR and the twenty-second timeout reports TIMEOUT. Missing or malformed codes report UNAVAILABLE. Provider messages and credentials are never included. Disabled Plaid makes no call. The public health response is unchanged.

First-visit source information is saved at sign-up for email and Google accounts. The owner operations report at /ops/health includes the latest 100 organizations and their sources only when authenticated with the operations token. Missing source information is returned as null. Trial enforcement runs independently of billing synchronization. Trials are never disabled globally.

The owner operations report also includes upload_digests: reconciliation count, rejected requests awaiting retry, oldest unresolved attempt, and up to 25 reconciliation batches with delivery outcomes and errors. Definite rejections retry automatically. Ambiguous attempts stop retrying after 23 hours and require operator reconciliation with provider records before any resend.

Email sign-up requires a Turnstile security check with the signup action and the configured application hostname. Each token can be used once.

The REST API: Bearer API keys

Every request to the REST API authenticates with a Bearer API key. Create keys in Dashboard, under API keys.

The full key value is shown exactly once, at creation; the server stores only a hash of it, so if you lose a key there is no way to retrieve it, only to revoke it and create a new one.

bash
curl https://arkrel.com/v1/documents \
  -H "Authorization: Bearer sk_live_..."

Read and write keys

Every key is created with one of two permission scopes, chosen at creation time and shown in the dashboard's API keys table:

  • write (the default) can call every endpoint: upload and delete documents, and create or delete webhooks and schemas.
  • read can only make safe, read-only requests: listing and fetching documents, schemas, webhooks, and usage. A read-only key gets 403 FORBIDDEN from any request that would upload, delete, or create/modify anything, and from the equivalent MCP tools (e.g. extract_document).
  • A key's scope can't be changed after creation; create a new key with the scope you need and revoke the old one.

Expiry

A key can optionally be given an expiry (30 days, 90 days, or 1 year) at creation time. An expired key stops authenticating automatically, the same as a revoked one; there is nothing to clean up. Leave it unset for a key that should never expire on its own.

Key scope (organization & endpoints)

  • A key belongs to one organization. It cannot see or act on another organization's data.
  • Keys are not tied to a document type or schema; any key can call any endpoint its permission scope above allows.
  • Revoking a key takes effect immediately; in-flight requests already authenticated are not retroactively cancelled.
  • Only organization owners and admins can create or revoke API keys; other members can see that keys exist but not manage them. Creating or revoking a key requires re-confirming your password, two-factor code, passkey, emailed code for a passwordless account, or linked Google sign-in first, if it's been a while since you last did.
  • Removing a member from the organization automatically revokes every API key (and disables every webhook) they created.

Rotating a key safely

Create the new key first, deploy it, confirm traffic has moved, then revoke the old one. Nothing forces a hard cutover.

The dashboard's own sign-in

Accounts with a password must enable an authenticator app (TOTP) before checkout, billing changes, reports and exports, sharing, API keys and MCP, bank or ledger connections, team changes, email or password changes, sender allowlist changes, and callback secrets. This also applies with a linked passkey or Google sign-in. Accounts without a password keep their existing protection rules. The free first look stays open: verify your email, sign in, upload or email in your first statement, review merchants and rules, preview My year and the locked report, view pricing, or edit your profile or business name. A business rename must send only the name field; requests with retention or any other field still require protection. You can sign out or delete your account without TOTP; deletion keeps its existing identity check.

Uploads within your included monthly or purchased Catch-Up allowance remain available. Using paid page credits or billable overage requires protection before upload. A business with an active saved outbound webhook also requires protection before uploading, even without a callback in the upload request. Callback delivery and retries check the current protection of both the webhook creator and document uploader. If the processed page count exceeds that allowance, processing stops without spending and asks you to protect your account before uploading again. Business settings changes, session revocation, provider linking and token access require protection. Signing in with a new provider cannot automatically link to an existing account with the same email. Sign in with your password first, protect your account and verify your identity, then link explicitly. Explicit linking and passkey registration require a fresh identity check, including when the callback or registration finishes. Existing provider sign-in and new provider signup remain available. Sign-in, recovery and authenticator enrollment remain available. Passkey registration and credential removal require protection. Removing an OAuth account or passkey also requires a fresh identity check. Password sign-in can be changed but cannot be removed; unlinking it returns PASSWORD_REMOVAL_NOT_ALLOWED. Ledger chart sync and chart writes require protection. Stored chart and categorization-settings views remain available without contacting a provider. Sensitive app API requests return 403 TWO_FACTOR_SETUP_REQUIRED until setup is complete. Sign-up and sign-in open the app without a setup redirect. A refused action shows "Protect your account to continue" inline. Scan the QR code, verify the code and save your backup codes, then the action resumes. Existing role, plan and step-up checks still apply. Direct links to /protect-account also work.

The web dashboard is a completely separate system from the API keys above: it signs in with a password, a passkey (Face ID, Touch ID, or a security key), or Google, then sets a session cookie. There is no email-link ("magic link") sign-in option, anywhere. See Two-factor authentication, Passkeys, and Sessions and devices for detail. This session is separate from API keys and is used only by the dashboard's own endpoints under /app/api/*, not the public /v1/* API documented on this page.

API keys and MCP credentials are checked against their creating user on every request. If that user has a password without enabled TOTP, requests return HTTP 403 TWO_FACTOR_SETUP_REQUIRED. Organization/service keys with no creating user keep their existing behavior.