Skip to content

Authentication

Every request carries an API key as a bearer token:

Terminal window
curl https://api.flychain.us/external/v1/business_entities \
-H "Authorization: Bearer $FLYCHAIN_API_KEY"

Always https://. A request to http:// is refused with 400 INSECURE_TRANSPORT rather than redirected, because a redirect cannot un-send what was already transmitted: the key travelled the network unencrypted, so it must be treated as compromised and rotated. We refuse rather than redirect precisely so this is impossible to miss.

There is no OAuth flow, no token refresh and no per-provider consent step, whichever kind of key you hold.

A key is always exactly one of these. Which one you hold determines both what it can read and which endpoints it reaches.

Issued to a platform that reads the books of the providers in its partner relationship.

  • Scoped to your partner relationship. It reads only the providers in that relationship. A request for anything outside it is rejected — see Data semantics on how “not yours” is reported differently from “does not exist”.
  • No per-provider authorization. Because you hold the credential rather than each provider, a provider joining Flychain needs no new authorization step on your side or theirs. They simply appear in GET /business_entities. This is the main operational difference from pulling reports out of a provider’s own accounting system.

Issued to a Flychain provider reading its own books. See Provider quickstart for the full walkthrough.

  • Scoped to one provider — its own. A request naming any other provider or business entity is answered as though that id did not exist.
  • It reads every business entity under that provider. Per-user entity restrictions configured for individual staff in the provider’s Flychain organization do not apply to it: an organization key has no user, so there is nothing to filter by. Those restrictions are an internal delegation control, not a boundary against the provider itself.
  • Access follows the Flychain account. A provider whose account is not active, or which is not enrolled in the API programme, is refused with a 403 — see the failure table.
  • Read-only. Every endpoint on this API is a GET. There is nothing here that can modify data on our side.
  • Not tied to a person. A key belongs to your organization, so it keeps working when the engineer who created it changes role.

Fourteen operations. Six are open to both kinds of key; eight are provider-key only.

Report paths are shown relative to /provider/{provider_id}/business_entity/{business_entity_id}/financial_reports. Discovery paths are absolute.

Endpoint Partner key Provider key
/providers yes yes
/business_entities yes yes
income_statement yes yes
income_statement/summary yes yes
income_statement/monthly yes yes
income_statement/monthly/summary yes yes
balance_sheet no yes
balance_sheet/summary no yes
balance_sheet/monthly no yes
balance_sheet/monthly/summary no yes
cash_flow_report no yes
cash_flow_report/summary no yes
cash_flow_report/monthly no yes
cash_flow_report/monthly/summary no yes

A partner key on one of the eight gets 403 ENDPOINT_NOT_AVAILABLE. Your URL is not wrong and your key is not broken — that operation is not served for your kind of key, and rotating the credential will not change it.

The narrowing is deliberate rather than incidental. A cash flow report descends to individual transactions and a balance sheet is an entity’s whole financial position; neither is needed to source revenue figures, which is what the partner integration exists to do. Versioning commits us to additive change within v1, so opening one of these to partner keys later costs nothing, while closing an already-published one would be impossible.

Key management is self-serve, from your Flychain partner dashboard or provider dashboard depending on which kind of key you hold. Either way you can issue a key, set its expiry, rotate it and revoke it yourself, without a request to us. The mechanics below are identical for both.

When you create a key you give it a label and an expiry, and you must choose the expiry explicitly — there is no default. A key that never expires is a legitimate choice for a service integration; it should be a decision rather than something that happens by omission.

The key value is shown exactly once, at the moment it is created. Store it in your secret manager then. It cannot be retrieved afterwards — if it is lost, issue a new one and revoke the old one.

You can hold more than one key at a time, which is what makes a clean rotation possible:

  1. Create the new key.
  2. Deploy it to every environment that calls this API.
  3. Confirm traffic is flowing on the new key.
  4. Revoke the old key.

There is no window in which neither key works, and no coordination with us. Do the same thing to retire a key you believe has been exposed — create, deploy, revoke — rather than revoking first and going dark in between.

Hold a distinct key for each environment that calls us. A development key can then be revoked on its own without touching production, and the labels tell you which is which when you come back to the dashboard months later.

Seven responses look similar and mean different things. Distinguish them, because retrying the wrong one wastes hours and giving up on another loses a day of data.

Status Code Applies to What it means What to do
400 INSECURE_TRANSPORT Both You called http:// instead of https://, so the key was sent in the clear. Rotate the key, then fix the URL. Retrying over HTTPS works, but the old key is exposed.
401 INVALID_API_KEY Both The key is missing, invalid, expired or revoked. Stop and fix the credential. Retrying will not help.
403 PARTNER_API_NOT_ENABLED Partner keys Your key is fine. Your organization is not enrolled in the API programme. Contact us to be enrolled. Do not rotate the key — a new one behaves identically.
403 PROVIDER_NOT_ACTIVE Provider keys Your key is fine. The provider’s Flychain account is not active — churned, paused, or still onboarding. Contact us. This is an account state, not an outage; see below.
403 PROVIDER_API_NOT_ENABLED Provider keys Your key is fine. The account is active but not enrolled in the API programme. Contact us to be enrolled. Do not rotate the key.
403 ENDPOINT_NOT_AVAILABLE Partner keys Your key and your URL are both fine. That operation is provider-key only — see the table above. Stop calling it. No credential change will open it.
503 AUTH_SERVICE_UNAVAILABLE Both We could not check your key. Our identity provider was unreachable or rate-limited. Retry with backoff. Your key is probably fine.

A 401 returns the same message whichever way the key failed — revoked, unknown, expired, or valid but on an organization that is neither a partner nor a provider. That is deliberate: the response cannot be used to learn which keys exist.

The four 403s are deliberately not folded into that 401. Every one of them means the credential itself is valid, so answering “invalid key” would send you off to rebuild an integration whose credential was never the problem.

PROVIDER_NOT_ACTIVE and PROVIDER_API_NOT_ENABLED are checked in that order, and the order carries information: if the account is not live, telling a provider to request access to the API programme would point them at the wrong problem entirely.

Both are read fresh on every request, with nothing cached. That means a change in either — an account moving out of active state, an enrollment being withdrawn — takes effect on the next call, not on a schedule. Existing keys are not revoked; they go inert while the condition holds and work again once it clears.

There is no separate sandbox, deliberately. Every endpoint is a read-only GET, so there is nothing an integration can do to affect our data, and testing against real books is more informative than testing against synthetic ones. Build and test against live credentials from the start.

Partners: we will nominate a specific entity for you to develop against and confirm it alongside your key.

Providers: you develop against your own books. GET /business_entities lists the entities your key reaches, and reporting_available tells you which of them a report can be produced for today — see Data semantics.