Skip to main content
This page covers the two halves of access control:
  1. Getting a token — proving who you are with a username/password and receiving a JWT.
  2. Authorization — what that token lets you do, and which rules each endpoint is gated by.
Once you have a token, every subsequent request uses it as documented in Authentication.

Before you start

You need a partner account — an email + password issued by the Blackswan integration team. If you don’t have one yet, contact hello@bsa.ai. Accounts come with the admin role attached, which is what every partner-facing endpoint requires. Token issuance lives on a separate auth host from the main API: The same partner credentials are used to mint a token on the auth host, and the resulting JWT is presented as a Bearer token on the main API.

1. Obtain a token

Call GET /v1/auth/token with HTTP Basic authentication. The endpoint returns a signed JWT.

Headers

Most HTTP clients do this for you — curl -u email:password or requests.get(..., auth=(email, password)).

Example

Response

The header carries the kid of the key that signed it (so callers relying on JWKS verification get the right key), and the payload carries the standard claims:

Token lifetime

Tokens are valid for 365 days from issuance (exp - iat = 31_536_000). There’s no refresh endpoint — when expiry approaches, just call GET /v1/auth/token again with your Basic credentials.

Handling expiry

Pick whichever pattern fits your architecture; they’re not mutually exclusive.

Proactive — decode the exp claim

The cleanest approach if you cache the token. JWTs are header.payload.signature with each segment as base64url-encoded JSON. Decode the payload, read exp (unix seconds), refresh when the remaining lifetime drops below a threshold (e.g. 7 days).
You don’t need to verify the signature here — you’re just reading your own copy of the claim to decide whether to refresh. The API does the real verification on every call.

Reactive — catch 401, refresh, retry once

Simplest pattern. No JWT parsing required, just one extra round-trip when expiry actually hits.
Two caveats:
  • Don’t retry indefinitely — retry exactly once. If the second call also 401s, the credentials are wrong, not the token.
  • A 401 can also mean the token was revoked or your account was disabled — same handler still works (you’ll get 401 again on retry, and surface it).

Scheduled rotation

For machine-to-machine integrations where you already have the Basic credentials stored, the simplest possible setup is a cron that refreshes weekly or monthly. No expiry math, no retry logic — just a fresh token always ready.
Your app reads /var/lib/bsa/token (or whatever store you use) on every request. The cron ensures it’s never within 7 days of expiry.

Knowing when expiry is coming

If you operate the integration yourself rather than via cron, set a calendar reminder for ~11 months after each token issuance. The iat claim in the JWT payload gives you the exact issuance timestamp to anchor on.

Errors

2. How authorization works

Every partner-facing endpoint enforces:
  1. Authentication — a valid, unexpired JWT in the Authorization header. Failure: 401 unauthenticated.
  2. Authorization — the JWT must contain the ADMIN role. Failure: 401 unauthenticated (the API does not distinguish “not authenticated” from “not authorized” on the wire — both map to 401).
All partner-facing endpoints (/v1/customers/..., /v1/loans/..., /v1/repayments/..., /v1/loan-products/..., /v1/credit-decisions/...) require the ADMIN role.

3. Use the token

Set the Authorization header on every request:
For the per-call mechanics — headers, expiry handling, common 401 causes — see Authentication.

Putting it together