O Olik Split API Docs

Olik Split API

Programmatic expense splitting, balances, and settlements for your app. REST over HTTPS, JSON in and out.

Base URL: https://api.oliksplit.app Version prefix: /v1
Beta

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. 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. 2 Make your first call

    Check your account usage. A 200 here 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/health

    Response:

    {"status":"ok","version":"..."}
  3. 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:

  1. Using your secret key, create a session for the user via POST /v1/sessions. This returns a short-lived link token.
  2. Exchange that link token for a session JWT via POST /v1/sessions/exchange.
  3. Use the returned JWT as the bearer token for all /v1/data/* calls. Refresh it before expiry with POST /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

MethodPathDescription
POST/v1/sessionsMint a link token for an end-user.
POST/v1/sessions/exchangeExchange a link token for a session JWT.
POST/v1/sessions/refreshRefresh a session JWT before it expires.

Partner surface secret key

MethodPathDescription
GET/v1/groupsList groups.
POST/v1/groupsCreate a group.
GET/v1/groups/{id}Retrieve a single group.
GET/v1/groups/{id}/expensesList expenses in a group.
GET/v1/groups/{id}/balancesCurrent balances for a group.
GET/v1/groups/{id}/settlementsList settlements for a group.
GET/v1/expensesList expenses across groups.
POST/v1/expensesCreate an expense.
GET/v1/expenses/{id}Retrieve a single expense.
GET/v1/budgetsList budgets.
POST/v1/budgetsCreate a budget.
GET/v1/budgets/{id}Retrieve a single budget.
GET/v1/categoriesList categories.
POST/v1/categoriesCreate a category.
GET/v1/categories/{id}Retrieve a single category.
GET/v1/recurring-expensesList recurring expenses.
POST/v1/recurring-expensesCreate 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.

MethodPathDescription
GET/v1/data/meThe current end-user's profile.
GET/v1/data/groupsGroups the user belongs to.
GET/v1/data/groups/{id}A single group the user can see.
GET/v1/data/groups/{id}/expensesExpenses in a group.
GET/v1/data/groups/{id}/balancesBalances in a group.
GET/v1/data/groups/{id}/membersMembers of a group.
GET/v1/data/groups/{id}/settlementsSettlements in a group.
GET/v1/data/groups/{id}/realtimeRealtime updates stream for a group.
GET/v1/data/expensesList the user's expenses.
GET/v1/data/expenses/{id}Retrieve a single expense.
GET/v1/data/groups/{id}/settle-upCompute the minimal settle-up plan.
POST/v1/data/groups/{id}/settle-up/executeExecute a settle-up plan.
GET/v1/data/pairsPairwise balances with other users.
GET/v1/data/pairs/{otherUserId}Pairwise balance with one user.
GET/v1/data/groups/{id}/split-presetsList 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}/useApply a split preset to a new expense.
POST/v1/data/ocr/scanScan a receipt image into a draft expense.

Usage & webhooks secret key

MethodPathDescription
GET/v1/usageUsage and metering for your account.
GET/v1/webhook-endpointsList configured webhook endpoints.
POST/v1/webhook-endpointsRegister a webhook endpoint.
GET/v1/webhook-endpoints/{id}Retrieve a single webhook endpoint.

Utility no auth

MethodPathDescription
GET/healthLiveness check. Returns status and version.
GET/openapi.yamlOpenAPI spec (YAML).
GET/openapi.jsonOpenAPI 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:

errorMeaning
missing_authorizationNo Authorization header was sent.
malformed_keyThe header is present but not a valid Olik key / bearer format.
invalid_keyA 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.