App platform API

Learn more about the App platform project.

SpotTheSplat API v2.3

Base URL: https://spotthesplat.fly.dev/api/v2

Authentication

All endpoints require the X-API-Key header unless marked as public.

Header: X-API-Key: your-api-key

Health check

GET/api/v2/test/Simple test endpoint

Core

Platform health, organisations, activities, and user management.

GET/health/Health check

Returns service status. Use to verify the API is running.

GET/organisations/List organisations

Returns all organisations registered on the platform with name, subdomain, and branding.

GET/activities/List activities

Returns app instances (activities) for organisations. Each activity links an app to an organisation.

ParameterTypeRequiredDescription
orgstringNoFilter by organisation subdomain
GET/user/Check user exists

Check if a Django user account exists for the given email address.

ParameterTypeRequiredDescription
emailstringYesEmail address to look up

Members

Member directory and verification for SSO-protected content.

GET/api/v2/me/Get the calling member's profile

ParameterTypeRequiredDescription
emailstringYes
POST/api/v2/me/Update the calling member's profile (JSON or multipart for photo upload)

GET/api/v2/me/dashboard/Personalised member home-page dashboard

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).

ParameterTypeRequiredDescription
emailstringYes
GET/api/v2/members/List members by club

ParameterTypeRequiredDescription
clubstringYesClub name
GET/api/v2/members/detail/Read-only full profile of any member in the same org

ParameterTypeRequiredDescription
emailstringYes
GET/api/v2/members/dietary/Admin-only catering roster — every active member's dietary requirements + their partner's dietary requirements (org-scoped)

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.

GET/api/v2/members/{member_id}/Get member details by ID

ParameterTypeRequiredDescription
member_idintegerYes
GET/api/v2/user/Get authenticated user membership info

GET/members/List all members

Returns all active members with name, email, mobile, member type, access role, and organisation.

GET/members/verify/Verify membership

Checks if an email belongs to an active member. Used by WordPress plugins to gate content behind Google SSO.

ParameterTypeRequiredDescription
emailstringYesEmail address to verify

App Store

GET/api/v2/apps/List available apps for a club

ParameterTypeRequiredDescription
clubstringNo

Authentication

Social sign-in flows for mobile apps and WordPress plugins. Google and Apple are supported; Facebook is planned.

POST/auth/google/mobile/Google mobile sign-inPublic

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.

ParameterTypeRequiredDescription
id_tokenstringYesGoogle ID token from the mobile SDK
POST/auth/apple/mobile/Apple mobile sign-inPublic

Exchange an Apple identity token (from ASAuthorizationAppleIDCredential) for a bearer session token. Audience must match the app's bundle ID.

ParameterTypeRequiredDescription
identity_tokenstringYesApple identity token JWT from the iOS SDK
first_namestringNoFirst name (Apple only provides this on first sign-in)
last_namestringNoLast name (Apple only provides this on first sign-in)
GET/auth/apple/web/start/Apple web sign-in (start)Public

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.

ParameterTypeRequiredDescription
return_tostringYesHTTPS URL to redirect back to after Apple auth (e.g. the WP callback page)
POST/auth/apple/web/Apple web sign-in (callback)Public

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.

ParameterTypeRequiredDescription
codestringYesAuthorization code from Apple (form-posted)
statestringYesHMAC-signed state containing the return URL (form-posted)
POST/auth/apple/link/start/Apple link account (start)Public
GET/auth/apple/link/verify/Apple link account (verify)Public

Activities

GET/api/v2/activities/List activities for a club + app slug

ParameterTypeRequiredDescription
clubstringNo
appstringNo

Notices

Organisation announcements and events with date-ranged visibility.

GET/api/v2/notices/{club_slug}/List notices for a club

ParameterTypeRequiredDescription
club_slugstringYes
GET/api/v2/notices/{club_slug}/{activity_id}/List notices for a single activity

ParameterTypeRequiredDescription
club_slugstringYes
activity_idintegerYes
GET/notices/List active notices

Returns notices currently within their visibility window. Includes title, description, event date/time, price, contact details, and access level.

GET/notices/{id}/qr/Notice QR code

Returns a QR code PNG image encoding the notice's website URL.

