Reference
Organiser
Your own events: attendance, external sales, ticket lists and the door scanner.
Your own events: attendance, external sales and the door scanner.
GET/events/{id}/attendance
Attendance of your event
How many people said "Ik ga", how many marked interest and how many tickets were sold through PartyPPL, exact; and who is coming as groups (returning, province, age, genres), never a group under ten. Only for events of the token's own organisation.
Parameters
| Name | In | Type | Default | Description |
|---|---|---|---|---|
id required | path | string | - | The id of the resource. Events also accept their slug. |
Example request
curl -s "https://api.partyppl.nl/v1/events/oost-sat/attendance" \
-H "Authorization: Bearer $PPL_TOKEN"const res = await fetch("https://api.partyppl.nl/v1/events/oost-sat/attendance", {
headers: {
Authorization: `Bearer ${process.env.PPL_TOKEN}`,
},
});
if (!res.ok) throw new Error((await res.json()).error.message);
const { data, meta } = await res.json();import os
import requests
res = requests.get(
"https://api.partyppl.nl/v1/events/oost-sat/attendance",
headers={"Authorization": f"Bearer {os.environ['PPL_TOKEN']}"},
timeout=30,
)
res.raise_for_status()
payload = res.json()Show the example response
{
"data": {
"ok": true,
"eventId": "oost-sat",
"counts": {
"going": 412,
"interested": 88,
"tickets": 260
},
"audience": {
"computed_at": 1790000000,
"min_cell": 10,
"total": 520,
"returning": 185,
"new": 335,
"returning_share": 36,
"regions": {
"rows": [
{
"key": "Noord-Holland",
"count": 290
},
{
"key": "Utrecht",
"count": 95
}
],
"other": 105,
"hidden": 4
},
"ages": {
"rows": [
{
"key": "21-24",
"count": 180
},
{
"key": "25-29",
"count": 150
}
],
"other": 160,
"hidden": 3
},
"genres": {
"rows": [
{
"key": "Techno",
"count": 310
}
],
"other": null,
"hidden": 0
}
}
},
"meta": {
"request_id": "9f1c2b4a-7e3d-4a10-9c2f-6b8d1e5a0c33"
}
}Statuses
200Attendance of your event400The request is wrong.error.details.paramsnames every bad parameter.401No token, or a token we do not know.403The token is valid but does not carry theattendancescope, or the organisation is suspended.404No such resource.429Over the per-minute limit or the daily quota.Retry-Aftersays how long to wait.500Something went wrong on our side. Quoterequest_id.
GET/events/{id}/external-sales
Read the external sales count
The number of tickets you last reported as sold through your own shop for this event.
Parameters
| Name | In | Type | Default | Description |
|---|---|---|---|---|
id required | path | string | - | The id of the resource. Events also accept their slug. |
Example request
curl -s "https://api.partyppl.nl/v1/events/oost-sat/external-sales" \
-H "Authorization: Bearer $PPL_TOKEN"const res = await fetch("https://api.partyppl.nl/v1/events/oost-sat/external-sales", {
headers: {
Authorization: `Bearer ${process.env.PPL_TOKEN}`,
},
});
if (!res.ok) throw new Error((await res.json()).error.message);
const { data, meta } = await res.json();import os
import requests
res = requests.get(
"https://api.partyppl.nl/v1/events/oost-sat/external-sales",
headers={"Authorization": f"Bearer {os.environ['PPL_TOKEN']}"},
timeout=30,
)
res.raise_for_status()
payload = res.json()Show the example response
{
"data": {
"ok": true,
"eventId": "oost-sat",
"external": true,
"sold": 340,
"updatedAt": 1758499200
},
"meta": {
"request_id": "9f1c2b4a-7e3d-4a10-9c2f-6b8d1e5a0c33"
}
}Statuses
200Read the external sales count400The request is wrong.error.details.paramsnames every bad parameter.401No token, or a token we do not know.403The token is valid but does not carry theattendancescope, or the organisation is suspended.404No such resource.429Over the per-minute limit or the daily quota.Retry-Aftersays how long to wait.500Something went wrong on our side. Quoterequest_id.
POST/events/{id}/external-sales
Report the external sales count
Tell us how many tickets your own shop has sold for this event, so the event page and your dashboard can show the real number. Only for events with external ticketing.
Parameters
| Name | In | Type | Default | Description |
|---|---|---|---|---|
id required | path | string | - | The id of the resource. Events also accept their slug. |
Body (JSON)
| Name | Type | Default | Description |
|---|---|---|---|
sold required | integer0..10000000 | - | Tickets sold so far, a whole number of 0 or more. |
Example request
curl -s -X POST "https://api.partyppl.nl/v1/events/oost-sat/external-sales" \
-H "Authorization: Bearer $PPL_TOKEN" \
-H "Content-Type: application/json" \
-d '{"sold":340}'const res = await fetch("https://api.partyppl.nl/v1/events/oost-sat/external-sales", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.PPL_TOKEN}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"sold": 340
}),
});
if (!res.ok) throw new Error((await res.json()).error.message);
const { data, meta } = await res.json();import os
import requests
res = requests.post(
"https://api.partyppl.nl/v1/events/oost-sat/external-sales",
headers={"Authorization": f"Bearer {os.environ['PPL_TOKEN']}"},
json={
"sold": 340,
},
timeout=30,
)
res.raise_for_status()
payload = res.json()Show the example response
{
"data": {
"ok": true,
"eventId": "oost-sat",
"external": true,
"sold": 340,
"updatedAt": 1758499200
},
"meta": {
"request_id": "9f1c2b4a-7e3d-4a10-9c2f-6b8d1e5a0c33"
}
}Statuses
200Report the external sales count400The request is wrong.error.details.paramsnames every bad parameter.401No token, or a token we do not know.403The token is valid but does not carry theattendancescope, or the organisation is suspended.404No such resource.409This event does not use external ticketing.429Over the per-minute limit or the daily quota.Retry-Aftersays how long to wait.500Something went wrong on our side. Quoterequest_id.
POST/scan
Scan a ticket at the door
Validate a ticket QR and mark it used. A refused ticket comes back as 200 with ok false and a reason, because the door needs the reason on screen; only a broken request is an error. Same rules as the door page in the organiser portal.
Body (JSON)
| Name | Type | Default | Description |
|---|---|---|---|
code required | string | - | The ticket code, or the whole scanned URL containing /t/<code>. |
eventId optional | string | - | Refuse tickets that are not for this event. Leave it out to accept any ticket of your organisation. |
Example request
curl -s -X POST "https://api.partyppl.nl/v1/scan" \
-H "Authorization: Bearer $PPL_TOKEN" \
-H "Content-Type: application/json" \
-d '{"code":"PPL-A1B2-C3D4-E5F6","eventId":"oost-sat"}'const res = await fetch("https://api.partyppl.nl/v1/scan", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.PPL_TOKEN}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"code": "PPL-A1B2-C3D4-E5F6",
"eventId": "oost-sat"
}),
});
if (!res.ok) throw new Error((await res.json()).error.message);
const { data, meta } = await res.json();import os
import requests
res = requests.post(
"https://api.partyppl.nl/v1/scan",
headers={"Authorization": f"Bearer {os.environ['PPL_TOKEN']}"},
json={
"code": "PPL-A1B2-C3D4-E5F6",
"eventId": "oost-sat",
},
timeout=30,
)
res.raise_for_status()
payload = res.json()Show the example response
{
"data": {
"ok": true,
"status": "ok",
"title": "Jesse · Regular",
"sub": "Gescand 23:14",
"type": "Regular",
"holder": "Jesse",
"eventId": "oost-sat",
"scannedAt": 1758499200
},
"meta": {
"request_id": "9f1c2b4a-7e3d-4a10-9c2f-6b8d1e5a0c33"
}
}Statuses
200Scan a ticket at the door400The request is wrong.error.details.paramsnames every bad parameter.401No token, or a token we do not know.403The token is valid but does not carry thescanscope, or the organisation is suspended.429Over the per-minute limit or the daily quota.Retry-Aftersays how long to wait.500Something went wrong on our side. Quoterequest_id.
GET/events/{id}/external-tickets
What became of the delivered tickets
Per event: how many tickets were delivered, how many are on a member's account, how many wait for somebody with that address to log in, and how many still have to be processed (a mail to send). Plus the last twenty deliveries.
Parameters
| Name | In | Type | Default | Description |
|---|---|---|---|---|
id required | path | string | - | The id of the resource. Events also accept their slug. |
Example request
curl -s "https://api.partyppl.nl/v1/events/oost-sat/external-tickets" \
-H "Authorization: Bearer $PPL_TOKEN"const res = await fetch("https://api.partyppl.nl/v1/events/oost-sat/external-tickets", {
headers: {
Authorization: `Bearer ${process.env.PPL_TOKEN}`,
},
});
if (!res.ok) throw new Error((await res.json()).error.message);
const { data, meta } = await res.json();import os
import requests
res = requests.get(
"https://api.partyppl.nl/v1/events/oost-sat/external-tickets",
headers={"Authorization": f"Bearer {os.environ['PPL_TOKEN']}"},
timeout=30,
)
res.raise_for_status()
payload = res.json()Show the example response
{
"data": {
"ok": true,
"eventId": "oost-sat",
"counts": {
"delivered": 340,
"linked": 212,
"pending": 128,
"todo": 0
},
"batches": [
{
"id": "xb_2a91f0c4e3b7d8a1f6c2",
"source": "eventix",
"via": "api",
"received": 340,
"added": 340,
"duplicates": 0,
"refused": 0,
"linked": 212,
"createdAt": 1758499200
}
]
},
"meta": {
"request_id": "9f1c2b4a-7e3d-4a10-9c2f-6b8d1e5a0c33"
}
}Statuses
200What became of the delivered tickets400The request is wrong.error.details.paramsnames every bad parameter.401No token, or a token we do not know.403The token is valid but does not carry theticketsscope, or the organisation is suspended.404No such resource.429Over the per-minute limit or the daily quota.Retry-Aftersays how long to wait.500Something went wrong on our side. Quoterequest_id.
POST/events/{id}/external-tickets
Deliver the ticket list of your own shop
Hand over the tickets another shop (Eventix, Paylogic, Ticketmaster, your own) sold for this event, so each one lands on the PartyPPL account of the person who bought it: the same barcode under Tickets, scannable at the door, and the buyer listed as going. An address that has no account yet gets one mail saying the ticket is waiting (unless invite is false), and the ticket attaches itself the moment that address logs in. Idempotent on the code: send the same export again and nothing is added twice. Every item is answered separately; only a request that is wrong as a whole is refused. What is kept of an address: an HMAC of it and, until the one mail went out, the address itself.
Parameters
| Name | In | Type | Default | Description |
|---|---|---|---|---|
id required | path | string | - | The id of the resource. Events also accept their slug. |
Body (JSON)
| Name | Type | Default | Description | ||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
source optional | eventix | paylogic | ticketmaster | weezevent | other | "other" | The shop that sold them. Shown on the ticket ("via Eventix") and at the door. | ||||||||||||||||||||||||
invite optional | boolean | true | Whether an address without an account gets the mail that says its ticket is waiting. Members are always notified. | ||||||||||||||||||||||||
items required | object[]max 500 items | - | The tickets, at most 500 per call. Every item comes back in results with its own verdict: added (with whether the address is a member), duplicate (this code was delivered before for this event) or refused with the reason. | ||||||||||||||||||||||||
Fields of one item:
| |||||||||||||||||||||||||||
Example request
curl -s -X POST "https://api.partyppl.nl/v1/events/oost-sat/external-tickets" \
-H "Authorization: Bearer $PPL_TOKEN" \
-H "Content-Type: application/json" \
-d '{"source":"eventix","invite":true,"items":[{"email":"jesse@example.com","code":"EVX-8F3K2-91","type":"Early Bird","name":"Jesse Bos","price":27.5}]}'const res = await fetch("https://api.partyppl.nl/v1/events/oost-sat/external-tickets", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.PPL_TOKEN}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"source": "eventix",
"invite": true,
"items": [
{
"email": "jesse@example.com",
"code": "EVX-8F3K2-91",
"type": "Early Bird",
"name": "Jesse Bos",
"price": 27.5
}
]
}),
});
if (!res.ok) throw new Error((await res.json()).error.message);
const { data, meta } = await res.json();import os
import requests
res = requests.post(
"https://api.partyppl.nl/v1/events/oost-sat/external-tickets",
headers={"Authorization": f"Bearer {os.environ['PPL_TOKEN']}"},
json={
"source": "eventix",
"invite": True,
"items": [
{
"email": "jesse@example.com",
"code": "EVX-8F3K2-91",
"type": "Early Bird",
"name": "Jesse Bos",
"price": 27.5,
},
],
},
timeout=30,
)
res.raise_for_status()
payload = res.json()Show the example response
{
"data": {
"ok": true,
"batchId": "xb_2a91f0c4e3b7d8a1f6c2",
"eventId": "oost-sat",
"results": [
{
"index": 0,
"code": "EVX-8F3K2-91",
"status": "added",
"member": true
},
{
"index": 1,
"code": "EVX-8F3K2-92",
"status": "duplicate"
},
{
"index": 2,
"code": "X",
"status": "refused",
"reason": "invalid_code"
}
],
"totals": {
"received": 3,
"added": 1,
"duplicates": 1,
"refused": 1,
"matched": 1
},
"processed": {
"linked": 1,
"mailed": 1,
"skipped": 0,
"failed": 0,
"left": 0,
"budgetOut": false
}
},
"meta": {
"request_id": "9f1c2b4a-7e3d-4a10-9c2f-6b8d1e5a0c33"
}
}Statuses
200Deliver the ticket list of your own shop400The request is wrong.error.details.paramsnames every bad parameter.401No token, or a token we do not know.403The token is valid but does not carry theticketsscope, or the organisation is suspended.404No such resource.429Over the per-minute limit or the daily quota.Retry-Aftersays how long to wait.500Something went wrong on our side. Quoterequest_id.