Authentication
The Betflow B2B API supports two authentication methods: API Key and OAuth2 Client Credentials. Your account is configured for one or both methods during onboarding.
Authentication Methods
Each account has an authentication method setting that determines which flows are available. This is configured by your administrator during onboarding.
| Auth Method | API Key (X-API-Key) | Bearer Token (Authorization: Bearer) | OAuth Login (/v1/oauth/login) | API Key Login (/v1/auth/login) |
|---|---|---|---|---|
api_key | ✅ | ✅ | ❌ | ✅ |
oauth | ❌ | ✅ | ✅ | ❌ |
both | ✅ | ✅ | ✅ | ✅ |
api_key— You can call the API directly with your API key in theX-API-Keyheader, or exchange it for a JWT token pair via/v1/auth/loginand use Bearer tokens. OAuth login is not available.oauth— You must use yourclient_idandclient_secretto obtain a JWT token pair via/v1/oauth/login, then call the API with Bearer tokens. Direct API key usage is not available.both— All authentication flows are available. You can use API keys directly, exchange them for tokens, or use OAuth client credentials.
To check which method your account uses, call GET /v1/account/config — the auth_method field shows your current setting. Attempting to use a flow that isn't enabled for your account will result in a 401 Unauthorized response.
API Key Authentication
The simplest way to authenticate. Send your API key with every request:
curl https://api.odditt.com/v1/references/sports \
-H "X-API-Key: YOUR_API_KEY"
You can also exchange your API key for a JWT token pair if you prefer token-based authentication:
curl -X POST https://api.odditt.com/v1/auth/login \
-H "X-API-Key: YOUR_API_KEY"
OAuth2 Client Credentials
For OAuth2 authentication, exchange your client_id and client_secret for a JWT token pair:
curl -X POST https://api.odditt.com/v1/oauth/login \
-H "Content-Type: application/json" \
-d '{
"client_id": "YOUR_CLIENT_ID",
"client_secret": "YOUR_CLIENT_SECRET"
}'
Response
Both login endpoints return the same token pair:
{
"access_token": "eyJhbGciOiJIUzI1NiIs...",
"refresh_token": "dGhpcyBpcyBhIHJlZnJl...",
"token_type": "Bearer",
"expires_at": "2026-03-17T16:15:00Z",
"expires_in": 900
}
| Field | Description |
|---|---|
access_token | JWT token to use in the Authorization header |
refresh_token | Opaque token used to obtain new access tokens |
token_type | Always Bearer |
expires_at | ISO 8601 timestamp of when the access token expires |
expires_in | Access token TTL in seconds |
Using Access Tokens
Once you have an access token, include it in the Authorization header:
curl https://api.odditt.com/v1/trends/mixed-flows \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{"sport_id": 1, "league_id": 7, "page": 1, "page_size": 10}'
Refreshing Tokens
Access tokens expire after the duration indicated in expires_in. Before or after expiry, use the refresh token to get a new token pair without re-sending your credentials.
API key flow:
curl -X POST https://api.odditt.com/v1/auth/refresh \
-H "Content-Type: application/json" \
-d '{"refresh_token": "YOUR_REFRESH_TOKEN"}'
OAuth flow:
curl -X POST https://api.odditt.com/v1/oauth/refresh \
-H "Content-Type: application/json" \
-d '{"refresh_token": "YOUR_REFRESH_TOKEN"}'
Refresh Token Rotation
The API uses refresh token rotation for security:
- Each refresh request returns a new refresh token.
- The old refresh token is immediately revoked.
- Always store and use the latest refresh token.
Login → access_token_1 + refresh_token_1
Refresh (refresh_token_1) → access_token_2 + refresh_token_2 (refresh_token_1 is now revoked)
Refresh (refresh_token_2) → access_token_3 + refresh_token_3 (refresh_token_2 is now revoked)
If you attempt to use an already-revoked refresh token, the request will fail with a 401 response. You will need to re-authenticate using your API key or client credentials.
JWT Claims
The access token is a standard JWT (HS256) containing:
| Claim | Description |
|---|---|
client_id | Your client identifier (UUID) |
tenant_id | Your tenant identifier (UUID) |
tier | Your account tier (free, pro, enterprise) |
iss | Token issuer |
sub | Subject (same as client_id) |
iat | Issued at timestamp |
exp | Expiration timestamp |
Recommended Flow
┌──────────────┐
│ Your App │
└──────┬───────┘
│
│ 1. POST /v1/oauth/login (or /v1/auth/login)
▼
┌──────────────┐
│ Betflow API │ → Returns access_token + refresh_token
└──────┬───────┘
│
│ 2. Use access_token for API calls
│ Authorization: Bearer <access_token>
▼
┌──────────────┐
│ Betflow API │ → Returns data
└──────┬───────┘
│
│ 3. When access_token expires:
│ POST /v1/oauth/refresh (or /v1/auth/refresh)
▼
┌──────────────┐
│ Betflow API │ → Returns NEW access_token + refresh_token
└──────────────┘
Best Practices
- Store tokens securely — never expose access tokens or refresh tokens in client-side code, URLs, or logs.
- Refresh proactively — refresh your access token before it expires to avoid failed requests. Use the
expires_inorexpires_atfield to schedule refreshes. - Handle 401 gracefully — if you receive a
401, attempt a token refresh. If the refresh also fails, re-authenticate with your credentials. - Use Bearer tokens in production — while API keys work on every request, using JWT tokens reduces how often your API key is sent over the wire.