ParameterTypeRequiredDescription
idintegerYesNotice ID

Breakfast

Breakfast meeting RSVP system with choice selection, guest bookings, and reports.

GET/api/v2/breakfast/{club_slug}/{activity_id}/orders/Get breakfast orders for activity

ParameterTypeRequiredDescription
club_slugstringYes
activity_idintegerYes
GET/breakfast/events/Next breakfast eventPublic

Returns the next upcoming breakfast event with title, date, time, and location.

POST/breakfast/submit/Submit breakfast bookingPublic

Submit a breakfast choice for an event. Validates the choice code.

ParameterTypeRequiredDescription
event_idintegerYesBreakfast event ID
emailstringYesMember email
breakfast_choicestringYesChoice code: full, continental, bacon, none, apology
GET/breakfast/{org_slug}/current/Current breakfast status

Returns the current breakfast activity for the organisation, including deadline and the member's latest choice.

ParameterTypeRequiredDescription
org_slugstringYesOrganisation subdomain
emailstringYesMember email
POST/breakfast/{org_slug}/{activity_id}/submit/Submit or update choice

Submit or change a breakfast choice. Validates deadline, normalises choice codes, supports guest bookings.

ParameterTypeRequiredDescription
org_slugstringYesOrganisation subdomain
activity_idintegerYesActivity ID
emailstringYesMember email
breakfast_choicestringYesChoice code
bringing_guestbooleanNoSet to true if bringing a guest
guest_first_namestringNoGuest first name
guest_last_namestringNoGuest last name
guest_breakfast_choicestringNoGuest choice code
GET/breakfast/{org_slug}/{activity_id}/report/Breakfast attendance report

Full attendance report listing all members with their choices and summary totals.

ParameterTypeRequiredDescription
org_slugstringYesOrganisation subdomain
activity_idintegerYesActivity ID

Groups & Positions

Member groups (committees, teams), organisational positions (President, Secretary), and year-scoped assignments. Used for access control, leadership displays, and committee listings.

GET/groups/List groups

Returns all active member groups for the organisation.

GET/groups/{id}/members/Group members

Returns members of a group for a given year, including ongoing (year-less) memberships. Includes role_label for each member.

ParameterTypeRequiredDescription
idintegerYesGroup ID
yearstringNoOrgYear label (e.g. '2025-26') or 'current' (default)
GET/groups/{id}/team/Group team with positions

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.

ParameterTypeRequiredDescription
idintegerYesGroup ID
yearstringNoOrgYear label or 'current' (default)
GET/groups/all-teams/All groups with teams

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.

ParameterTypeRequiredDescription
yearstringNoOrgYear label or 'current' (default)
orgintegerNoOrganisation ID (required when using the global API key)
GET/officers/Current officers

Returns all positions for the organisation with their current holders. Designed for 'Meet the Team' displays. Positions are ordered by display_order.

ParameterTypeRequiredDescription
yearstringNoOrgYear label or 'current' (default)

Library

GET/api/v2/library/List folders + visible documents in the calling member's org library

ParameterTypeRequiredDescription
emailstringYes
folder_idintegerNoOmit for root
GET/api/v2/library/{doc_id}/Document detail with full version history

ParameterTypeRequiredDescription
doc_idintegerYes
emailstringYes
GET/api/v2/library/{doc_id}/download/302 to a 300-second presigned R2 download URL for the current version

ParameterTypeRequiredDescription
doc_idintegerYes
emailstringYes
GET/api/v2/library/{doc_id}/signed-url/10-minute presigned R2 URL for in-browser viewing

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.

ParameterTypeRequiredDescription
doc_idintegerYes
emailstringYes
POST/api/v2/library/{doc_id}/checkout/Soft check-out (default 7-day window)

ParameterTypeRequiredDescription
doc_idintegerYes
emailstringNo
notestringNo
daysintegerNo
POST/api/v2/library/{doc_id}/release/Release an active checkout (holder or admin)

ParameterTypeRequiredDescription
doc_idintegerYes
POST/api/v2/library/{doc_id}/upload/Upload a new version (multipart)

ParameterTypeRequiredDescription
doc_idintegerYes
POST/api/v2/library/create/Create a new document (admin only, multipart)

