Olik Split API
Programmatic expense splitting, balances, and settlements for your app. REST over HTTPS, JSON in and out.
The Olik Split API is in active development. Endpoints and auth may change before GA. Pin to the OpenAPI spec for the current contract — it is the source of truth and is regenerated on every deploy.
Quickstart
Three steps to your first response.
-
1 Get your secret key
Provision a secret key from your partner dashboard. It looks like
sk_live_...and authenticates the partner / management surface. Keep it server-side — never ship it in a client app. -
2 Make your first call
Check your account usage. A
200here confirms your key works.curl https://api.oliksplit.app/v1/usage \ -H "Authorization: Bearer sk_live_..."No key needed for the health check:
curl https://api.oliksplit.app/healthResponse:
{"status":"ok","version":"..."} -
3 Explore
Browse the endpoint reference below, or pull the machine-readable contract from openapi.yaml / openapi.json.
Authentication
Every request carries a bearer token in the Authorization header. There are two auth modes, and which one you use depends entirely on the path prefix.
1. Secret key
sk_live_...
Server-side only. Acts as you, the partner. Used for the management surface: creating groups, posting expenses on behalf of users, reading usage, configuring webhooks.
2. Session JWT
<jwt>
Scoped to a single end-user. Used for everything under /v1/data/*, so a user only ever sees their own groups, expenses, and balances.
Which key for which path
| Path prefix | Auth mode | Header |
|---|---|---|
| /v1/sessions/* | Secret key | Authorization: Bearer sk_live_... |
| /v1/groups, /v1/expenses, /v1/usage, /v1/webhook-endpoints, … | Secret key | Authorization: Bearer sk_live_... |
| /v1/data/* | Session JWT | Authorization: Bearer <jwt> |
Header format
Both modes use the same scheme — only the token value differs:
Authorization: Bearer <token>
Link token → session exchange
To act on behalf of one of your end-users, mint a session JWT for them:
- Using your secret key, create a session for the user via
POST /v1/sessions. This returns a short-lived link token. - Exchange that link token for a session JWT via
POST /v1/sessions/exchange. - Use the returned JWT as the bearer token for all
/v1/data/*calls. Refresh it before expiry withPOST /v1/sessions/refresh.
# 1. mint a session for an end-user (secret key)
curl -X POST https://api.oliksplit.app/v1/sessions \
-H "Authorization: Bearer sk_live_..." \
-H "Content-Type: application/json" \
-d '{"userId":"your-end-user-id"}'
# 2. exchange the returned link token for a session JWT
curl -X POST https://api.oliksplit.app/v1/sessions/exchange \
-H "Content-Type: application/json" \
-d '{"linkToken":"lt_..."}'
# 3. call the end-user surface with the JWT
curl https://api.oliksplit.app/v1/data/me \
-H "Authorization: Bearer <jwt>"
Core concepts
The data model, from the outside in.
- Customer (the partner)
- That's you — the company integrating Olik Split. Your secret key represents the Customer account. All groups, expenses, and end-users you create belong to your Customer.
- End-users
- The people inside your app. They can be full accounts or "ghost" users — participants you create with no signup, useful for someone who needs to be in a split but hasn't installed anything. Session JWTs are always scoped to one end-user.
- Groups
- A shared ledger between end-users — a trip, a household, a project. Every group carries a base currency and a member list. Expenses and balances live inside a group.
- Expenses
- A charge logged against a group: who paid, how much, in what currency, and how it splits across members (equal, exact amounts, shares, or a saved split preset).
- Balances
- The running net position of each member, derived from all expenses in the group: who owes whom and by how much, expressed in the group's base currency.
- Settlements
- Recorded payments that clear debt. The settle-up flow computes the minimal set of transfers to zero out balances; executing a settlement writes those transfers back to the ledger.
Endpoint reference
All paths are relative to https://api.oliksplit.app. The full contract — request/response schemas included — is in the OpenAPI spec.
Sessions secret key
| Method | Path | Description |
|---|---|---|
| POST | /v1/sessions | Mint a link token for an end-user. |
| POST | /v1/sessions/exchange | Exchange a link token for a session JWT. |
| POST | /v1/sessions/refresh | Refresh a session JWT before it expires. |
Partner surface secret key
| Method | Path | Description |
|---|---|---|
| GET | /v1/groups | List groups. |
| POST | /v1/groups | Create a group. |
| GET | /v1/groups/{id} | Retrieve a single group. |
| GET | /v1/groups/{id}/expenses | List expenses in a group. |
| GET | /v1/groups/{id}/balances | Current balances for a group. |
| GET | /v1/groups/{id}/settlements | List settlements for a group. |
| GET | /v1/expenses | List expenses across groups. |
| POST | /v1/expenses | Create an expense. |
| GET | /v1/expenses/{id} | Retrieve a single expense. |
| GET | /v1/budgets | List budgets. |
| POST | /v1/budgets | Create a budget. |
| GET | /v1/budgets/{id} | Retrieve a single budget. |
| GET | /v1/categories | List categories. |
| POST | /v1/categories | Create a category. |
| GET | /v1/categories/{id} | Retrieve a single category. |
| GET | /v1/recurring-expenses | List recurring expenses. |
| POST | /v1/recurring-expenses | Create a recurring expense. |
| GET | /v1/recurring-expenses/{id} | Retrieve a single recurring expense. |
End-user data surface session JWT
All paths under /v1/data/*. Scoped to the end-user the JWT was minted for.
| Method | Path | Description |
|---|---|---|
| GET | /v1/data/me | The current end-user's profile. |
| GET | /v1/data/groups | Groups the user belongs to. |
| GET | /v1/data/groups/{id} | A single group the user can see. |
| GET | /v1/data/groups/{id}/expenses | Expenses in a group. |
| GET | /v1/data/groups/{id}/balances | Balances in a group. |
| GET | /v1/data/groups/{id}/members | Members of a group. |
| GET | /v1/data/groups/{id}/settlements | Settlements in a group. |
| GET | /v1/data/groups/{id}/realtime | Realtime updates stream for a group. |
| GET | /v1/data/expenses | List the user's expenses. |
| GET | /v1/data/expenses/{id} | Retrieve a single expense. |
| GET | /v1/data/groups/{id}/settle-up | Compute the minimal settle-up plan. |
| POST | /v1/data/groups/{id}/settle-up/execute | Execute a settle-up plan. |
| GET | /v1/data/pairs | Pairwise balances with other users. |
| GET | /v1/data/pairs/{otherUserId} | Pairwise balance with one user. |
| GET | /v1/data/groups/{id}/split-presets | List a group's saved split presets. |
| GET | /v1/data/groups/{id}/split-presets/{presetId} | Retrieve a single split preset. |
| POST | /v1/data/groups/{id}/split-presets/{presetId}/use | Apply a split preset to a new expense. |
| POST | /v1/data/ocr/scan | Scan a receipt image into a draft expense. |
Usage & webhooks secret key
| Method | Path | Description |
|---|---|---|
| GET | /v1/usage | Usage and metering for your account. |
| GET | /v1/webhook-endpoints | List configured webhook endpoints. |
| POST | /v1/webhook-endpoints | Register a webhook endpoint. |
| GET | /v1/webhook-endpoints/{id} | Retrieve a single webhook endpoint. |
Utility no auth
| Method | Path | Description |
|---|---|---|
| GET | /health | Liveness check. Returns status and version. |
| GET | /openapi.yaml | OpenAPI spec (YAML). |
| GET | /openapi.json | OpenAPI spec (JSON). |
SDKs
The official Android / Kotlin Multiplatform SDK is in preview. It is not yet published to Maven Central — that's coming soon. Until then, integrate one of two ways:
1. Call REST directly
Every endpoint is plain HTTPS + JSON with a bearer token. Any HTTP client works — see the Quickstart.
2. Generate a typed client from the OpenAPI spec
Point any OpenAPI codegen at our spec. For a TypeScript client:
npx openapi-typescript https://api.oliksplit.app/openapi.json -o olik.ts
Errors
Errors use a uniform JSON envelope and standard HTTP status codes. Every response carries a requestId — quote it when contacting support.
{
"error": "...",
"message": "...",
"requestId": "..."
}
401 Unauthorized shapes
Auth failures are discriminated so you can tell why a request was rejected — by the error field:
error | Meaning |
|---|---|
| missing_authorization | No Authorization header was sent. |
| malformed_key | The header is present but not a valid Olik key / bearer format. |
| invalid_key | A well-formed key that is unknown or has been revoked. |
Example:
{
"error": "malformed_key",
"message": "Authorization header is not a valid API key.",
"requestId": "req_..."
}
Multi-currency
Each group carries a base currency. Expenses can be logged in any ISO-4217 currency — when an expense currency differs from the group's base currency, the conversion is handled server-side, and balances and settlements are always expressed in the group's base currency.
In short: log expenses in whatever currency they actually occurred in; Olik Split normalizes everything to the group base for you.