Build on the Playbook Platform
The Playbook Open API gives developers programmatic access to registrations, scheduling, payments, user profiles, and more. Integrate sports and recreation management data directly into your own applications and workflows.
How it works
Authentication
All endpoints require a Bearer token. Admin tokens are provisioned by your Playbook Success Coach. User-scoped tokens can be minted per session via the auth endpoint.
Two token scopes
Admin tokens have full read access across all data. User-scoped tokens are short-lived and automatically filter responses to a single end-user's records — ideal for member-facing integrations.
Async operations
Write operations (registrations, bookings) return a task ID immediately. Poll GET /open-api/tasks/{id}/ to track completion — no long-running HTTP connections needed.
Sandbox mode
Set is_test: true when minting a token, or pass X-Open-API-Dry-Run: true on any write request. Full validation runs but no data is written, charged, or notified.
Ready to get started?
Contact your Playbook Success Coach to schedule a setup call with our Technical Implementation team.
API Reference
All endpoints require a valid Bearer token and are scoped to your organization's tenant.
Base URL: https://callplaybook.com/open-api
Returns the current health status of the API and the league ID for the authenticated tenant. Callable with either an admin or user-scoped Bearer token.
No parameters
{ "status": "string", "league_id": 1 }
Inspect the calling identity, mint short-lived user-scoped tokens (admin only), and revoke them. Admin tokens are provisioned out-of-band via shell.
Mints a short-lived Bearer token that authenticates subsequent requests as the specified end-user (rather than as the tenant admin). Identify the target user by email or user_id — the user must exist in the authenticated league. The default token lifetime is 1 hour; clients should mint a fresh token per session. The raw token value is returned once — only its hash is persisted, so it cannot be retrieved later.
| Field | Type | Description |
|---|---|---|
| string(email) | Target user email | |
| user_id | integer | Target user ID (alternative to email) |
| client_label | string | Optional label to identify the issuing client |
| ttl_seconds | integer | Token lifetime in seconds. Defaults to 3600, capped at 28800 |
| is_test | boolean | If true, issues a sandbox token. Write requests are validated but produce no DB writes, payments, or notifications. Read endpoints behave normally |
{ "token": "string", "expires_at": "2026-01-01T00:00:00Z", "user_id": 1, "user_email": "user@example.com", "is_test": true }
Revokes a user-scoped token previously issued via POST /open-api/auth/user-tokens/. The raw token is sent in the request body so it does not appear in webserver access logs. Returns 204 on success or 404 if the token does not belong to the authenticated league.
| Field | Type | Description |
|---|---|---|
| tokenrequired | string | The user-scoped token to revoke |
Returns the identity behind the supplied Bearer token. Useful for clients to verify that a freshly minted user-scoped token is valid before issuing dependent API calls.
No parameters
{ "user_id": 1, "user_email": "user@example.com", "league_id": 1, "expires_at": "2026-01-01T00:00:00Z", "is_test": true }
Reference data describing what a league offers: programs available for registration, subscription plans, pass types, coupons, waiver definitions, seasons, divisions, teams, and locations.
Returns all programs currently available for registration, grouped by type. Includes pricing, restrictions (age, grade, gender, membership), capacity, and dates.
| Parameter | Type | Description |
|---|---|---|
| type | string | Filter by program type: class_package, season, club, membership, pass_package |
| category_id | integer | Filter by category ID |
{ "count": 1, "next": null, "previous": null, "results": [] }Returns a paginated list of seasons for the authenticated league. Catalog data: identical results for admin and user tokens.
| Parameter | Type | Description |
|---|---|---|
| is_active | boolean | Filter by active status |
| sport | string | Filter by sport code |
| start_date_after | string | YYYY-MM-DD |
| start_date_before | string | YYYY-MM-DD |
| registration_available | boolean | Filter by registration_available |
| category_id | integer | Filter by category ID |
| limit | integer | Page size |
| offset | integer | Pagination offset |
{ "count": 1, "results": [{ "id": 1, "league_id": 1, "name": "string", "sport": null, "start_date": "2026-01-01", "end_date": "2026-01-01" }] }Returns a paginated list of internal divisions for the authenticated league. External divisions (synced placeholders) are excluded.
| Parameter | Type | Description |
|---|---|---|
| season_id | integer | Filter by season ID |
| skill_level | string | Filter by skill_level code |
| is_default | boolean | Filter by is_default |
| limit | integer | Page size |
| offset | integer | Pagination offset |
{ "count": 1, "results": [{ "id": 1, "league_id": 1, "season_id": 1, "name": "string", "skill_level": "NA", "is_default": true }] }Returns a paginated list of teams for the authenticated league. When called with a user-scoped token, results are auto-filtered to teams whose roster includes one of the acting user's participants (via RosterStatus).
| Parameter | Type | Description |
|---|---|---|
| season_id | integer | Filter by season ID |
| division_id | integer | Filter by division ID |
| user_id | integer | Filter to teams whose roster includes a participant belonging to this user |
| club_team | boolean | Filter by club_team flag |
| is_external | boolean | Filter teams synced from external systems |
| limit | integer | Page size |
{ "count": 1, "results": [{ "id": 1, "league_id": 1, "name": "string", "skill_level": null, "club_team": true, "is_external": true }] }Returns a paginated list of league locations (gyms / venues). Catalog data: identical results for admin and user tokens.
| Parameter | Type | Description |
|---|---|---|
| is_rentable | boolean | Filter by is_rentable |
| neighborhood_id | integer | Filter by neighborhood ID |
| priority_min | integer | Only return priority >= this value |
| limit | integer | Page size |
{ "results": [{ "id": 1, "name": "string", "address": null, "is_rentable": true, "priority": 1 }] }Returns a paginated list of pass types for the authenticated league. Catalog data: identical results for admin and user tokens.
| Parameter | Type | Description |
|---|---|---|
| is_active | boolean | Computed: inactive when make_pass_expires is false and a stale expiration_date is set |
| type_of_pass | string | onetime or duration |
| make_pass_expires | boolean | Filter by make_pass_expires |
| limit | integer | Page size |
{ "results": [{ "id": 1, "league_id": 1, "name": "string", "type_of_pass": null, "expiration_type": null }] }Returns a paginated catalog of subscription plans (recurring memberships). This is the catalog endpoint; for actual purchases see /open-api/memberships/.
| Parameter | Type | Description |
|---|---|---|
| interval | string | Billing interval: day, week, month, year |
| is_active | boolean | Filter by is_active |
| is_unlimited | boolean | Filter by is_unlimited |
| registration_open_at | string | YYYY-MM-DD. Returns only plans whose registration window includes this date |
| category_id | integer | Filter by category ID |
| limit | integer | Page size |
{ "results": [{ "id": 1, "league_id": 1, "title": "string", "cost": "0.00", "num_installments": 1 }] }Returns a paginated list of coupon codes for the authenticated league. Admin-only: user-scoped tokens are rejected.
| Parameter | Type | Description |
|---|---|---|
| active | boolean | Filter by active flag |
| code | string | Exact-match coupon code lookup |
| gender_required | string | Filter by gender_required code |
| sport_required | string | Filter by sport_required code |
| start_date_after | string | ISO 8601 datetime |
| end_date_before | string | ISO 8601 datetime |
| limit | integer | Page size |
{ "results": [{ "id": 1, "code": "string", "dollar_amount": "string", "percent_amount": "0.00", "active": true }] }Returns a paginated list of waivers for the authenticated league. Catalog data: identical results for admin and user tokens.
| Parameter | Type | Description |
|---|---|---|
| is_default | boolean | Filter by is_default |
| limit | integer | Page size |
| offset | integer | Pagination offset |
{ "results": [{ "id": 1, "league_id": 1, "title": "string", "is_default": true, "pdf_url": "string" }] }Chronological feed of events — games, practices, class sessions, and generic events.
Returns a chronologically ordered feed of events (games, practices, class sessions, generic events). Defaults to the current week when no date range is supplied. Each record includes a type_details object with fields specific to the event type. When called with a user-scoped token, results are auto-filtered to events the user's participants are clocked into.
| Parameter | Type | Description |
|---|---|---|
| start_date | string | Inclusive start of range (YYYY-MM-DD, league timezone). Must be paired with end_date |
| end_date | string | Inclusive end of range (YYYY-MM-DD) |
| event_type | array | Repeat to request multiple: game, practice, class_session, generic_event. Omit for all |
| season_id | integer | Filter game, practice, and generic_event results to a single season |
| participant_id | integer | Filter to events the participant is clocked into. User-scoped: must be one of the acting user's participants |
| class_package_id | integer | Filter class_session results to a single ClassPackage |
| session_block_id | integer | Filter class_session results to a given SessionBlock |
[{ "id": 1, "type": "string", "name": "string", "start_datetime": "2026-01-01T00:00:00Z", "end_datetime": "2026-01-01T00:00:00Z", "time_is_tba": true, "location": "string", "type_details": {} }]
Returns rentable timeslots currently available for booking. Defaults to the current week. League-level rental restrictions (lead hours, max-days-ahead, is_rentable flags) are applied. When participant_id is supplied, results are filtered by membership eligibility. Capped at 250 timeslots per response.
| Parameter | Type | Description |
|---|---|---|
| start_date | string | Inclusive start (YYYY-MM-DD). Must be paired with end_date |
| end_date | string | Inclusive end of range |
| location_id | integer | Restrict to a single location |
| sub_location_id | integer | Restrict to a single sub-location |
| staff_member_id | integer | Restrict to a single staff member |
| resource_type | string | location, sub_location, or staff_member. Omit for all three |
| participant_id | integer | Filter by membership eligibility. User-token callers must pass one of their own participants |
| category_id | integer | Restrict to timeslots in this category |
[{ "id": 1, "resource_type": "string", "window_start": "2026-01-01T00:00:00Z", "window_end": "2026-01-01T00:00:00Z", "minimum_rental_minutes": 60, "price_per_hour": "string", "available_start_times": [] }]
Directory reads of user profiles and the participants (children/players) attached to them. Admin tokens see the full league; user tokens see only the acting user.
Returns a paginated list of user profiles belonging to the authenticated league. When called with a user-scoped token, only returns the acting user's own profile.
| Parameter | Type | Description |
|---|---|---|
| string | Case-insensitive substring match against email (admin tokens only; ignored for user tokens) | |
| limit | integer | Page size |
| offset | integer | Pagination offset |
{ "results": [{ "id": 1, "league_id": 1, "email": "user@example.com", "first_name": "string", "last_name": "string", "phone": "string", "birthday": "2026-01-01", "gender": null }] }Returns a paginated list of participants belonging to the authenticated league. When called with a user-scoped token, only returns participants belonging to the acting user.
| Parameter | Type | Description |
|---|---|---|
| limit | integer | Page size |
| offset | integer | Pagination offset |
{ "results": [{ "id": 1, "user_id": 1, "league_id": 1, "first_name": "string", "last_name": "string", "relation": "ME", "birthday": "2026-01-01" }] }Invoices, payment transactions, refunds, and credit movements.
Returns a paginated list of invoices for the authenticated league. Supports filtering by payment status, date range, and user. When called with a user-scoped token, results are auto-filtered to the acting user's invoices.
| Parameter | Type | Description |
|---|---|---|
| status | string | Filter by payment status: PA, NP, PR, RF |
| user_id | integer | Filter by user ID |
| created_after | string | ISO 8601 datetime |
| created_before | string | ISO 8601 datetime |
| limit | integer | Page size |
{ "results": [{ "id": 1, "user_id": 1, "status": "string", "status_display": "string", "invoice_total": "0.00", "date_created": "2026-01-01T00:00:00Z" }] }Returns a paginated list of payment transactions. By default only paid transactions are returned. Use status=all to include all statuses. When called with a user-scoped token, results are auto-filtered to the acting user's payments.
| Parameter | Type | Description |
|---|---|---|
| status | string | Filter by status (defaults to PA). Use all to include all statuses |
| method | string | Payment method: CC, POS, BA, CH, CA, ET, PS, OT |
| user_id | integer | Filter by user ID |
| created_after | string | ISO 8601 datetime |
| created_before | string | ISO 8601 datetime |
| limit | integer | Page size |
{ "results": [{ "id": 1, "user_id": 1, "invoice_id": 1, "status": null, "method": "CC", "receivable": "0.00", "fee_amount": "0.00" }] }Returns a paginated list of refund transactions for the authenticated league. When called with a user-scoped token, results are auto-filtered to the acting user's refunds.
| Parameter | Type | Description |
|---|---|---|
| invoice_id | integer | Filter by invoice ID |
| payment_transaction_id | integer | Filter to refunds against this payment transaction |
| user_id | integer | Filter by invoice owner user ID |
| created_after | string | ISO 8601 datetime |
| created_before | string | ISO 8601 datetime |
| limit | integer | Page size |
{ "results": [{ "id": 1, "invoice_id": 1, "user_id": 1, "payment_transaction_id": 1, "amount": "0.00", "fee_amount": "0.00" }] }Returns a paginated list of credit transactions (credits used and discounts applied). When called with a user-scoped token, results are auto-filtered to the acting user.
| Parameter | Type | Description |
|---|---|---|
| invoice_id | integer | Filter by invoice ID |
| is_discount | boolean | True = only discounts; false = only credits |
| coupon_code_id | integer | Filter to a coupon code |
| user_id | integer | Filter by user ID |
| created_after | string | ISO 8601 datetime |
| limit | integer | Page size |
{ "results": [{ "id": 1, "user_id": 1, "invoice_id": 1, "num_points": 1, "is_discount": true, "coupon_code_id": 1 }] }Historical record of who registered for what: class registrations, season registrations, membership registrations, the unified feed, pass purchases, and waiver submissions.
Returns a unified, paginated feed of all registration types (class, season, membership). When called with a user-scoped token, results are auto-filtered to the acting user.
| Parameter | Type | Description |
|---|---|---|
| type | string | Filter by type: class, season, membership |
| user_id | integer | Filter by user ID |
| participant_id | integer | Filter by participant ID |
| created_after | string | ISO 8601 datetime |
| created_before | string | ISO 8601 datetime |
| limit | integer | Page size |
{ "count": 0, "results": [] }Returns a paginated list of season registrations. When called with a user-scoped token, results are auto-filtered to the acting user.
| Parameter | Type | Description |
|---|---|---|
| season_id | integer | Filter by season ID |
| division_id | integer | Filter by division ID |
| team_id | integer | Filter by team ID |
| user_id | integer | Filter by user ID |
| participant_id | integer | Filter by participant ID |
| created_after | string | ISO 8601 datetime |
| limit | integer | Page size |
{ "count": 0, "results": [] }Returns a paginated list of class registrations. Supports filtering by date range, user, participant, class package, and payment status. When called with a user-scoped token, results are auto-filtered to the acting user.
| Parameter | Type | Description |
|---|---|---|
| class_package_id | integer | Filter by class package ID |
| participant_id | integer | Filter by participant ID |
| user_id | integer | Filter by user ID |
| payment_status | string | Filter by payment status |
| created_after | string | ISO 8601 datetime |
| created_before | string | ISO 8601 datetime |
| limit | integer | Page size |
{ "results": [{ "id": 1, "user_id": 1, "participant_id": 1, "class_package_id": 1, "class_package_title": "string", "date_created": "2026-01-01T00:00:00Z" }] }Returns a paginated list of membership/credit purchase registrations. Supports filtering by date range, user, participant, credit offer, origin, and active status. When called with a user-scoped token, results are auto-filtered to the acting user.
| Parameter | Type | Description |
|---|---|---|
| credit_offer_id | integer | Filter by credit offer ID |
| is_active | boolean | Filter by active status |
| origin | string | Filter by registration origin |
| participant_id | integer | Filter by participant ID |
| user_id | integer | Filter by user ID |
| created_after | string | ISO 8601 datetime |
| limit | integer | Page size |
{ "results": [{ "id": 1, "user_id": 1, "credit_offer_id": 1, "credit_offer_title": "string", "date_created": "2026-01-01T00:00:00Z" }] }Returns a paginated list of pass purchases (passes a user has acquired). When called with a user-scoped token, results are auto-filtered to the acting user.
| Parameter | Type | Description |
|---|---|---|
| pass_type_id | integer | Filter by pass type ID |
| status | string | Computed status: available, spent, or expired |
| user_id | integer | Filter by user ID |
| created_after | string | ISO 8601 datetime |
| limit | integer | Page size |
{ "results": [{ "id": 1, "user_id": 1, "pass_type_id": 1, "pass_type_name": "string", "expiration_date": "2026-01-01", "status": "string" }] }Returns a paginated list of waiver submissions for the authenticated league. When called with a user-scoped token, results are auto-filtered to the acting user.
| Parameter | Type | Description |
|---|---|---|
| waiver_id | integer | Filter by waiver ID |
| user_id | integer | Filter by user ID |
| limit | integer | Page size |
{ "count": 0, "results": [] }Returns the custom fields required for a given program registration. Call this before submitting a write registration to know which custom_fields keys are required.
| Parameter | Type | Description |
|---|---|---|
| typerequired | string | Program type: class_package, season, club, membership, pass_package |
| idrequired | integer | Program ID |
[{ "key": "string", "label": "string", "type": "string", "required": true }]
Registers the authenticated user (or a participant they manage) into a program. Returns a task_id immediately — poll GET /open-api/tasks/{task_id}/ to track completion. Fetch required fields first via GET /open-api/register/{type}/{id}/fields/.
| Field | Type | Description |
|---|---|---|
| program_idrequired | integer | ID of the program to register for |
| participant_id | integer | Participant to register (omit to register the account holder) |
| coupon_code | string | Optional discount coupon |
| custom_fields | object | Answers to required registration fields (from /fields/ endpoint) |
{ "task_id": "string", "status": "pending" }Polls the status of an asynchronous operation. Keep polling until status is complete or failed. Recommended interval: 1–2 seconds.
| Parameter | Type | Description |
|---|---|---|
| task_idrequired | string | Task ID returned by the write operation |
{ "task_id": "string", "status": "complete", "result": { "registration_id": 99, "invoice_id": 12, "pending_waiver_ids": [4, 7] } }
{ "task_id": "string", "status": "failed", "error": "Program is full." }Returns the profile of the authenticated user — name, email, phone, address, and account preferences.
No parameters
{ "id": 1, "email": "user@example.com", "first_name": "string", "last_name": "string", "phone": "string" }Partially updates the authenticated user's profile. Only include fields you want to change.
| Field | Type | Description |
|---|---|---|
| first_name | string | First name |
| last_name | string | Last name |
| phone | string | Phone number |
| address | object | Address fields |
{ "id": 1, "email": "user@example.com", ... }Returns the authenticated user's active and historical memberships, including pause/cancel eligibility flags.
status (active, paused, cancelled), limit, offset
{ "count": 0, "results": [] }Cancels the specified membership. Check can_cancel flag on the membership object before calling. Takes effect at end of billing period unless immediate: true.
| Field | Type | Description |
|---|---|---|
| reason | string | Cancellation reason (optional) |
| immediate | boolean | Cancel immediately vs. end of period. Default: false |
{ "status": "cancelled", "effective_date": "2026-07-01" }Pauses the membership. Billing is suspended for the pause duration. Check can_pause flag before calling.
| Field | Type | Description |
|---|---|---|
| resume_date | date | Date to automatically resume (YYYY-MM-DD) |
{ "status": "paused", "resume_date": "2026-08-01" }Tutorials
Step-by-step walkthroughs for the most common integration scenarios. Click any tutorial to expand it.
-
1Get your admin Bearer token
Your Playbook Technical Implementation team provisions your admin token out-of-band. You'll receive it directly — it does not expire unless manually revoked. Store it securely; treat it like a password.
-
2Call the health endpoint
Make a GET request to confirm your token is valid and the API is reachable. Replace
YOUR_TOKENwith your admin Bearer token.curl -X GET https://callplaybook.com/open-api/health/ \ -H "Authorization: Bearer YOUR_TOKEN"Expected response:
{ "status": "ok", "league_id": 42 }
Note theleague_id— this is your organization's tenant identifier. It will appear on every response object. -
3Verify your identity with whoami
Call
GET /open-api/auth/whoami/to confirm the token type and confirm it's scoped to the right tenant.curl -X GET https://callplaybook.com/open-api/auth/whoami/ \ -H "Authorization: Bearer YOUR_TOKEN"Expected response for an admin token:
{ "user_id": null, "user_email": null, "league_id": 42, "expires_at": null, "is_test": false }
user_id: nullconfirms this is an admin token, not a user-scoped token.is_test: falseconfirms you're in live mode. -
4You're ready
Your token is valid, your
league_idis confirmed, and you can make authenticated requests to any admin-scoped endpoint. For user-facing integrations, proceed to Tutorial 2 to mint user-scoped tokens.
-
1List available programs
Fetch the program catalog to find the program ID you want to register into. Use the
typefilter to narrow results.curl -X GET "https://callplaybook.com/open-api/programs/?type=season" \ -H "Authorization: Bearer ADMIN_TOKEN"
Note the
idof the target program from theresultsarray. -
2Fetch required registration fields
Before registering, call the fields endpoint to know what custom data is required. Replace
{type}and{id}with the program type and ID from step 1.curl -X GET https://callplaybook.com/open-api/register/season/101/fields/ \ -H "Authorization: Bearer ADMIN_TOKEN"Response is an array of field definitions. Store any
required: truefields — you must include them in your registration payload. -
3Mint a user-scoped token for the member
Registration requires a user-scoped token. Use your admin token to mint one for the member by their
user_idor email.curl -X POST https://callplaybook.com/open-api/auth/user-tokens/ \ -H "Authorization: Bearer ADMIN_TOKEN" \ -H "Content-Type: application/json" \ -d '{"user_id": 5821, "ttl_seconds": 3600}'
Store the
tokenfrom the response. It expires in 1 hour.To test without writing real data, add"is_test": trueto the payload. All validation runs but no records are created. -
4Submit the registration
POST to the programs registration endpoint using the user-scoped token. Include
program_id, optionallyparticipant_id, and any requiredcustom_fields.curl -X POST https://callplaybook.com/open-api/register/programs/ \ -H "Authorization: Bearer USER_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "program_id": 101, "participant_id": 2204, "custom_fields": {"jersey_size": "M", "emergency_contact": "555-0100"} }'
The response returns immediately with a
task_idandstatus: "pending". -
5Poll the task until complete
Poll every 1–2 seconds using the
task_idfrom step 4 untilstatusiscompleteorfailed.curl -X GET https://callplaybook.com/open-api/tasks/abc123/ \ -H "Authorization: Bearer USER_TOKEN"A completed task returns:
{ "task_id": "abc123", "status": "complete", "result": { "registration_id": 9901, "invoice_id": 4412, "pending_waiver_ids": [7, 8] } }
Ifpending_waiver_idsis non-empty, the member still needs to sign waivers. Submit them viaPOST /open-api/me/waiver-submissions/before access is granted.
-
1Mint a user-scoped token
Follow step 3 from Tutorial 2 to mint a token for the specific member whose schedule you want to retrieve. The user-scoped token automatically filters event results to that member's registered programs and teams.
-
2Fetch the member's upcoming events
Call
GET /open-api/events/with a date range. The user-scoped token means you get back only events the member's participants are clocked into — no filtering logic needed on your side.curl -X GET \ "https://callplaybook.com/open-api/events/?start_date=2026-06-01&end_date=2026-06-30" \ -H "Authorization: Bearer USER_TOKEN"
Response is an array of event objects. Each includes
type(game,practice,class_session),start_datetime,end_datetime,location, and atype_detailsobject with event-specific fields. -
3Filter by event type (optional)
To return only games, repeat the
event_typeparameter for each type you want.curl -X GET \ "https://callplaybook.com/open-api/events/?start_date=2026-06-01&end_date=2026-06-30&event_type=game&event_type=practice" \ -H "Authorization: Bearer USER_TOKEN"
-
4Handle the time_is_tba flag
Some events have a confirmed date but no set time yet. Check the
time_is_tbaboolean on each event before displaying a time in your UI — display "TBA" instead of a time when it'strue.The API returns datetimes in UTC. Convert to the member's local timezone in your application layer.
-
1Fetch invoices for a date range
Use your admin token to pull all invoices created within a period. Use
created_afterandcreated_beforeas ISO 8601 datetimes.curl -X GET \ "https://callplaybook.com/open-api/invoices/?created_after=2026-05-01T00:00:00Z&created_before=2026-06-01T00:00:00Z&limit=100" \ -H "Authorization: Bearer ADMIN_TOKEN"
Check
countin the response. If it exceeds yourlimit, paginate using thenextURL. -
2Paginate through all records
Keep following the
nextURL in the response until it returnsnull. This pattern is the same across all list endpoints.# First page GET /open-api/invoices/?created_after=...&limit=100 # Response includes: "next": "https://callplaybook.com/open-api/invoices/?...&offset=100" # Follow next until null GET /open-api/invoices/?...&offset=100 GET /open-api/invoices/?...&offset=200
-
3Pull corresponding payment transactions
For each invoice, fetch the payment transactions to get method, amount, and fee breakdown.
curl -X GET \ "https://callplaybook.com/open-api/payments/?created_after=2026-05-01T00:00:00Z&status=all&limit=100" \ -H "Authorization: Bearer ADMIN_TOKEN"
Omittingstatus=allreturns only paid (PA) transactions by default. Passstatus=allto include pending, refunded, and failed transactions for a complete audit trail. -
4Pull refunds and credits separately
Refunds and applied credits are on their own endpoints. Fetch them with the same date range and join to invoices via
invoice_id.GET /open-api/refunds/?created_after=2026-05-01T00:00:00Z&limit=100 GET /open-api/credits/?created_after=2026-05-01T00:00:00Z&limit=100
-
5Map to your external system
Each invoice has a
user_idyou can join toGET /open-api/user-profiles/for member details. Thestatus_displayfield on invoices gives a human-readable status (Paid,Not Paid,Partial,Refunded) suitable for display in your accounting tool.
-
1Fetch available rental timeslots
Call the bookable calendar with a date range and optionally filter by location. Results respect league-configured lead time and max-days-ahead restrictions automatically.
curl -X GET \ "https://callplaybook.com/open-api/bookable-calendar/?start_date=2026-06-10&end_date=2026-06-10&location_id=3" \ -H "Authorization: Bearer USER_TOKEN"
Each result includes
window_start,window_end,minimum_rental_minutes,price_per_hour, and anavailable_start_timesarray of valid booking start times. -
2Check membership eligibility
Pass
participant_idto filter results to only slots the participant is eligible to book based on their membership. If noparticipant_idis passed, all timeslots are returned regardless of eligibility.curl -X GET \ "https://callplaybook.com/open-api/bookable-calendar/?start_date=2026-06-10&end_date=2026-06-10&participant_id=2204" \ -H "Authorization: Bearer USER_TOKEN"
-
3Dry-run the booking first
Before submitting a real booking, validate your payload with the dry-run header. The server runs all validation but writes nothing.
curl -X POST https://callplaybook.com/open-api/register/bookable-calendar/ \ -H "Authorization: Bearer USER_TOKEN" \ -H "Content-Type: application/json" \ -H "X-Open-API-Dry-Run: true" \ -d '{ "timeslot_id": 88, "participant_id": 2204, "start_time": "2026-06-10T10:00:00Z", "duration_minutes": 60 }'
A 202 response with no errors means your payload is valid. Remove the dry-run header to submit for real.
-
4Poll the task for confirmation
The booking endpoint returns a
task_idimmediately. PollGET /open-api/tasks/{task_id}/untilstatusiscomplete. The result will include theregistration_idandinvoice_idfor the booking.
-
1Fetch the member's memberships
Using a user-scoped token, call
GET /open-api/me/memberships/to retrieve the member's current memberships. Each object includes status (active,paused,cancelled) and permission flags.curl -X GET https://callplaybook.com/open-api/me/memberships/ \ -H "Authorization: Bearer USER_TOKEN" -
2Check eligibility flags before acting
Each membership object includes
can_pauseandcan_cancelbooleans. Always check these before displaying options to the member or submitting a request — they reflect the league's configured rules for that membership plan.{ "id": 331, "status": "active", "credit_offer_title": "Monthly Unlimited", "can_pause": true, "can_cancel": true }
Only show "Pause" or "Cancel" buttons in your UI when the corresponding flag istrue. If a member can't pause, the API will reject the request — don't let users attempt it. -
3Pause the membership
POST to the pause endpoint with an optional
resume_date. Billing is suspended from the pause date until resumption.curl -X POST https://callplaybook.com/open-api/me/memberships/331/pause/ \ -H "Authorization: Bearer USER_TOKEN" \ -H "Content-Type: application/json" \ -d '{"resume_date": "2026-08-01"}'
Response confirms the new status and resume date.
-
4Cancel the membership
POST to the cancel endpoint. By default cancellation takes effect at the end of the current billing period. Pass
"immediate": trueto cancel instantly.curl -X POST https://callplaybook.com/open-api/me/memberships/331/cancel/ \ -H "Authorization: Bearer USER_TOKEN" \ -H "Content-Type: application/json" \ -d '{"reason": "Moving out of area", "immediate": false}'
Response includes
status: "cancelled"andeffective_dateconfirming when the cancellation takes effect. -
5Resume a paused membership
If a membership was paused without a
resume_date, or you want to resume early, POST to the resume endpoint.curl -X POST https://callplaybook.com/open-api/me/memberships/331/resume/ \ -H "Authorization: Bearer USER_TOKEN" \ -H "Content-Type: application/json" \ -d '{}'
Need a custom integration walkthrough?
Our Technical Implementation team can guide you through your specific use case on a setup call.
Frequently Asked Questions
Common questions about integrating with the Playbook Open API. Can't find what you need? Contact your Playbook Success Coach.
POST /open-api/auth/user-tokens/ and automatically filters every response to a single end-user's records. User-scoped tokens expire after 1 hour by default (max 8 hours) and are designed for member-facing applications where you want each user to see only their own data.is_test: true when minting a token to issue a sandbox token. Every write request authenticated by a sandbox token runs full server-side validation — registration rules, payment logic, waiver requirements — but produces no database changes, charges, or notification emails. You can also add the X-Open-API-Dry-Run: true header on any individual write request to sandbox just that call without changing the token.task_id immediately so your application stays responsive. Poll GET /open-api/tasks/{task_id}/ every 1–2 seconds until status is complete or failed. A completed task includes the full result — registration ID, invoice ID, and any pending waiver IDs that still need to be submitted.limit and offset pagination parameters rather than issuing high-frequency parallel requests. Contact your Technical Implementation team if your integration pattern requires elevated throughput.count (total records matching your filters), next (full URL for the next page, or null if you're on the last page), previous, and results. Control page size with the limit parameter (default: 20) and position with offset. To page through all records, keep following the next URL until it returns null.league_id mean in API responses?league_id is the internal identifier for your organization's tenant in the Playbook platform. It appears in response objects to confirm which tenant the data belongs to. You never need to pass it in requests — your Bearer token determines tenant scope automatically. If you call GET /open-api/auth/whoami/ you can confirm the league_id your token is scoped to.POST /open-api/register/bookable-calendar/) are currently in Beta. They are fully supported in sandbox mode and have been tested against common workflows, but edge cases may exist. We recommend coordinating with the Technical Implementation team before enabling Beta endpoints in a production user flow. Non-Beta endpoints are stable and production-ready.GET /open-api/register/{type}/{id}/fields/ before any write registration. This returns the list of custom fields the specific program requires, including field keys, labels, types, and whether they're required. Pass the answers as a custom_fields object in your registration POST body. Skipping this step will result in a validation error if required fields are missing.POST /open-api/auth/user-tokens/, and pass that token to your client application. The user-scoped token automatically filters all reads to that member's data and can register them into programs, manage their memberships, and submit waivers. Revoke the token on logout via POST /open-api/auth/user-tokens/revoke/.Still have questions?
Our Technical Implementation team is available to help with any integration questions not covered here.
Support
Get help with your integration or escalate a technical issue. All API access is set up through your Playbook Success Coach.
Success Coach
Your Playbook Success Coach is your primary point of contact for API access setup, integration planning, and coordinating with our Technical Implementation team. Reach out at customersuccess@callplaybook.com to get started.
Technical Implementation
For complex integrations, our Technical Implementation team can join a call to review your architecture, help you reach production faster, and connect you with our sales team.
API Reference
Browse all 48 endpoints, request and response schemas, and parameter definitions in the full API Reference section of this portal.
View API reference →Tutorials
Step-by-step guides for authentication, registration, scheduling, payment sync, and membership lifecycle management.
Browse tutorials →When to contact us
Getting started
To request API credentials, set up your first integration, or provision a QA environment — start with your Playbook Success Coach.
Production issues
For unexpected errors, authentication failures, or data discrepancies in production, contact your Success Coach and include the endpoint path, relevant request details, and any task IDs or error messages.
Feature requests
Have a use case the current API doesn't support? Let your Success Coach know — our Technical Implementation team reviews integration feedback regularly.
Tutorials
Step-by-step walkthroughs for the most common integration scenarios. Contact your Playbook Success Coach to schedule a hands-on session with our Technical Implementation team.
Authenticate and make your first API call
Get your Bearer token from your Playbook Success Coach, verify your identity with whoami, and call the health endpoint to confirm everything is working end-to-end.
Register a participant in a program
Discover available programs, fetch required registration fields, create a user-scoped token, and submit a registration — then poll the async task until completion.
IntermediatePull a member's schedule and event feed
Use a user-scoped token to retrieve the authenticated member's upcoming games, practices, and class sessions filtered by date range.
BeginnerSync payment and invoice data to an external system
Use the invoices, payments, and credits endpoints to export financial records to your accounting software or data warehouse with pagination and date filters.
IntermediateBook a rental timeslot for a member
Query the bookable calendar for available slots, check membership eligibility, and submit a booking request. Covers dry-run validation and async task polling.
Intermediate · BetaManage membership lifecycle
Read permission flags on a membership object and call the pause, resume, and cancel endpoints based on the member's request and league-configured rules.
IntermediateNeed a custom integration walkthrough?
Our Technical Implementation team can guide you through your specific use case on a setup call.