POST/api/v2/library/folders/create/Create a folder under the given parent (admin only)

ParameterTypeRequiredDescription
emailstringYes
namestringYes
parent_idintegerNoOmit or 0 for root
restricted_to_group_idintegerNoOptional MemberGroup id (folder + children visible only to that group)
POST/api/v2/library/{doc_id}/delete/Soft-delete a document (admin only)

ParameterTypeRequiredDescription
doc_idintegerYes
POST/api/v2/library/{doc_id}/restore/Restore a soft-deleted document (admin only)

ParameterTypeRequiredDescription
doc_idintegerYes
GET/api/v2/library/audit/Library audit log (admin only)

ParameterTypeRequiredDescription
emailstringYes
daysintegerNo

Furniture Project

GET/api/v2/furniture/categories/Furniture categories (platform-wide, public)

GET/api/v2/furniture/deliveries/List deliveries (org-scoped)

ParameterTypeRequiredDescription
statusstringNo
POST/api/v2/furniture/deliveries/create/Create a delivery (existing recipient_id OR new recipient + items[])

GET/api/v2/furniture/deliveries/{delivery_id}/Delivery detail (recipient + items)

POST/api/v2/furniture/deliveries/{delivery_id}/status/Transition a delivery's status (auto-syncs item statuses)

GET/api/v2/furniture/items/List furniture items (public — defaults to status=available)

ParameterTypeRequiredDescription
orgintegerNo
categorystringNo
qstringNo
statusstringNo
limitintegerNo
offsetintegerNo
POST/api/v2/furniture/items/create/Create a furniture item (multipart for photos)

GET/api/v2/furniture/items/{item_id}/Single furniture item (public, full detail incl. all photos)

ParameterTypeRequiredDescription
item_idintegerYes
POST/api/v2/furniture/items/{item_id}/photos/Add a photo to an existing item (multipart)

GET/api/v2/furniture/recipients/Search recipients (org-scoped)

ParameterTypeRequiredDescription
qstringNo
POST/api/v2/furniture/recipients/create/Create a recipient

Calendar

ICS calendar feed integration for club/organisation calendars.

GET/calendar/events/Get calendar events

Fetches and parses the ICS feed configured for the given activity. Returns events with name, start, end, location, description, and access level.

ParameterTypeRequiredDescription
activity_idintegerYesActivity ID with calendar config

Borrowers

GET/api/v2/borrow/List this org's borrow requests (date-asc)

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.

ParameterTypeRequiredDescription
emailstringYes
POST/api/v2/borrow/create/Create a new borrow request

ParameterTypeRequiredDescription
emailstringYesCalling member's email.
item_namestringYes
descriptionstringYes
start_atstringYes
end_atstringYes
POST/api/v2/borrow/{request_id}/cancel/Requester cancels (or unmatches) the request

ParameterTypeRequiredDescription
request_idintegerYes
emailstringYes
POST/api/v2/borrow/{request_id}/match/Agree to lend the item (records lender + optional comments)

ParameterTypeRequiredDescription
request_idintegerYes
emailstringYes
commentsstringNoOptional note to the requester.

Recycle

GET/api/v2/recycle/List this org's recycle listings (newest first)

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.

ParameterTypeRequiredDescription
emailstringYes
POST/api/v2/recycle/applications/{application_id}/decide/Donor approves or rejects an application

Approving auto-rejects every other PENDING application on the same listing and flips the listing to `promised`.

ParameterTypeRequiredDescription
application_idintegerYes
emailstringYes
actionstringYes
POST/api/v2/recycle/listings/Create a recycle listing (multipart — photo + fields)

Multipart/form-data ONLY (the photo is a file upload). Required fields: item_name, description, photo, email.

POST/api/v2/recycle/listings/{listing_id}/apply/Recipient applies for a listing (with optional message)

ParameterTypeRequiredDescription
listing_idintegerYes
emailstringYes
messagestringNoOptional pitch from the recipient.
POST/api/v2/recycle/listings/{listing_id}/withdraw/Donor withdraws the listing (auto-rejects pending applications)

ParameterTypeRequiredDescription
listing_idintegerYes
emailstringYes

Courses

Video course delivery with drip-feed, completion tracking, and PDF certificates.

