Developer API
Personal access tokens let you script TailSpend for your own account: read your groups and members, and list, read, create, update and delete expenses. OAuth (apps acting for other people) is not supported yet.
- Base URL:
https://developer-api.tailspend.kinesis.studio/v1(beta:https://developer-api.beta.tailspend.kinesis.studio/v1) - Guide: the public getting-started guide is the root of the API docs site (
https://docs.tailspend.kinesis.studio/), generated frompackages/openapi/src/docs-site.ts; the interactive reference isdeveloper-reference.htmlon the same site. - Contract:
developer-openapi.jsonon the API docs site. Bodies, errors and pagination are identical to the app API.
Tokens
Create tokens in the web or desktop app under Profile → Developer access. Each token has:
- a name;
- groups: one or more of your groups (a token sees nothing else);
- scopes:
groups:read: list the token's groups, read a group and its participants;expenses:read: list and read expenses;expenses:create,expenses:update,expenses:delete: each write is a separate permission;
- an expiry of between 1 and 365 days.
The secret (tsp_<tokenId>_<secret>) is shown once; TailSpend stores only its SHA-256 hash and cannot show it again. If you lose it, rotate the token: you get a new secret with the same settings and the old one stops working immediately. Revoking is also immediate. You can hold up to 10 active tokens.
A token never gives you more than your own account has. Each request must satisfy both the token's scopes and groups and your current role in the group. If you leave a group or are demoted, your tokens lose that access on the next request.
Keep tokens server-side. Never ship one in a browser or mobile app.
curl -H "Authorization: Bearer $TAILSPEND_TOKEN" \
https://developer-api.tailspend.kinesis.studio/v1/users/me/groups
Operations
| Operation | Scope |
|---|---|
GET /users/me/groups |
groups:read (only the token's groups are listed) |
GET /groups/{groupId} |
groups:read |
GET /groups/{groupId}/participants |
groups:read |
GET /groups/{groupId}/expenses |
expenses:read |
GET /groups/{groupId}/expenses/{expenseId} |
expenses:read |
POST /groups/{groupId}/expenses |
expenses:create |
PATCH /groups/{groupId}/expenses/{expenseId} |
expenses:update |
DELETE /groups/{groupId}/expenses/{expenseId} |
expenses:delete |
Anything else (account, admin, scans, invites, participant management, token management) returns 404.
Idempotent Creates
POST /groups/{groupId}/expenses requires an Idempotency-Key header: 1–255 printable ASCII characters, unique per logical expense. Reuse the same key when retrying:
- The same key and the same body return the original expense (
201) withIdempotent-Replayed: true. Concurrent retries never create duplicates. - The same key with a different body or group returns
422. - A completed key whose expense was since deleted returns
409. - Keys are remembered for 24 hours.
Updates use the expense's version (optimistic concurrency): send the version you read; a stale one returns 409, so re-read and retry.
Limits
| Allowance | Default |
|---|---|
| Per user, across all your tokens | 60 weighted units per minute |
| Per token | 30 weighted units per minute |
| Expense creates | 500 per user per UTC day |
| Request body | 64 KiB |
Most operations cost 1 unit; GET /users/me/groups costs 10. Developer traffic has its own allowance, so a busy integration never slows down your use of the app.
Exceeding a limit returns 429, with a Retry-After header in seconds when the limit resets (per-minute and daily allowances). Wait at least that long, then back off exponentially with jitter if you are limited again. These allowances are initial values and may be tuned.
Usage
Profile → Developer access shows your requests today and this month, a daily table, per-token totals, status classes and rate-limit rejections, all by UTC day for the last 90 days. App usage is shown separately.
The counts are approximate and informational, not billing records:
- only authenticated requests that reached the API are counted;
- requests rejected before then (an invalid token, gateway throttling) are not;
- a retried counter write can occasionally overcount.