Developers
API reference
Create and look up parties from your own booking form or CRM. Available to Owners with the API access module (Pro plan) - create a key under Settings → API keys.
Base URL
https://mypartyhub.com/api/v1
- served on the platform host only, not on Owner subdomains or custom domains.
Authentication
Send your key as a bearer token:
Authorization: Bearer 12|mph_...
Each key acts as the Owner who created it and only sees that Owner's parties. Keys don't expire. Revoking a key deletes it immediately.
A key stops working (403) while the Owner is suspended or no longer has the API module, for example after dropping to Starter. It works again if access returns.
Scopes
| Scope | Allows |
|---|---|
party:read |
GET /parties, GET /parties/{id} |
party:create |
POST /parties |
rsvp:read |
GET /parties/{id}/rsvps |
document:read |
GET /parties/{id}/documents |
checklist:read |
GET /parties/{id}/checklists |
POST /parties
Creates a draft party. The host (booker) is not emailed; the owner sends their magic link from the party page when ready. Requires party:create.
| Field | Type | Rules |
|---|---|---|
children |
array | required, at least one |
children[].name |
string | required, max 255 |
children[].age |
integer | required, 0–25 |
party_date |
string | required, YYYY-MM-DD, today or later |
start_time |
string | required, HH:MM |
end_time |
string | required, HH:MM, after start_time |
venue_address |
string | optional, max 255 |
venue_name |
string | optional, max 255 |
venue_line1 |
string | optional, max 255 |
venue_city |
string | optional, max 255 |
venue_postcode |
string | optional, max 32 |
venue_country |
string | optional, max 255 |
venue_lat |
number | optional, -90 to 90 |
venue_lng |
number | optional, -180 to 180 |
venue_place_id |
string | optional, max 255 |
special_notes |
string | optional, max 2000 |
booker_name |
string | required, max 255 |
booker_email |
string | required, email |
booker_phone |
string | required, max 40 |
rsvp_contact_name |
string | optional, defaults to booker_name |
rsvp_contact_phone |
string | optional, defaults to booker_phone |
curl -X POST https://mypartyhub.com/api/v1/parties \
-H "Authorization: Bearer 12|mph_..." \
-H "Content-Type: application/json" \
-d '{
"children": [{"name": "Mia", "age": 5}, {"name": "Theo", "age": 7}],
"party_date": "2026-11-14",
"start_time": "14:00",
"end_time": "16:00",
"venue_address": "Old Vic Hall, Bristol",
"booker_name": "Sarah Jones",
"booker_email": "[email protected]",
"booker_phone": "07700 900123"
}'
Returns 201 Created with the party:
{
"data": {
"id": "9d2f6c1e-5b0a-4f7e-9d1c-2a3b4c5d6e7f",
"status": "draft",
"party_date": "2026-11-14",
"start_time": "14:00",
"end_time": "16:00",
"venue_address": "Old Vic Hall, Bristol",
"venue": {
"name": null, "line1": null, "city": null, "postcode": null,
"country": null, "lat": null, "lng": null, "place_id": null
},
"special_notes": null,
"children": [{"name": "Mia", "age": 5}, {"name": "Theo", "age": 7}],
"booker": {"name": "Sarah Jones", "email": "[email protected]", "phone": "07700 900123"},
"rsvp_contact": {"name": "Sarah Jones", "phone": "07700 900123"},
"guest_count": 0,
"booker_link_url": "https://acme.mypartyhub.com/my/auth/…",
"invite_url": null,
"confirmed_at": null,
"created_at": "2026-09-21T10:15:00+00:00",
"updated_at": "2026-09-21T10:15:00+00:00"
}
}
booker_link_url is the host's private sign-in link; treat it like a password. Only this create response includes it.
invite_url stays null until the host confirms the party.
status is one of draft, pending_confirmation, confirmed.
guest_count is the total guests across "yes" RSVPs only - a decline never adds to it.
Requests are not idempotent: retrying a create that timed out can create a second party.
GET /parties
Lists your parties, newest party date first. Requires party:read.
| Query | Notes |
|---|---|
status | draft, pending_confirmation or confirmed |
date_from | YYYY-MM-DD, party date on or after |
date_to | YYYY-MM-DD, party date on or before |
per_page | 1–100, default 25 |
page | page number, default 1 |
Returns {"data": [...], "links": {...}, "meta": {...}}, where each item has the shape above (without booker_link_url) and meta carries current_page, last_page, per_page and total.
GET /parties/{id}
One party, same shape as above without booker_link_url. Requires party:read. Another Owner's party returns 404.
GET /parties/{id}/rsvps
Lists guest RSVPs on a party, newest first. Requires rsvp:read. Another Owner's party returns 404.
| Query | Notes |
|---|---|
status | yes or no |
per_page | 1–100, default 25 |
page | page number, default 1 |
{
"data": [
{
"id": 42,
"status": "yes",
"guest_name": "Sarah Jones",
"guest_count": 2,
"attendees": ["Sarah Jones", "Tom Jones"],
"notes": "Dairy-free please.",
"created_at": "2026-09-21T10:15:00+00:00",
"updated_at": "2026-09-21T10:15:00+00:00"
}
],
"links": { "...": "..." },
"meta": { "current_page": 1, "last_page": 1, "per_page": 25, "total": 1 }
}
The guest's email is never included, on any plan or scope - an Owner (and by extension their API key) never sees a guest's plaintext email address.
GET /parties/{id}/documents
Lists documents attached to a party, in display order. Requires document:read. Another Owner's party returns 404.
| Query | Notes |
|---|---|
per_page | 1–100, default 25 |
page | page number, default 1 |
{
"data": [
{
"id": "3f2a1b4c-...",
"title": "Party pack",
"description": "Everything you need to know.",
"instruction_text": "Print two copies.",
"display_order": 0,
"file": {
"filename": "party-pack.pdf",
"mime_type": "application/pdf",
"size_bytes": 412000
},
"release_rule": "immediate",
"released_at": null,
"visible_to_host": true,
"created_at": "2026-09-21T10:15:00+00:00",
"updated_at": "2026-09-21T10:15:00+00:00"
}
],
"links": { "...": "..." },
"meta": { "current_page": 1, "last_page": 1, "per_page": 25, "total": 1 }
}
No file download URL is included - the app never exposes direct file URLs, even to the Owner's own account; files are only ever streamed through an authenticated download route. visible_to_host tells you whether the Host can currently see this attachment given its release_rule (immediate, after_confirmation, or checklist_triggered), so you can replicate that gating without re-implementing the rule yourself.
GET /parties/{id}/checklists
Lists checklists assigned to a party, each with its items in section/sort order. Requires checklist:read. Another Owner's party returns 404.
| Query | Notes |
|---|---|
per_page | 1–100, default 25 |
page | page number, default 1 |
{
"data": [
{
"id": "7c1e...",
"name": "Essentials",
"allow_host_items": true,
"allow_host_notes": true,
"allow_host_complete_owner_items": false,
"items": [
{
"id": "9a2f...",
"section_title": "Two weeks before",
"title": "Order the cake",
"description": null,
"responsibility": "booker",
"visibility": "booker",
"due": { "offset": 14, "unit": "days", "direction": "before" },
"link_url": null,
"completed": false,
"completed_at": null,
"completed_by": null,
"notes": null,
"is_booker_added": false
}
],
"assigned_at": "2026-09-21T10:15:00+00:00",
"created_at": "2026-09-21T10:15:00+00:00",
"updated_at": "2026-09-21T10:15:00+00:00"
}
],
"links": { "...": "..." },
"meta": { "current_page": 1, "last_page": 1, "per_page": 25, "total": 1 }
}
responsibility is the raw value (owner, booker or either), not a display name - the app UI shows the owner's business name or the Host's real name instead of these words, but that's a presentation choice; resolve it yourself against the party's own booker_name if you need a display label.
completed_by is owner, booker, or null if not yet completed. Read-only - items can't be created or ticked via the API yet.
Errors
Every error is JSON, whatever Accept header you send.
| Status | When |
|---|---|
| 401 | Missing, invalid or revoked key |
| 403 | Key lacks the scope, API module not enabled, or account suspended |
| 404 | Party not found, or request sent to a non-platform host |
| 422 | Validation failed |
| 429 | Rate limit exceeded |
{
"message": "The party date cannot be in the past.",
"errors": {
"party_date": ["The party date cannot be in the past."]
}
}
Rate limits
60 requests a minute per key. Responses carry X-RateLimit-Limit and X-RateLimit-Remaining; a 429 adds Retry-After (seconds).