GET/api/v2/courses/List published courses for the calling member's org

ParameterTypeRequiredDescription
emailstringNoOptional — adds enrolment status to each course
GET/api/v2/courses/{slug}/Course detail with lessons + per-lesson availability and progress

ParameterTypeRequiredDescription
slugstringYes
emailstringNo
POST/api/v2/courses/{slug}/enrol/Enrol the member in a course (idempotent)

ParameterTypeRequiredDescription
slugstringYes
emailstringNo
POST/api/v2/courses/{slug}/lessons/{lesson_id}/complete/Mark a lesson complete for the member's enrolment

ParameterTypeRequiredDescription
slugstringYes
lesson_idintegerYes
emailstringNo
GET/api/v2/courses/{slug}/certificate.pdfPDF certificate for a completed course (A4 landscape, WeasyPrint)

ParameterTypeRequiredDescription
slugstringYes
emailstringYes

Events

Organisation events with maps, QR codes, and per-event access control.

GET/events/List events

Returns published events with date, time, location, description, website, QR code URL, and access level.

ParameterTypeRequiredDescription
orgstringNoFilter by organisation subdomain
upcomingbooleanNoSet to 'true' to show only future events
GET/events/{id}/qr/Event QR codePublic

Returns a QR code PNG image encoding the event's website URL.

ParameterTypeRequiredDescription
idintegerYesEvent ID

Vouchers

POST/api/v2/vouchers/validate/Validate a discount voucher (live, pre-checkout)

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).

ParameterTypeRequiredDescription
codestringYesCustomer-facing voucher code, case-insensitive.
scope_typestringYesWhich feature is this voucher being applied to.
scope_idstringYesFeature-specific identifier — course slug, duck-race id, splat-game id.
base_amount_minorintegerYesCart total in minor units (pence) BEFORE discount.
currencystringYesThree-letter ISO code, lowercase.

Duck Race

Duck race fundraiser — buy a numbered duck, share the prize pot.

GET/api/v2/duck/{race_id}/Public duck race state with live prize pot

ParameterTypeRequiredDescription
race_idintegerYes
POST/api/v2/duck/{race_id}/checkout/Reserve a duck and start a Stripe Checkout session

ParameterTypeRequiredDescription
race_idintegerYes
numberintegerNo
buyer_namestringNo
buyer_emailstringNo
buyer_phonestringNo
success_urlstringNo
cancel_urlstringNo
GET/api/v2/duck/{race_id}/results/Declared race results (1st / 2nd / 3rd + race photo)

ParameterTypeRequiredDescription
race_idintegerYes

Splat Game

GET/api/v2/splat/{activity_id}/Splat game state — grid + per-square status (public)

ParameterTypeRequiredDescription
activity_idintegerYes
POST/api/v2/splat/{activity_id}/checkout/Soft-reserve a square and create a Stripe Checkout session

ParameterTypeRequiredDescription
activity_idintegerYes

Compliance (DSAR + Privacy + Cookies)

POST/api/v2/compliance/cookies-consent/Log a visitor's cookie consent choice (anonymous audit trail)
GET/api/v2/compliance/cookies-notice/Public Cookies Notice for one tenant — UK PECR / GDPR / UAE PDPL / India DPDP

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).

ParameterTypeRequiredDescription
orgstringYesOrganisation subdomain.
GET/api/v2/compliance/dpo/queue/DPO queue (cross-tenant)

Caller must attest DPO role server-side; the WP plugin enforces access_role in (admin, global_admin) and DPO group membership.

ParameterTypeRequiredDescription
statestringNoopen (default) | all | <status slug>
POST/api/v2/compliance/dsar/Submit a Data Subject Access Request

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.

ParameterTypeRequiredDescription
emailstringYes
request_typestringNo
notesstringNo
verify_urlstringNo
attest_fresh_ssobooleanNo
sso_providerstringNo
POST/api/v2/compliance/dsar/{dsar_id}/pay/Create a Stripe Checkout session for the £10 repeat-DSAR fee

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).

ParameterTypeRequiredDescription
dsar_idintegerYes
success_urlstringYes
cancel_urlstringYes
GET/api/v2/compliance/dsar/{dsar_id}/status/Self-serve status check

