Authentication
All endpoints require the X-API-Key header unless marked as public.
Header: X-API-Key: your-api-key
Core
Platform health, organisations, activities, and user management.
Returns service status. Use to verify the API is running.
Returns all organisations registered on the platform with name, subdomain, and branding.
Returns app instances (activities) for organisations. Each activity links an app to an organisation.
| Parameter | Type | Required | Description |
|---|
org | string | No | Filter by organisation subdomain |
Check if a Django user account exists for the given email address.
| Parameter | Type | Required | Description |
|---|
email | string | Yes | Email address to look up |
Members
Member directory and verification for SSO-protected content.
| Parameter | Type | Required | Description |
|---|
email | string | Yes | |
Per-org API key + member email. Returns a name + organisation
envelope plus a `tiles` list. Tiles are server-side and
registered per-app via a `dashboard_tile.py` module — when a
new app ships its tile appears automatically without WP plugin
changes. Tiles auto-skip when a count is zero (so a tenant
without breakfast events doesn't see a breakfast tile).
| Parameter | Type | Required | Description |
|---|
email | string | Yes | |
| Parameter | Type | Required | Description |
|---|
club | string | Yes | Club name |
| Parameter | Type | Required | Description |
|---|
email | string | Yes | |
Trust model: per-org API key is admin-tier trust. Calling shortcode
([member_dietary] in the Members WP plugin) gates on access_role
in (admin, global_admin) before requesting. Returns name + dietary
+ partner name + partner_dietary + has_any_dietary boolean per row.
| Parameter | Type | Required | Description |
|---|
member_id | integer | Yes | |
Returns all active members with name, email, mobile, member type, access role, and organisation.
Checks if an email belongs to an active member. Used by WordPress plugins to gate content behind Google SSO.
| Parameter | Type | Required | Description |
|---|
email | string | Yes | Email address to verify |
App Store
| Parameter | Type | Required | Description |
|---|
club | string | No | |
Authentication
Social sign-in flows for mobile apps and WordPress plugins. Google and Apple are supported; Facebook is planned.
Exchange a Google ID token (from native Google Sign-In) for an opaque bearer session token. The token is returned alongside the member's profile and organisation.
| Parameter | Type | Required | Description |
|---|
id_token | string | Yes | Google ID token from the mobile SDK |
Exchange an Apple identity token (from ASAuthorizationAppleIDCredential) for a bearer session token. Audience must match the app's bundle ID.
| Parameter | Type | Required | Description |
|---|
identity_token | string | Yes | Apple identity token JWT from the iOS SDK |
first_name | string | No | First name (Apple only provides this on first sign-in) |
last_name | string | No | Last name (Apple only provides this on first sign-in) |
Redirects the browser to Apple's authorize URL. Used by WordPress plugins to initiate Sign in with Apple. Apple POSTs back to the callback endpoint.
| Parameter | Type | Required | Description |
|---|
return_to | string | Yes | HTTPS URL to redirect back to after Apple auth (e.g. the WP callback page) |
Receives Apple's form_post callback with an authorization code + state. Exchanges the code for tokens, verifies the ID token, finds the member, and redirects back to the return_to URL with a signed payload (ok, email, expires, sig). If the member is not found, ok=false and apple_sub is included for linking.
| Parameter | Type | Required | Description |
|---|
code | string | Yes | Authorization code from Apple (form-posted) |
state | string | Yes | HMAC-signed state containing the return URL (form-posted) |
For Hide-My-Email Apple users whose relay email doesn't match a membership. Sends a verification email to the provided club email. The email contains a signed link that binds the Apple subject to the membership.
| Parameter | Type | Required | Description |
|---|
apple_sub | string | Yes | Apple subject identifier from the failed sign-in |
email | string | Yes | The member's club email address |
return_to | string | Yes | HTTPS URL to redirect to after verification |
Consumes a signed link token from email, binds apple_subject to the membership, and redirects back to the WP site with ok=true.
| Parameter | Type | Required | Description |
|---|
token | string | Yes | HMAC-signed link token from the verification email |
return_to | string | Yes | HTTPS URL to redirect to after successful linking |
Activities
| Parameter | Type | Required | Description |
|---|
club | string | No | |
app | string | No | |
Notices
Organisation announcements and events with date-ranged visibility.
| Parameter | Type | Required | Description |
|---|
club_slug | string | Yes | |
| Parameter | Type | Required | Description |
|---|
club_slug | string | Yes | |
activity_id | integer | Yes | |
Returns notices currently within their visibility window. Includes title, description, event date/time, price, contact details, and access level.
Returns a QR code PNG image encoding the notice's website URL.
| Parameter | Type | Required | Description |
|---|
id | integer | Yes | Notice ID |
Breakfast
Breakfast meeting RSVP system with choice selection, guest bookings, and reports.
| Parameter | Type | Required | Description |
|---|
club_slug | string | Yes | |
activity_id | integer | Yes | |
Returns the next upcoming breakfast event with title, date, time, and location.
Submit a breakfast choice for an event. Validates the choice code.
| Parameter | Type | Required | Description |
|---|
event_id | integer | Yes | Breakfast event ID |
email | string | Yes | Member email |
breakfast_choice | string | Yes | Choice code: full, continental, bacon, none, apology |
Returns the current breakfast activity for the organisation, including deadline and the member's latest choice.
| Parameter | Type | Required | Description |
|---|
org_slug | string | Yes | Organisation subdomain |
email | string | Yes | Member email |
Submit or change a breakfast choice. Validates deadline, normalises choice codes, supports guest bookings.
| Parameter | Type | Required | Description |
|---|
org_slug | string | Yes | Organisation subdomain |
activity_id | integer | Yes | Activity ID |
email | string | Yes | Member email |
breakfast_choice | string | Yes | Choice code |
bringing_guest | boolean | No | Set to true if bringing a guest |
guest_first_name | string | No | Guest first name |
guest_last_name | string | No | Guest last name |
guest_breakfast_choice | string | No | Guest choice code |
Full attendance report listing all members with their choices and summary totals.
| Parameter | Type | Required | Description |
|---|
org_slug | string | Yes | Organisation subdomain |
activity_id | integer | Yes | Activity ID |
Groups & Positions
Member groups (committees, teams), organisational positions (President, Secretary), and year-scoped assignments. Used for access control, leadership displays, and committee listings.
Returns all active member groups for the organisation.
Returns members of a group for a given year, including ongoing (year-less) memberships. Includes role_label for each member.
| Parameter | Type | Required | Description |
|---|
id | integer | Yes | Group ID |
year | string | No | OrgYear label (e.g. '2025-26') or 'current' (default) |
Returns group members enriched with their position assignments. Members are derived from both explicit MemberGroupMembership and PositionAssignments where the position is scoped to this group. Sorted by position display_order. Also returns all OrgYears for a year picker.
| Parameter | Type | Required | Description |
|---|
id | integer | Yes | Group ID |
year | string | No | OrgYear label or 'current' (default) |
Returns every active group for the organisation, each with its members and positions for the given year. Groups sorted by display_order; members within each group sorted by position display_order then last name. Designed for committee overview pages.
| Parameter | Type | Required | Description |
|---|
year | string | No | OrgYear label or 'current' (default) |
org | integer | No | Organisation ID (required when using the global API key) |
Returns all positions for the organisation with their current holders. Designed for 'Meet the Team' displays. Positions are ordered by display_order.
| Parameter | Type | Required | Description |
|---|
year | string | No | OrgYear label or 'current' (default) |
Library
| Parameter | Type | Required | Description |
|---|
email | string | Yes | |
folder_id | integer | No | Omit for root |
| Parameter | Type | Required | Description |
|---|
doc_id | integer | Yes | |
email | string | Yes | |
| Parameter | Type | Required | Description |
|---|
doc_id | integer | Yes | |
email | string | Yes | |
Same auth + access-control gates as /download/ but returns the signed
URL as JSON instead of 302-redirecting to it. The WP in-browser viewer
(Office Online + native browser PDF viewer) needs a URL that can be
fetched anonymously by Microsoft's servers / the browser itself —
admin-ajax proxied URLs require an `sts_session` cookie that those
clients don't have. Logs an opened_editor event distinct from downloaded.
| Parameter | Type | Required | Description |
|---|
doc_id | integer | Yes | |
email | string | Yes | |
| Parameter | Type | Required | Description |
|---|
doc_id | integer | Yes | |
email | string | No | |
note | string | No | |
days | integer | No | |
| Parameter | Type | Required | Description |
|---|
doc_id | integer | Yes | |
| Parameter | Type | Required | Description |
|---|
doc_id | integer | Yes | |
| Parameter | Type | Required | Description |
|---|
email | string | Yes | |
name | string | Yes | |
parent_id | integer | No | Omit or 0 for root |
restricted_to_group_id | integer | No | Optional MemberGroup id (folder + children visible only to that group) |
| Parameter | Type | Required | Description |
|---|
doc_id | integer | Yes | |
| Parameter | Type | Required | Description |
|---|
doc_id | integer | Yes | |
| Parameter | Type | Required | Description |
|---|
email | string | Yes | |
days | integer | No | |
Furniture Project
| Parameter | Type | Required | Description |
|---|
status | string | No | |
| Parameter | Type | Required | Description |
|---|
org | integer | No | |
category | string | No | |
q | string | No | |
status | string | No | |
limit | integer | No | |
offset | integer | No | |
| Parameter | Type | Required | Description |
|---|
item_id | integer | Yes | |
| Parameter | Type | Required | Description |
|---|
q | string | No | |
Calendar
ICS calendar feed integration for club/organisation calendars.
Fetches and parses the ICS feed configured for the given activity. Returns events with name, start, end, location, description, and access level.
| Parameter | Type | Required | Description |
|---|
activity_id | integer | Yes | Activity ID with calendar config |
Borrowers
Per-org API key + `email` of the calling member. Returns every
request for the tenant including matched + cancelled, with
per-viewer flags (is_requester / is_lender / can_match /
can_cancel) so the WP table renders the right buttons.
| Parameter | Type | Required | Description |
|---|
email | string | Yes | |
| Parameter | Type | Required | Description |
|---|
email | string | Yes | Calling member's email. |
item_name | string | Yes | |
description | string | Yes | |
start_at | string | Yes | |
end_at | string | Yes | |
| Parameter | Type | Required | Description |
|---|
request_id | integer | Yes | |
email | string | Yes | |
| Parameter | Type | Required | Description |
|---|
request_id | integer | Yes | |
email | string | Yes | |
comments | string | No | Optional note to the requester. |
Recycle
Per-org API key + `email` of the calling member. Recipient
privacy: non-donor viewers only see their OWN application on
each listing (not the full applicant list); donors see them all.
| Parameter | Type | Required | Description |
|---|
email | string | Yes | |
Approving auto-rejects every other PENDING application on the
same listing and flips the listing to `promised`.
| Parameter | Type | Required | Description |
|---|
application_id | integer | Yes | |
email | string | Yes | |
action | string | Yes | |
Multipart/form-data ONLY (the photo is a file upload).
Required fields: item_name, description, photo, email.
| Parameter | Type | Required | Description |
|---|
listing_id | integer | Yes | |
email | string | Yes | |
message | string | No | Optional pitch from the recipient. |
| Parameter | Type | Required | Description |
|---|
listing_id | integer | Yes | |
email | string | Yes | |
Courses
Video course delivery with drip-feed, completion tracking, and PDF certificates.
| Parameter | Type | Required | Description |
|---|
email | string | No | Optional — adds enrolment status to each course |
| Parameter | Type | Required | Description |
|---|
slug | string | Yes | |
email | string | No | |
| Parameter | Type | Required | Description |
|---|
slug | string | Yes | |
email | string | No | |
| Parameter | Type | Required | Description |
|---|
slug | string | Yes | |
lesson_id | integer | Yes | |
email | string | No | |
| Parameter | Type | Required | Description |
|---|
slug | string | Yes | |
email | string | Yes | |
Events
Organisation events with maps, QR codes, and per-event access control.
Returns published events with date, time, location, description, website, QR code URL, and access level.
| Parameter | Type | Required | Description |
|---|
org | string | No | Filter by organisation subdomain |
upcoming | boolean | No | Set to 'true' to show only future events |
Returns a QR code PNG image encoding the event's website URL.
| Parameter | Type | Required | Description |
|---|
id | integer | Yes | Event ID |
Vouchers
Per-org API key required (X-API-Key). Pure read — does NOT
increment the redemption counter; that happens in the feature's
webhook AFTER payment. Returns the discount + final amount when
valid; otherwise {valid:false, error:...} with HTTP 200 (so the
WP form can render the error inline rather than treat it as a
network failure).
| Parameter | Type | Required | Description |
|---|
code | string | Yes | Customer-facing voucher code, case-insensitive. |
scope_type | string | Yes | Which feature is this voucher being applied to. |
scope_id | string | Yes | Feature-specific identifier — course slug, duck-race id, splat-game id. |
base_amount_minor | integer | Yes | Cart total in minor units (pence) BEFORE discount. |
currency | string | Yes | Three-letter ISO code, lowercase. |
Duck Race
Duck race fundraiser — buy a numbered duck, share the prize pot.
| Parameter | Type | Required | Description |
|---|
race_id | integer | Yes | |
| Parameter | Type | Required | Description |
|---|
race_id | integer | Yes | |
number | integer | No | |
buyer_name | string | No | |
buyer_email | string | No | |
buyer_phone | string | No | |
success_url | string | No | |
cancel_url | string | No | |
| Parameter | Type | Required | Description |
|---|
race_id | integer | Yes | |
Splat Game
| Parameter | Type | Required | Description |
|---|
activity_id | integer | Yes | |
| Parameter | Type | Required | Description |
|---|
activity_id | integer | Yes | |
Compliance (DSAR + Privacy + Cookies)
PUBLIC — no API key. The banner runs in unauthenticated browsers,
so it can't carry one. We hash the IP (sha256, salted) for dedupe
only — no raw IP stored. 60-second dedupe per (org, ip_hash, action)
prevents page-spam from filling the table. Always returns 200 with
{"ok": true} unless org/action are invalid.
| Parameter | Type | Required | Description |
|---|
org | string | Yes | Organisation subdomain |
action | string | Yes | |
categories | array | No | |
page_url | string | No | |
notice_version | string | No | The cookies-notice last_published_at value the visitor saw. |
PUBLIC — no API key. Visitors must be able to read this BEFORE
any non-essential cookies are set, so authentication isn't possible.
Cache-Control: public, max-age=300. Returns inline HTML + signed
PDF URL + structured `categories` list (the WP banner JS reads
`categories` to build the customise UI).
| Parameter | Type | Required | Description |
|---|
org | string | Yes | Organisation subdomain. |
Caller must attest DPO role server-side; the WP plugin enforces
access_role in (admin, global_admin) and DPO group membership.
| Parameter | Type | Required | Description |
|---|
state | string | No | open (default) | all | <status slug> |
Creates a DSAR. If `attest_fresh_sso` is true and the caller is
using a per-org or global API key (server-side proxy attests the
requester is a signed-in member), identity is recorded immediately
as `fresh_sso` and the 30-day statutory clock starts. Otherwise
a magic-link email is sent if `verify_url` is provided.
| Parameter | Type | Required | Description |
|---|
email | string | Yes | |
request_type | string | No | |
notes | string | No | |
verify_url | string | No | |
attest_fresh_sso | boolean | No | |
sso_provider | string | No | |
UK ICO permits a "reasonable fee" only for manifestly excessive
repeat requests. First request per email per 12-month window is
always free; second-or-later auto-flagged with fee_required=True.
Pays to Investcope's central Stripe account (no Connect destination
charge — the platform does the technical work).
| Parameter | Type | Required | Description |
|---|
dsar_id | integer | Yes | |
success_url | string | Yes | |
cancel_url | string | Yes | |
| Parameter | Type | Required | Description |
|---|
dsar_id | integer | Yes | |
email | string | Yes | |
| Parameter | Type | Required | Description |
|---|
dsar_id | integer | Yes | |
token | string | Yes | |
last_name | string | Yes | |
postcode | string | Yes | |
PUBLIC — no API key. UK GDPR Art. 12-14 require the privacy
notice to be readily accessible BEFORE any data is collected,
so authentication is by design absent. Cache-Control: public,
max-age=300. Returns the inline HTML + a 1-hour signed PDF URL.
| Parameter | Type | Required | Description |
|---|
org | string | Yes | Organisation subdomain. |
Statistics
| Parameter | Type | Required | Description |
|---|
days | integer | No | |
Charities & Funders
Directory of charities and grant funders, filterable by UK county.
Returns charities with Charity Commission data, income, contact details, areas served, and tags.
| Parameter | Type | Required | Description |
|---|
county | string | No | UK county code (e.g. bedfordshire) |
org | string | No | Filter by organisation subdomain |
tag | string | No | Filter by tag (e.g. homelessness) |
search | string | No | Search name, description, and address |
Returns grant funders with type, geographic focus, grant range, eligibility, and how to apply.
| Parameter | Type | Required | Description |
|---|
county | string | No | UK county code |
org | string | No | Filter by organisation subdomain |
search | string | No | Search name, notes, and eligibility |
Alpaca Portfolio
Alpaca paper/live trading portfolio for club investment activities. Data is server-cached for 5 minutes per activity.
Returns the cached Alpaca portfolio for an activity: account summary (equity, cash, buying power), open positions, recent orders (last 10), and intraday portfolio history (5-min intervals). Refreshes from Alpaca if the cache is older than 5 minutes. Respects per-member access control via ActivityMemberAccess and ActivityGroupAccess.
| Parameter | Type | Required | Description |
|---|
activity_id | integer | Yes | Activity ID (must be an Alpaca Portfolio activity with credentials configured) |
member_email | string | No | Member email for access check (used by WP plugins; mobile apps use the Bearer token instead) |
WordPress plugin updates
Self-hosted update server — every STS WP plugin polls its own slug daily via WP-Cron and
installs the new zip if version is newer than what's currently installed.
| Parameter | Type | Required | Description |
|---|
slug | string | Yes | e.g. spotthesplat-notices |
| Parameter | Type | Required | Description |
|---|
slug | string | Yes | |
version | string | Yes | |
QuickBooks Online
Integration with QuickBooks Online for bank balances and balance sheet. Requires OAuth2 connection per organisation.
Initiates the QBO OAuth2 flow. Redirects the browser to Intuit's authorisation page. The organisation must have a QboConnection with Client ID and Secret configured in Django admin first.
| Parameter | Type | Required | Description |
|---|
org | integer | Yes | Organisation ID |
Intuit redirects here after authorisation. Exchanges the authorisation code for access and refresh tokens, stores the realm_id (QBO Company ID), and confirms the connection.
| Parameter | Type | Required | Description |
|---|
code | string | Yes | Authorisation code from Intuit |
state | string | Yes | HMAC-signed state for CSRF protection |
realmId | string | Yes | QBO Company ID |
Returns cached bank account balances and a simplified balance sheet (one level deep with sub-sections). Data is refreshed from QBO if the cache is older than 5 minutes. Access tokens are auto-refreshed if expired.
| Parameter | Type | Required | Description |
|---|
org_id | integer | Yes | Organisation ID (must have a connected QboConnection) |
Audit
User action logs, model change logs, web sign-in tracking, and member platform access summary.
Returns custom action logs (sign-ins, page views, connections) for the organisation. Paginated with limit and offset.
| Parameter | Type | Required | Description |
|---|
org | integer | No | Organisation ID (required when using the global API key) |
limit | integer | No | Max results (default 50, max 200) |
offset | integer | No | Pagination offset (default 0) |
Returns django-auditlog model change logs (create/update/delete) with field-level old and new values. Paginated.
| Parameter | Type | Required | Description |
|---|
org | integer | No | Organisation ID (required when using the global API key) |
limit | integer | No | Max results (default 50, max 200) |
offset | integer | No | Pagination offset (default 0) |
Called by the WordPress plugin after a successful sign-in to record web platform access for audit tracking.
| Parameter | Type | Required | Description |
|---|
email | string | Yes | The signed-in member's email address |
Returns all active members with their platform access status (web, iOS, Android) and counts. Used by the Member Access summary table.
| Parameter | Type | Required | Description |
|---|
org | integer | No | Organisation ID (required when using the global API key) |
Communications
Channel-agnostic message dispatch system. Email channel working via Resend; push, WhatsApp, and SMS channels planned.
Compose and immediately dispatch a message to all org members, a group, or explicit recipients via the specified channel. Per-org API key required.
| Parameter | Type | Required | Description |
|---|
channel | string | Yes | Channel type: email, push, whatsapp, or sms |
subject | string | No | Email subject or push notification title |
body | string | Yes | Message body (HTML for email, plain text for push/SMS) |
body_plain | string | No | Plain text fallback for email |
target_all_members | boolean | No | Send to all active members (default false) |
target_group_id | integer | No | Send to members of this group |
source_app | string | No | Which app triggered the message (e.g. breakfast, notices) |
Returns sent message history for the organisation with recipient counts and delivery status. Paginated.
| Parameter | Type | Required | Description |
|---|
limit | integer | No | Max results (default 20, max 100) |
offset | integer | No | Pagination offset (default 0) |
Installs
Every STS WordPress plugin POSTs to this endpoint on activation, daily via WP-Cron,
and on deactivation. Public, no API key required. Tolerant — any malformed payload
returns 200 silently so a buggy plugin can never block a member's page render.
Records site_url, plugin_slug, plugin_version, wp_version, php_version, event.
No member data, no tokens.
| Parameter | Type | Required | Description |
|---|
site_url | string | Yes | |
plugin_slug | string | Yes | |
plugin_version | string | No | |
wp_version | string | No | |
php_version | string | No | |
event | string | No | |
Links
Returns published LinkGroups (sorted by sort_order) for the
organisation owning the API key, with each group's published
Links nested. Powers the [link_library] WP shortcode.
| Parameter | Type | Required | Description |
|---|
group | string | No | Optional case-insensitive group name filter |
Photos
| Parameter | Type | Required | Description |
|---|
event_id | integer | Yes | |
email | string | Yes | |
Per-org API key + member email auth. Returns folders with cover
thumb URL (signed, 1h TTL), photo count, originator + event
labels, can_edit flag, and per-folder size_bytes. Top-level
`totals` aggregates org-wide folder count, photo count, and
bytes for the WP gallery's header banner.
| Parameter | Type | Required | Description |
|---|
email | string | Yes | |
| Parameter | Type | Required | Description |
|---|
email | string | Yes | |
name | string | Yes | |
description | string | No | |
originator_id | integer | No | Membership id; display credit only |
event_id | integer | No | events.Event id (past or future) |
| Parameter | Type | Required | Description |
|---|
folder_id | integer | Yes | |
| Parameter | Type | Required | Description |
|---|
folder_id | integer | Yes | |
email | string | No | |
name | string | No | |
description | string | No | |
originator_id | integer | No | |
event_id | integer | No | |
cover_photo_id | integer | No | |
Returns photos with signed `thumb_url` (inline disposition for
<img> rendering), `view_url` (inline original), and
`download_url` (attachment disposition for Save As).
| Parameter | Type | Required | Description |
|---|
folder_id | integer | Yes | |
email | string | Yes | |
Multipart/form-data ONLY. Server processes: EXIF-strip + auto-
rotate + flatten alpha + cap 4MP original + generate 600px thumb.
Both stored as JPEG quality 85 on R2.
| Parameter | Type | Required | Description |
|---|
folder_id | integer | Yes | |
| Parameter | Type | Required | Description |
|---|
photo_id | integer | Yes | |
SpotTheSplat API v2.3 — Schema auto-generated from /api/v2/schema/