Skip to main content
This page covers the two halves of access control:
  1. Getting a token — proving who you are with your partner email and 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: Your email and password are used in exactly one place: to mint a token on the auth host. The resulting JWT is what you present, as a Bearer token, on the main API. The main API never accepts the email and password themselves — a request to https://api-staging.bsa.ai that carries them instead of a token is rejected with 401 unauthenticated.

1. Obtain a token

Call GET /v1/auth/token on the auth host with your partner email and password. The endpoint returns a signed JWT. This is the only way to obtain a token; there is no other issuance endpoint and no API key.

Credentials

Pass the email and password as the request’s user and password — every HTTP client has a built-in way to do this: curl -u email:password, requests.get(..., auth=(email, password)), and so on. You do not build any header yourself.

Example

Response

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 email and password.

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 email and password 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: 403 permission_denied with sub_code: insufficient_role. A 403 is never fixed by refreshing the token — the account needs the role.
All partner-facing endpoints (/v1/customers/..., /v1/loans/... including the repayment routes under a loan, /v1/loan-products/..., /v1/credit-scorecard/..., /v1/credit-boost) require the ADMIN role. User management (/v1/users) is reserved for the SUPER_ADMIN role and is not part of the partner surface.

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