ParameterTypeRequiredDescription
dsar_idintegerYes
emailstringYes
POST/api/v2/compliance/dsar/{dsar_id}/verify/Verify identity via magic-link token + last name + postcode

ParameterTypeRequiredDescription
dsar_idintegerYes
tokenstringYes
last_namestringYes
postcodestringYes
GET/api/v2/compliance/privacy-notice/Public Privacy Notice for one tenant — UK GDPR Art. 13/14

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.

ParameterTypeRequiredDescription
orgstringYesOrganisation subdomain.

Statistics

GET/api/v2/stats/summary/Aggregated stats for the org (admin)

ParameterTypeRequiredDescription
daysintegerNo
POST/api/v2/stats/track/Record a page view (no auth — uses org_slug or per-org key in body)

Charities & Funders

Directory of charities and grant funders, filterable by UK county.

GET/charities/List charities

Returns charities with Charity Commission data, income, contact details, areas served, and tags.

ParameterTypeRequiredDescription
countystringNoUK county code (e.g. bedfordshire)
orgstringNoFilter by organisation subdomain
tagstringNoFilter by tag (e.g. homelessness)
searchstringNoSearch name, description, and address
GET/funders/List funders

Returns grant funders with type, geographic focus, grant range, eligibility, and how to apply.

ParameterTypeRequiredDescription
countystringNoUK county code
orgstringNoFilter by organisation subdomain
searchstringNoSearch name, notes, and eligibility

Platform Usage

GET/api/v2/usage/summary/Platform Health dashboard JSON (admin / global admin only)

ParameterTypeRequiredDescription
emailstringYesCaller email — must resolve to a Membership with access_role in (admin, global_admin)
GET/api/v2/installations/by-org/WP plugin installations grouped by Organisation (admin only)

Per-tenant view of which STS plugins are running where, with per-row version-status (✅ up to date / ⚠ update available / · no release / ? unknown) computed against the latest published PluginRelease per slug. Sites whose URL doesn't match any Organisation.wp_site_url bucket under '(unmatched sites)' so misconfiguration is visible. Backs the [platform_installations] WP shortcode in spotthesplat-platform-health.

ParameterTypeRequiredDescription
emailstringYes
GET/api/v2/platform/stats/Public marketing headline stats (organisations / apps / categories)

Public, no auth. Returns headline numbers for the [platform_stats] shortcode used on marketing pages.

Platform Docs

GET/api/v2/docs/check/Check if a member has been granted platform-docs access (cross-org)

ParameterTypeRequiredDescription
emailstringYes
GET/api/v2/docs/platform-guide/Returns the platform_guide.html content if the member has docs access (else 403)

ParameterTypeRequiredDescription
emailstringYes

Alpaca Portfolio

Alpaca paper/live trading portfolio for club investment activities. Data is server-cached for 5 minutes per activity.

GET/alpaca/{activity_id}/Portfolio snapshot

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.

ParameterTypeRequiredDescription
activity_idintegerYesActivity ID (must be an Alpaca Portfolio activity with credentials configured)
member_emailstringNoMember email for access check (used by WP plugins; mobile apps use the Bearer token instead)

WordPress plugin updates

GET/api/v2/wp-update/{slug}/WordPress plugin update manifest (public)

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.

ParameterTypeRequiredDescription
slugstringYese.g. spotthesplat-notices
GET/api/v2/wp-update/{slug}/{version}/download/Plugin zip download — 302 to 300-second presigned R2 URL (public)

ParameterTypeRequiredDescription
slugstringYes
versionstringYes

QuickBooks Online

Integration with QuickBooks Online for bank balances and balance sheet. Requires OAuth2 connection per organisation.

GET/qbo/connect/Connect to QuickBooks (OAuth start)Public

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.

ParameterTypeRequiredDescription
orgintegerYesOrganisation ID
GET/qbo/callback/QuickBooks OAuth callbackPublic

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.

ParameterTypeRequiredDescription
codestringYesAuthorisation code from Intuit
statestringYesHMAC-signed state for CSRF protection
realmIdstringYesQBO Company ID
GET/qbo/{org_id}/summary/Finance summary

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.

ParameterTypeRequiredDescription
org_idintegerYesOrganisation ID (must have a connected QboConnection)

