Skip to content
Home » Clubtreasurer Membership API — Developer Guide (v0.1)

Clubtreasurer Membership API — Developer Guide (v0.1)

The Clubtreasurer Membership API lets you display and manage your club’s membership and billing data on your own website or application — member lists, membership details, invoices and balances — always live, straight from your Clubtreasurer account.

What you can do:

  • List and search your members
  • Read full member details, including parent/guardian and emergency contacts
  • Update a member’s contact details or section
  • List your membership types and each member’s membership assignments
  • List invoices and balances, for one member or your whole organisation

What you’ll need:

  • API credentials (a Client ID and Client Secret) — generated by your organisation’s Primary Contact inside Clubtreasurer (see Getting your credentials below)
  • A server-side environment to call the API from (PHP, Node.js, Python, .NET, etc.)

⚠️ Your Client Secret is a password for your club’s data. Never put it in website JavaScript, mobile apps, or anything else that runs on your users’ devices — anyone could read it there. All API calls should be made from your own server. If you believe your secret has been exposed, your Primary Contact should use Regenerate in the REST API tab immediately (or contact support).

🔒 Early Access Programme
The REST API is currently available as an early access preview to a limited number of organisations. If your organisation doesn’t yet have access, please open a support ticket requesting to join the Early Access Programme, with “REST API Early Access” in the subject line. Once you’re onboarded, everything below is fully self-service — no further waiting on us.

Getting your credentials

Once your organisation has early access, credentials are self-service and managed inside Clubtreasurer by your organisation’s Primary Contact (other users will not see this option):

  1. Log in to Clubtreasurer as the Primary Contact
  2. Go to Membership → Membership Setup and open the REST API tab
  3. Click Generate API Credentials
  4. Copy the Client Secret immediately — for security it is shown only once. If you lose it, generate a new pair with Regenerate

About your Client ID: Client IDs are 24 characters and end in two dots (..). This is not a display error or truncation — the dots are part of the credential and must be included. The Client Secret is shown only once, when generated; if you lose it you must regenerate, which immediately invalidates the previous pair.

From the same tab the Primary Contact can also:

  • Regenerate — issues a new Client ID and Secret and immediately invalidates the old pair (any integration using them stops working until updated)
  • Revoke Access — disables API access for your organisation entirely, effective immediately

If you can’t see the REST API tab or need help, contact support@clubtreasurer.com.

Base URL

All API requests use this base URL:

https://myclubtreasurer.com/apex/prod/api/v1

All requests must use HTTPS. All responses are JSON.

Step 1 — Get an access token

The API uses the industry-standard OAuth 2.0 Client Credentials flow. You exchange your Client ID and Secret for a short-lived access token, then send that token with every API call.

POST https://myclubtreasurer.com/apex/prod/oauth/token
Content-Type: application/x-www-form-urlencoded

grant_type=client_credentials

Authenticate the request with HTTP Basic auth — username = Client ID, password = Client Secret.

curl example:

curl -s -X POST "https://myclubtreasurer.com/apex/prod/oauth/token" \
  -u "YOUR_CLIENT_ID:YOUR_CLIENT_SECRET" \
  -d "grant_type=client_credentials"

Response:

{
  "access_token": "cfd8avMuKwcwjFNrCF-lyQ",
  "token_type": "bearer",
  "expires_in": 3600
}

Tokens are valid for 1 hour (expires_in is in seconds). Cache the token and reuse it until it expires, then request a new one — do not request a new token for every API call.

Step 2 — Call the API

Send the token in the Authorization header of every request:

curl -s -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  "https://myclubtreasurer.com/apex/prod/api/v1/members/"

Node.js example (token + first call):

const BASE = "https://myclubtreasurer.com/apex/prod/api/v1";
const TOKEN_URL = "https://myclubtreasurer.com/apex/prod/oauth/token";

async function getToken(clientId, clientSecret) {
  const res = await fetch(TOKEN_URL, {
    method: "POST",
    headers: {
      "Content-Type": "application/x-www-form-urlencoded",
      "Authorization": "Basic " + Buffer.from(`${clientId}:${clientSecret}`).toString("base64"),
    },
    body: "grant_type=client_credentials",
  });
  if (!res.ok) throw new Error(`Token request failed: ${res.status}`);
  return (await res.json()).access_token;   // cache this for up to 1 hour
}

async function listMembers(token) {
  const res = await fetch(`${BASE}/members/?status=Active`, {
    headers: { Authorization: `Bearer ${token}` },
  });
  if (!res.ok) throw new Error(`API call failed: ${res.status}`);
  return (await res.json()).items;
}

Pagination

List endpoints return up to 50 records per page. Page through results with ?offset= and ?limit=:

