Clubtab API
Connect your own app or spreadsheet to your team’s money. The API reads and changes the same things as the Clubtab app, with the same rules.
Last updated 6 October 2026
The short version
- Make a token on your account page. Choose read only unless the app needs to record money.
- Every change takes an Idempotency-Key and a client_uuid, so sending it again gives back the first answer instead of doing it twice.
- Money is in whole pence. Each person can make 120 calls a minute.
Getting a token
Sign in to Clubtab and open your account. Under Connect an app, give the app or device a name and choose what it can do:
- Read only: See teams, statements, the inbox and cash. It can’t change anything. Choose this for a spreadsheet that reports on your money.
- Read and write: Also record cash, confirm matches and add receipts.
You see each token once, so copy it straight away. Treat it like a password: anyone with it can do what you chose. Your account lists your tokens, with what each can do and when it was last used. If one is lost or shared, remove it under Connect an app, and make a new one. It stops working at once.
A token can only reach the teams you can reach in the app, and do what your role allows there. A club treasurer can read a team’s squad but not record its cash, just as in the app.
Making a call
Every address starts with https://app.clubtab.co.uk/api/v1. Send the token as a bearer token, and ask for JSON:
GET https://app.clubtab.co.uk/api/v1/teams
Authorization: Bearer YOUR_TOKEN
Accept: application/json
Start with GET /me to check the token works, then GET /teams to find the ids of your teams.
Money, dates and ids
- Money is whole pence, as a number:
1000is £10.00. Money out is negative. When you send an amount, send pounds as text, like"10.00", just as you’d type it in the app. - Ids are ULIDs, like
01j9z3k8m6q2t4v7x0b5c8d1e2: 26 lower-case letters and digits. Send them as you got them. - Dates are
YYYY-MM-DD. - Field names in answers are camelCase, like
amountPence. Fields you send are snake_case, likeclient_uuid, as in the app’s forms.
Each answer is the same data the app shows on that page, so a field means the same thing in both.
Changing things safely
Anything that changes money (recording cash, confirming a match, adding a receipt) is a write, sent as a POST. Every write needs two things:
- an
Idempotency-Keyheader: a new UUID for each change you mean to make - a
client_uuidin the body: also a new UUID for each change. Most apps use the same UUID for both.
If a write times out, send it again with the same key, the same client_uuid and the same body. If the first one went through, you get its answer back, marked Idempotent-Replayed: true, and nothing is done twice. If it’s still being worked on, you get 409; wait a moment and send it again.
Use new UUIDs for each new change, even about the same thing, like each step of adding a receipt. Sending a key or client_uuid again with a different body, or to a different address, is refused with 422, so a mistake can’t replay another change’s answer.
Clubtab keeps the first answer for a day. After that, the client_uuid still stops money being recorded twice, but you may get an error rather than the first answer.
A read-only token gets 403 for any write.
When something goes wrong
Every answer that isn’t a success has a message to show or log.
| Status | What it means |
|---|---|
401 |
No token, or the token was deleted. |
403 |
The token can’t do this: it’s read only, your role doesn’t allow it, or your plan doesn’t include it. |
404 |
There’s nothing there that this token can see. |
409 |
The same change is still being worked on. Send it again shortly. |
422 |
Something sent needs fixing. errors says which field and why, in the words the app uses. |
428 |
A write without an Idempotency-Key or client_uuid, or one that isn’t a UUID. |
429 |
Too many calls. Wait a minute. |
Receipt photos
Photos never go through the API itself. To add one:
POST /teams/{team}/receipts/uploadswith the photo’sextension,typeandsize. You get back aurl, theheadersto send with it and apath.PUTthe photo to thaturl, with those headers, within 15 minutes.POST /teams/{team}/receiptswith thepath, and thetransaction_idof the payment out it’s for if you know it. You get back the receipt’sid.- Clubtab reads the photo in the background.
GET /teams/{team}/receipts/{id}shows what it read, and the payments out it could be for. POST /teams/{team}/receipts/{id}/confirmwith the supplier, total, date and payment out, once they’re right.
Receipts are on the Team and Club plans.
Limits
Each person can make 120 calls a minute, across all their tokens. Past that you get 429 until the minute is up. A spreadsheet that refreshes a few times an hour won’t come close.
What you can do
Addresses are under https://app.clubtab.co.uk/api/v1. {team}, {player} and the rest are ids.
You and your teams
| Call | What it does |
|---|---|
GET /me |
Who the token belongs to. |
GET /teams |
The teams you can see. |
GET /teams/{team}/setup |
What’s left to set up. |
GET /teams/{team}/squad |
The squad, with what each child owes. |
GET /teams/{team}/players/{player}/statement |
A child’s statement. |
The inbox
| Call | What it does |
|---|---|
GET /teams/{team}/inbox |
Payments waiting to be matched, with suggestions. |
POST /teams/{team}/inbox/{transaction}/confirm |
Confirm a suggested match. |
POST /teams/{team}/inbox/{transaction}/match |
Match a payment yourself, split across parts if you like. |
POST /teams/{team}/inbox/{transaction}/undo |
Undo a match. |
POST /teams/{team}/inbox/confirm-sure |
Confirm every sure match at once. |
Cash
| Call | What it does |
|---|---|
GET /teams/{team}/cash |
Cash in hand, what’s paid in, and the latest entries, as on the cash page. |
GET /teams/{team}/cash/training |
What cash at training can be for (pots and items, as for values) and the squad. |
GET /teams/{team}/cash/other |
The pots other cash can go to. |
POST /teams/{team}/players/{player}/cash |
Record cash for what a child owes. |
POST /teams/{team}/cash/training |
Record cash taken at training, for several children. |
POST /teams/{team}/cash/other |
Record a sponsor, donation or collection. |
POST /teams/{team}/cash/out |
Record cash spent. Add its receipt photo as a receipt. |
POST /teams/{team}/cash/bank |
Pay the cash in hand into the bank. |
POST /teams/{team}/cash/count |
Count up, with a note for any difference. |
POST /teams/{team}/cash/{transaction}/reverse |
Put a cash entry right, with a reason. |
When a write makes a single cash entry (cash for a child, other cash, cash out or a reversal), its answer names it in transactionId, so you can reverse it or add its receipt later. Cash at training makes one entry per child, and banking and counting don’t make a cash entry, so for those it’s empty.
Squad, charges and requests
| Call | What it does |
|---|---|
POST /teams/{team}/squad |
Add children. Anyone already in the squad is skipped. |
GET /teams/{team}/items |
What the team collects. |
POST /teams/{team}/items |
Save what the team collects, and charge the squad for the season so far. |
POST /teams/{team}/players/{player}/request |
Draft a payment request, with the parent’s link. |
POST /teams/{team}/players/{player}/charges/{charge}/let-off |
Let a family off a charge, with a reason. |
POST /teams/{team}/players/{player}/charges/{charge}/let-off/undo |
Make it owed again. |
Receipts
| Call | What it does |
|---|---|
GET /teams/{team}/receipts/new |
Start a receipt, for a payment out if you pass ?transaction=. |
POST /teams/{team}/receipts/uploads |
Get a link to send the photo straight to storage. |
POST /teams/{team}/receipts |
Add the uploaded photo by its path. |
GET /teams/{team}/receipts/{receipt} |
What was read, and the payments out it could be for. |
GET /teams/{team}/receipts/{receipt}/image |
The photo. |
POST /teams/{team}/receipts/{receipt}/confirm |
Attach it to the payment out. |
The full reference
The OpenAPI description lists every call with what it takes and what it answers, field by field. It’s built from the API itself, so its routes and fields always match. Some fields are needed only with others, like a sponsor’s name; if one is missing, the 422 says which. Most API tools can read it to make a client for you.
Something missing, or not working as this says? Email [email protected].