Audit

User action logs, model change logs, web sign-in tracking, and member platform access summary.

GET/audit/actions/Action logs

Returns custom action logs (sign-ins, page views, connections) for the organisation. Paginated with limit and offset.

ParameterTypeRequiredDescription
orgintegerNoOrganisation ID (required when using the global API key)
limitintegerNoMax results (default 50, max 200)
offsetintegerNoPagination offset (default 0)
GET/audit/changes/Model change logs

Returns django-auditlog model change logs (create/update/delete) with field-level old and new values. Paginated.

ParameterTypeRequiredDescription
orgintegerNoOrganisation ID (required when using the global API key)
limitintegerNoMax results (default 50, max 200)
offsetintegerNoPagination offset (default 0)
GET/audit/web-signin/Track web sign-in

Called by the WordPress plugin after a successful sign-in to record web platform access for audit tracking.

ParameterTypeRequiredDescription
emailstringYesThe signed-in member's email address
GET/audit/member-access/Member platform access

Returns all active members with their platform access status (web, iOS, Android) and counts. Used by the Member Access summary table.

ParameterTypeRequiredDescription
orgintegerNoOrganisation 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.

POST/comms/send/Send message

Compose and immediately dispatch a message to all org members, a group, or explicit recipients via the specified channel. Per-org API key required.

ParameterTypeRequiredDescription
channelstringYesChannel type: email, push, whatsapp, or sms
subjectstringNoEmail subject or push notification title
bodystringYesMessage body (HTML for email, plain text for push/SMS)
body_plainstringNoPlain text fallback for email
target_all_membersbooleanNoSend to all active members (default false)
target_group_idintegerNoSend to members of this group
source_appstringNoWhich app triggered the message (e.g. breakfast, notices)
GET/comms/history/Message history

Returns sent message history for the organisation with recipient counts and delivery status. Paginated.

ParameterTypeRequiredDescription
limitintegerNoMax results (default 20, max 100)
offsetintegerNoPagination offset (default 0)

Installs

POST/api/v2/installs/heartbeat/WP plugin install telemetry — public, fire-and-forget

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.

ParameterTypeRequiredDescription
site_urlstringYes
plugin_slugstringYes
plugin_versionstringNo
wp_versionstringNo
php_versionstringNo
eventstringNo

Other

GET/api/v2/API root

Payments

POST/api/v2/payments/webhook/Stripe webhook receiver (signature-verified, dispatches to per-app handlers)

Photos

GET/api/v2/photos/by-event/{event_id}/List folders attached to an event

ParameterTypeRequiredDescription
event_idintegerYes
emailstringYes
GET/api/v2/photos/folders/List photo folders for the calling member's org

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.

ParameterTypeRequiredDescription
emailstringYes
POST/api/v2/photos/folders/create/Create a photo folder (admin only)

ParameterTypeRequiredDescription
emailstringYes
namestringYes
descriptionstringNo
originator_idintegerNoMembership id; display credit only
event_idintegerNoevents.Event id (past or future)
POST/api/v2/photos/folders/{folder_id}/delete/Soft-delete folder + all its photos (admin only)

ParameterTypeRequiredDescription
folder_idintegerYes
POST/api/v2/photos/folders/{folder_id}/edit/Edit folder metadata (admin only)

ParameterTypeRequiredDescription
folder_idintegerYes
emailstringNo
namestringNo
descriptionstringNo
originator_idintegerNo
event_idintegerNo
cover_photo_idintegerNo
GET/api/v2/photos/folders/{folder_id}/photos/List photos in a folder

Returns photos with signed `thumb_url` (inline disposition for <img> rendering), `view_url` (inline original), and `download_url` (attachment disposition for Save As).

ParameterTypeRequiredDescription
folder_idintegerYes
emailstringYes
POST/api/v2/photos/folders/{folder_id}/upload/Upload one photo to a folder (admin only; multipart)

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.

ParameterTypeRequiredDescription
folder_idintegerYes
POST/api/v2/photos/{photo_id}/delete/Soft-delete a photo (admin only)

ParameterTypeRequiredDescription
photo_idintegerYes

SpotTheSplat API v2.3 — Schema auto-generated from /api/v2/schema/