Skip to content

Authentication

Outcome
Choose a key and environment that match your tenant model.
Prerequisites
A Space Invoices account.
You'll use
Account or entity API keys; sandbox before live.

All API requests require authentication using an API key, but the important decision is not just how to send the header. It is which key type and environment match your product model.

API Keys

You’ll find your API keys in the dashboard.

Choose The Right Key First

KeyPrefixBest forAccess scope
Account keysk_*Backend services, platforms, multi-entity controlOne account, potentially many entities
Entity keyek_*Isolated per-business access, customer-facing integrationsOne entity only

Choose The Right Environment

EnvironmentPrefix exampleUse it when
Sandboxsk_sandbox_*, ek_sandbox_*You are building, testing, demoing, or validating flows
Livesk_live_*, ek_live_*You are ready to issue real documents and operate in production

Using Your API Key

Include your API key in the Authorization header:

cURLbash
curl https://eu.spaceinvoices.com/entities \
  -H "Authorization: Bearer YOUR_API_KEY"

Or with the SDK:

SDKtypescript
import SpaceInvoices from "@spaceinvoices/js-sdk/sdk";

const _sdk = new SpaceInvoices("YOUR_API_KEY");

Account Key vs Entity Key

Use an account key when your backend needs to:

  • create or manage entities
  • switch across multiple customer businesses
  • act as the control plane for a platform, marketplace, fintech, or accounting product

Use an entity key when you want one business context only:

  • embedded customer-facing integrations
  • tenant-isolated access
  • simpler setups where one key should never move across entities

This is the most common split:

  • platform backend: account key
  • one tenant-facing integration or embedded UI: entity key

Environment Separation

Sandbox and live are completely separate:

  • different API keys
  • different data
  • different entities
  • no cross-contamination between test and production flows
Environment configtypescript
// Development
const _sdk = new SpaceInvoices(process.env.SI_SANDBOX_KEY);

// Production
const sdk = new SpaceInvoices(process.env.SI_LIVE_KEY);

Sandbox Behavior

The sandbox mirrors the production API model while keeping risk low.

AspectSandboxLive
DataSeparate test dataProduction data
API endpointsSame base URLSame base URL
KeysSandbox prefixesLive prefixes
FiscalizationTest servers where applicableReal authority servers
EmailRestricted test behaviorReal delivery behavior

Use sandbox for development, integration testing, demos, and first-value validation.

Key Rotation

To rotate your API key:

  1. Generate a new key in the dashboard
  2. Update your application to use the new key
  3. Revoke the old key once confirmed working

Rate Limits

Authenticated requests are limited per API token, with a shared-IP safety backstop. Authentication endpoints and document email sends have separate controls. See Rate Limiting for current defaults and retry handling.

  • start with a sandbox account key if you are still exploring
  • move to entity keys only when you need tenant-isolated access
  • keep live keys out of development environments
  • decide user access separately from API access

If your end users need dashboard access, continue to User Access.

Security Best Practices

  1. Store keys securely — Use environment variables or a secrets manager
  2. Use different keys per environment — Never use production keys in development
  3. Rotate regularly — Rotate keys at least quarterly
  4. Monitor usage — Set up alerts for unusual API activity
  5. Restrict access — Only give team members the access they need

Authenticator app protection

Users can turn on two-factor authentication in User settings:

  1. Scan the QR code with Google Authenticator or another TOTP app.
  2. Enter the six-digit code to confirm. Setup expires after ten minutes, and the account isn’t protected until it’s confirmed.
  3. Save the ten recovery codes somewhere safe.

Each recovery code works once. If you lose your authenticator, sign in with a recovery code, then turn two-factor off and set it up again to get new codes.

With two-factor on, password, Google, Apple and passkey sign-ins need a second step before you get a session:

  1. The sign-in returns a five-minute challenge. Its id starts with session_2fa_ and its scope is two_factor_pending. It can’t be used for API requests.
  2. Send it with the code to POST /users/two-factor/verify: { "token": "<challenge>", "code": "<authenticator-or-recovery-code>" }.
  3. Use the session that comes back.

Keep challenge tokens out of logs, URLs and persistent storage.

Reusing a code, an expired challenge or a consumed recovery code fails. Five incorrect codes lock verification for fifteen minutes across all challenges for that user. Password reset does not remove authenticator protection.

Shopify’s embedded password-only account linking rejects pending verification and enrollment challenges. If your account requires two-factor authentication, sign in to Apollo and connect Shopify there after completing verification or enrollment.

Changing authenticator settings requires the user’s own interactive session. Setup and disabling also require the current password, or a sign-in within ten minutes for users without a password. Disabling requires an unused authenticator or recovery code. Enabling and disabling revoke the user’s other sessions; API keys and separately delegated platform credentials retain their existing authorization model.

Authenticator secrets are encrypted at rest. Recovery codes are returned once and stored only as hashes. QR codes are generated locally by the API; no external QR service receives the secret. Keep recovery codes secure: this flow does not provide an email bypass when both the authenticator and recovery codes are lost.

Require two-factor authentication for a team

Account owners and admins can turn on Require two-factor authentication in the account team page. Entity settings managers can independently enable it in the entity users page. Both settings default to off. Existing sessions remain active; the requirement is checked on the next interactive login.

Account policy applies only to direct account-team membership. Entity policy applies only to direct entity-user membership. Neither setting flows through entity ownership, a white-label account association, parent accounts or sibling entities. If a user directly belongs to multiple scopes, any enabled policy requires enrollment for that user’s login. A user configures one authenticator for their identity, not a separate authenticator per scope.

The policy endpoints are GET and PUT /accounts/two-factor-policy (selected using X-Account-Id when needed) and GET and PUT /entities/{id}/two-factor-policy. The response and PUT body are { "required": true } or { "required": false }. PUT requires an explicit boolean; omitted and null values are rejected. Only an interactive session with the relevant administration permission may read or change the policy.

If two-factor is required and the user hasn’t set it up, sign-in returns a ten-minute setup challenge instead. Its id starts with session_2fa_setup_, its scope is two_factor_setup, and it can’t access ordinary endpoints.

  1. Call POST /users/two-factor/setup with { "token": "<challenge>" }, then scan the returned QR code or enter the manual secret.
  2. Call POST /users/two-factor/enable with { "token": "<challenge>", "code": "<six-digit-code>" }. It returns the recovery codes and a verified session: { "recovery_codes": ["<codes>"], "session": { "id": "<verified-session>", "user": {} } } (abbreviated).
  3. Show the recovery codes to the user before saving the session.

Accepting an entity invitation can also return a verification or setup challenge in access_token; check the prefix before saving that token. The web app and the iOS app both support required setup. Refreshing the web verification page means signing in again.

GET /users/me/two-factor includes required so settings can explain why disabling is unavailable. An applicable policy must be lifted before a user may disable or replace an enrolled authenticator through this flow. Turning a policy off does not disable authenticators that users have already configured.

White-label availability and branding

White-label entity users use the same enrollment and verification flow without needing account-team membership. Their authenticator entry uses the white label’s configured app name (falling back to its name), resolved from the authenticated user’s white-label account. The login screens retain the current white label’s auth shell, theme, and language behavior.

In white-label capabilities, two-factor authentication has the feature ID two_factor_authentication and follows the usual hidden_features settings, including new-feature review and the full-UI bypass for account users.

Hiding it removes the option to turn two-factor on and the controls to require it. Existing setups and requirements stay visible so they can be managed, and sign-in verification and required setup still run. Like other white-label controls, it doesn’t change API permissions or turn off an existing authenticator.