GET /members/?offset=0&limit=50     → records 1–50
GET /members/?offset=50&limit=50    → records 51–100

Every list response includes "hasMore": true/false — keep increasing offset until hasMore is false. The response also includes ready-made first/next links in the links array.

Response envelope (all list endpoints):

{
  "items": [ { ... }, { ... } ],
  "hasMore": true,
  "limit": 50,
  "offset": 0,
  "count": 50,
  "links": [ ... ]
}

Endpoints

All dates are returned as YYYY-MM-DD strings. Field names in responses are lower-case.

List members

GET /members/

Optional filters: ?status="Active" / "Inactive" / "Deleted” (member status) · ?section = <section_name> (member section)

Each item: id, ref_id, first_name, last_name, email, telephone_num1, section_id, section_name, mem_status, gender, dob, join_date.

Get one member (full detail)

GET /members/{id}

Returns everything from the list plus: email2, telephone_num2, telephone_num3, address fields (address1address3, addresstown, addresscounty, addresspostcode, addresscountry), gift_aid, and contact records — parent/guardian 1 (pc1_first_name, pc1_last_name, pc1_email1, pc1_phone1), parent/guardian 2 (pc2_...), and emergency contact (emc_first_name, emc_last_name, emc_phone1).

section_name is included here too; it is null for members not assigned to a section.

Returns 404 if the member does not exist in your organisation.

Update a member

PUT /members/{id}
Content-Type: application/json

Partial update — only the fields you include in the JSON body are changed; everything else is left untouched. Updatable fields (camelCase or snake_case both accepted):

email, email2, telephoneNum1, telephoneNum2, telephoneNum3, address1, address2, address3, addressTown, addressCounty, addressPostcode, addressCountry, sectionId

curl -s -X PUT \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"email": "new.address@example.com", "telephoneNum1": "07700 900123"}' \
  "https://myclubtreasurer.com/apex/prod/api/v1/members/420"

Responses: 200 updated · 404 member not found in your organisation (nothing changed) · 401 credentials no longer valid.

List membership types

GET /memberships/

Your organisation’s membership types. Each item: id, mem_name, mem_ref, mem_desc, billing_cycle, status.

A member’s membership assignments

GET /members/{id}/memberships

Required filter: Member ID for {id}

Current (non-archived) membership assignments, newest first. Each item: id, mem_map_name, mem_name, status, start_date, earliest_end_date, cancellation_date, billing_cycle, payment_term.

A member’s invoices

GET /members/{id}/billing

Required filter: Member ID for {id}

Optional filters: ?status= (invoice status) · ?date_from=2026-01-01 · ?date_to=2026-12-31 (invoice date range)

Each item: id, mem_map_id, mem_map_name, bill_from_date, bill_to_date, journal_date, due_amt, t_paid_amt, balance, inv_status, comments.

All invoices for your organisation

GET /billing/

Optional filters: ?member_id= · ?status= · ?date_from= · ?date_to=

Each item adds the member’s identity: member_id, first_name, last_name, ref_id.

Get one invoice (full detail)

GET /billing/{id}

Required filter: Invoice ID for {id}

Adds original_amt, mem_name, billing_cycle to the list fields. Returns 404 if the invoice is not in your organisation.

Status codes & error handling

CodeMeaningWhat to do
200Success
401Missing/expired/invalid token, or your API access has been revokedRequest a new token; if it persists, check with your Primary Contact whether credentials were regenerated or revoked
404Record doesn’t exist in your organisationCheck the ID; you can never read another club’s data
500 / 555Unexpected server error (e.g. malformed request)Check your request format; contact support if it persists

Your credentials are scoped to your organisation only — every request returns your club’s data and nothing else.

Good-practice checklist

  • ✅ Call the API from your server, never from browser/mobile code
  • ✅ Store the Client Secret in server configuration (environment variable / secrets store), not in source code
  • ✅ Cache the access token and reuse it for its 1-hour lifetime
  • ✅ Handle 401 by fetching a fresh token once, then failing gracefully
  • ✅ Use the filters (status, date_from, …) rather than downloading everything and filtering locally
  • ✅ Cache responses on your side where freshness allows (e.g. member lists for a few minutes)

Support

  • Credentials, questions, problems: support@clubtreasurer.com
  • Please include the approximate time of any failing request and the HTTP status code you received (never send us your Client Secret).

Version

VersionDateNotes
v1July 2026First release: members (read/update), memberships, billing (read)
v1.117 July 2026Added section_name to member list and member detail responses
v1.222 July 2026Self-service credentials via Membership Setup → REST API tab (Primary Contact only); Early Access Programme note added