DevelopersPointPerson API v1
An organization's own systems read and write its events with a key its admins make. A key acts as the organization, never as a person: every write is made for a roster member and held to the organization's rules as theirs. Refusals are { error, reason }, and reason codes are part of the contract.
Signing in
An admin makes a key on the organization's Integrations tab, with the scopes it needs. It is shown once.
Authorization: Bearer pp_live_…An organization's API key, made by its admins. Pass as Authorization: Bearer pp_live_…; /api/v1 only.
Within v1 an answer may gain fields and a request may gain optional ones; nothing is renamed, removed or made required. A refusal is { error, reason }: branch on reason.
Scopes
events:read | Read events | 3 routes |
events:write | Make, edit and cancel events | 3 routes |
roster:read | Read members and teams | 2 routes |
roster:write | Change members and teams | 8 routes |
rules:read | Read templates, fields and rules | 3 routes |
rules:write | Draft rules and import packs | 3 routes |
rules:publish | Publish rules | 1 route |
Events
GET/api/v1/events
A page of the events the organization governs (made from its templates or linked to its groups), by id
Needs events:readParameters
from | query · string | RFC 3339: events that end at or after it (a series always) |
to | query · string | RFC 3339: events that start before it |
template | query · string | A template's id |
group | query · integer | A group's id |
updated_since | query · string | RFC 3339: events whose history has a line since |
cursor | query · string | next_cursor of the page before |
limit | query · integer | 1 to 100, 50 when absent |
Answers
200 Events · object400 invalid_query, with param401 key_required (no key, or a session's token), invalid_key (revoked, expired or none)402 entitlement_limit_reached: the plan that pays for the organization lapsed403 scope_missing, with scope: the scope the route needs429 rate_limited (10 a second, bursts of 50) or daily_cap (100,000 requests a day; an event write past the organization's 10,000 runs a day); Retry-After says when
POST/api/v1/events
Make an event for a roster member, held to the organization's rules as theirs; counts toward the daily run cap
Needs events:writeParameters
Idempotency-Key | header · string | The same key and body within 24 hours answers the first answer (Idempotent-Replayed: true); another body is 409 idempotency_conflict, and while the first runs, 409 idempotency_in_progress |
Body
As POST /events takes it, without overrides. Fields not listed are taken too.on_behalf_ofrequired | string (uuid) | The public id of a current roster member: they are the event's creator, its rules judge it by their teams, and they are told the key made it |
template_id | string (uuid) | One of the organization's templates; this or group_ids (groups of the organization's the member may share with) is required |
Answers
201 Event · ApiEvent202 Event, held for approval: without the held opt-in, only its id and approval · ApiEvent400 on_behalf_of_required, on_behalf_of_not_member, overrides_not_allowed, invalid_template (a template not the organization's), invalid_group_ids (a group not one of its live groups), unsupported_field (with field: dates, poll, slots, details_pending, template_from_event_id, replaces, series_tag_id, series_group_id, audit_stream_id, extraction_id), and every refusal POST /events answers401 key_required (no key, or a session's token), invalid_key (revoked, expired or none)402 entitlement_limit_reached: the plan that pays for the organization lapsed403 scope_missing, with scope: the scope the route needs409 idempotency_conflict, idempotency_in_progress422 rule_violation, as POST /events429 rate_limited (10 a second, bursts of 50) or daily_cap (100,000 requests a day; an event write past the organization's 10,000 runs a day); Retry-After says when
GET/api/v1/events/{id}
One event the organization governs
Needs events:readParameters
Answers
200 Event · ApiEvent401 key_required (no key, or a session's token), invalid_key (revoked, expired or none)402 entitlement_limit_reached: the plan that pays for the organization lapsed403 scope_missing, with scope: the scope the route needs404 event_not_found (also an event held for approval, without the held opt-in)429 rate_limited (10 a second, bursts of 50) or daily_cap (100,000 requests a day; an event write past the organization's 10,000 runs a day); Retry-After says when
PATCH/api/v1/events/{id}
Change the fields named and leave the rest, written as the creator's edit and held to the rules as any edit
Needs events:writeParameters
Body
Any field PUT /events/{id} takes, without overrides. Fields not listed are taken too.Answers
200 Event · ApiEvent202 Event, the change held for approval · ApiEvent400 overrides_not_allowed, invalid_template, invalid_group_ids, and every refusal PUT /events/{id} answers401 key_required (no key, or a session's token), invalid_key (revoked, expired or none)402 entitlement_limit_reached: the plan that pays for the organization lapsed403 scope_missing, with scope: the scope the route needs404 event_not_found429 rate_limited (10 a second, bursts of 50) or daily_cap (100,000 requests a day; an event write past the organization's 10,000 runs a day); Retry-After says when
POST/api/v1/events/describe
What the create screen holds for on_behalf_of, as POST /events/describe answers it
Needs events:readBody
on_behalf_ofrequired | string (uuid) | The public id of a current roster member: they are the event's creator, its rules judge it by their teams, and they are told the key made it |
Answers
200 As POST /events/describe400 on_behalf_of_required, on_behalf_of_not_member, overrides_not_allowed, invalid_template (a template not the organization's), invalid_group_ids (a group not one of its live groups), unsupported_field (with field: dates, poll, slots, details_pending, template_from_event_id, replaces, series_tag_id, series_group_id, audit_stream_id, extraction_id), and every refusal POST /events answers401 key_required (no key, or a session's token), invalid_key (revoked, expired or none)402 entitlement_limit_reached: the plan that pays for the organization lapsed403 scope_missing, with scope: the scope the route needs429 rate_limited (10 a second, bursts of 50) or daily_cap (100,000 requests a day; an event write past the organization's 10,000 runs a day); Retry-After says when
POST/api/v1/events/{id}/cancel
Cancel an event, as its creator would
Needs events:writeParameters
idrequired | path · integer | |
Idempotency-Key | header · string | The same key and body within 24 hours answers the first answer (Idempotent-Replayed: true); another body is 409 idempotency_conflict, and while the first runs, 409 idempotency_in_progress |
Answers
200 Event · ApiEvent401 key_required (no key, or a session's token), invalid_key (revoked, expired or none)402 entitlement_limit_reached: the plan that pays for the organization lapsed403 scope_missing, with scope: the scope the route needs404 event_not_found409 already_cancelled429 rate_limited (10 a second, bursts of 50) or daily_cap (100,000 requests a day; an event write past the organization's 10,000 runs a day); Retry-After says when
Members and teams
GET/api/v1/members
The roster, as GET /organizations/{id}/members
Needs roster:readAnswers
200 As GET /organizations/{id}/members401 key_required (no key, or a session's token), invalid_key (revoked, expired or none)402 entitlement_limit_reached: the plan that pays for the organization lapsed403 scope_missing, with scope: the scope the route needs429 rate_limited (10 a second, bursts of 50) or daily_cap (100,000 requests a day; an event write past the organization's 10,000 runs a day); Retry-After says when
POST/api/v1/members
Add an address to the roster, or invite it to a community organization, as POST /organizations/{id}/members
Needs roster:writeParameters
Idempotency-Key | header · string | The same key and body within 24 hours answers the first answer (Idempotent-Replayed: true); another body is 409 idempotency_conflict, and while the first runs, 409 idempotency_in_progress |
Answers
201 As POST /organizations/{id}/members401 key_required (no key, or a session's token), invalid_key (revoked, expired or none)402 entitlement_limit_reached: the plan that pays for the organization lapsed403 scope_missing, with scope: the scope the route needs429 rate_limited (10 a second, bursts of 50) or daily_cap (100,000 requests a day; an event write past the organization's 10,000 runs a day); Retry-After says when
PUT/api/v1/members/{publicId}
Set a member's role, as PATCH /organizations/{id}/members/{publicId}
Needs roster:writeParameters
publicIdrequired | path · string | |
Answers
200 As PATCH /organizations/{id}/members/{publicId}401 key_required (no key, or a session's token), invalid_key (revoked, expired or none)402 entitlement_limit_reached: the plan that pays for the organization lapsed403 scope_missing, with scope: the scope the route needs429 rate_limited (10 a second, bursts of 50) or daily_cap (100,000 requests a day; an event write past the organization's 10,000 runs a day); Retry-After says when
DELETE/api/v1/members/{publicId}
Take a member off the roster
Needs roster:writeParameters
publicIdrequired | path · string | |
Answers
204 Removed401 key_required (no key, or a session's token), invalid_key (revoked, expired or none)402 entitlement_limit_reached: the plan that pays for the organization lapsed403 scope_missing, with scope: the scope the route needs429 rate_limited (10 a second, bursts of 50) or daily_cap (100,000 requests a day; an event write past the organization's 10,000 runs a day); Retry-After says when
GET/api/v1/teams
The teams, as GET /organizations/{id}/teams
Needs roster:readAnswers
200 As GET /organizations/{id}/teams401 key_required (no key, or a session's token), invalid_key (revoked, expired or none)402 entitlement_limit_reached: the plan that pays for the organization lapsed403 scope_missing, with scope: the scope the route needs429 rate_limited (10 a second, bursts of 50) or daily_cap (100,000 requests a day; an event write past the organization's 10,000 runs a day); Retry-After says when
POST/api/v1/teams
Make a team
Needs roster:writeParameters
Idempotency-Key | header · string | The same key and body within 24 hours answers the first answer (Idempotent-Replayed: true); another body is 409 idempotency_conflict, and while the first runs, 409 idempotency_in_progress |
Answers
201 As POST /organizations/{id}/teams401 key_required (no key, or a session's token), invalid_key (revoked, expired or none)402 entitlement_limit_reached: the plan that pays for the organization lapsed403 scope_missing, with scope: the scope the route needs429 rate_limited (10 a second, bursts of 50) or daily_cap (100,000 requests a day; an event write past the organization's 10,000 runs a day); Retry-After says when
PATCH/api/v1/teams/{id}
Rename a team
Needs roster:writeParameters
Answers
200 As PATCH /organizations/{id}/teams/{teamId}401 key_required (no key, or a session's token), invalid_key (revoked, expired or none)402 entitlement_limit_reached: the plan that pays for the organization lapsed403 scope_missing, with scope: the scope the route needs429 rate_limited (10 a second, bursts of 50) or daily_cap (100,000 requests a day; an event write past the organization's 10,000 runs a day); Retry-After says when
DELETE/api/v1/teams/{id}
Delete a team
Needs roster:writeParameters
Answers
200 As DELETE /organizations/{id}/teams/{teamId}401 key_required (no key, or a session's token), invalid_key (revoked, expired or none)402 entitlement_limit_reached: the plan that pays for the organization lapsed403 scope_missing, with scope: the scope the route needs429 rate_limited (10 a second, bursts of 50) or daily_cap (100,000 requests a day; an event write past the organization's 10,000 runs a day); Retry-After says when
PUT/api/v1/teams/{id}/members/{publicId}
Put a member on a team
Needs roster:writeParameters
idrequired | path · string | |
publicIdrequired | path · string | |
Answers
204 On the team401 key_required (no key, or a session's token), invalid_key (revoked, expired or none)402 entitlement_limit_reached: the plan that pays for the organization lapsed403 scope_missing, with scope: the scope the route needs429 rate_limited (10 a second, bursts of 50) or daily_cap (100,000 requests a day; an event write past the organization's 10,000 runs a day); Retry-After says when
DELETE/api/v1/teams/{id}/members/{publicId}
Take a member off a team
Needs roster:writeParameters
idrequired | path · string | |
publicIdrequired | path · string | |
Answers
204 Off the team401 key_required (no key, or a session's token), invalid_key (revoked, expired or none)402 entitlement_limit_reached: the plan that pays for the organization lapsed403 scope_missing, with scope: the scope the route needs429 rate_limited (10 a second, bursts of 50) or daily_cap (100,000 requests a day; an event write past the organization's 10,000 runs a day); Retry-After says when
Templates, fields, rules and packs
GET/api/v1/templates
The organization's templates, as GET /event-templates serves each
Needs rules:readAnswers
200 Templates · array of EventTemplate401 key_required (no key, or a session's token), invalid_key (revoked, expired or none)402 entitlement_limit_reached: the plan that pays for the organization lapsed403 scope_missing, with scope: the scope the route needs429 rate_limited (10 a second, bursts of 50) or daily_cap (100,000 requests a day; an event write past the organization's 10,000 runs a day); Retry-After says when
GET/api/v1/fields
The organization's custom fields
Needs rules:readAnswers
200 As GET /organizations/{id}/fields401 key_required (no key, or a session's token), invalid_key (revoked, expired or none)402 entitlement_limit_reached: the plan that pays for the organization lapsed403 scope_missing, with scope: the scope the route needs429 rate_limited (10 a second, bursts of 50) or daily_cap (100,000 requests a day; an event write past the organization's 10,000 runs a day); Retry-After says when
GET/api/v1/rules
The organization's rules, drafts and published
Needs rules:readAnswers
200 As GET /organizations/{id}/rules401 key_required (no key, or a session's token), invalid_key (revoked, expired or none)402 entitlement_limit_reached: the plan that pays for the organization lapsed403 scope_missing, with scope: the scope the route needs429 rate_limited (10 a second, bursts of 50) or daily_cap (100,000 requests a day; an event write past the organization's 10,000 runs a day); Retry-After says when
POST/api/v1/rules/publish
Publish every draft, as POST /organizations/{id}/rules/publish; read the dry-run first
Needs rules:publishParameters
Idempotency-Key | header · string | The same key and body within 24 hours answers the first answer (Idempotent-Replayed: true); another body is 409 idempotency_conflict, and while the first runs, 409 idempotency_in_progress |
Answers
200 As POST /organizations/{id}/rules/publish401 key_required (no key, or a session's token), invalid_key (revoked, expired or none)402 entitlement_limit_reached: the plan that pays for the organization lapsed403 scope_missing, with scope: the scope the route needs429 rate_limited (10 a second, bursts of 50) or daily_cap (100,000 requests a day; an event write past the organization's 10,000 runs a day); Retry-After says when
GET/api/v1/packs/export
Export a pack of the templates and rules named, saving nothing: the pack named at the version it has, or a new one at version 1
Needs rules:writeParameters
namerequired | query · string | |
template | query · string | A template's id; repeat for more |
rule | query · string | A rule's id; repeat for more |
pack | query · string | The uid of a pack to export the next version of |
Answers
200 Pack · Pack400 name_required, pack_empty401 key_required (no key, or a session's token), invalid_key (revoked, expired or none)402 entitlement_limit_reached: the plan that pays for the organization lapsed403 scope_missing, with scope: the scope the route needs404 pack_item_not_found429 rate_limited (10 a second, bursts of 50) or daily_cap (100,000 requests a day; an event write past the organization's 10,000 runs a day); Retry-After says when
POST/api/v1/packs/import/preview
What importing a pack would do
Needs rules:writeParameters
Idempotency-Key | header · string | The same key and body within 24 hours answers the first answer (Idempotent-Replayed: true); another body is 409 idempotency_conflict, and while the first runs, 409 idempotency_in_progress |
Body
packrequired | Pack | |
mapping | object | By uid: one of the organization's own team, group or endpoint ids, "new" for a new team, or null for nothing. Unmapped, each maps to what an earlier import made, else the one with its name, else (a team) a new one |
keep | array of string (uuid) | For a newer version, the items whose changes are written; all when absent |
Answers
200 Plan · PackPlan400 pack_invalid (with path, the place in the document), pack_mapping_required (with uids), and any refusal an item's own write answers, with the path to the item: too_many_fields, team_name_taken, invalid_field_value, constraint_invalid…401 key_required (no key, or a session's token), invalid_key (revoked, expired or none)402 entitlement_limit_reached: the plan that pays for the organization lapsed403 scope_missing, with scope: the scope the route needs429 rate_limited (10 a second, bursts of 50) or daily_cap (100,000 requests a day; an event write past the organization's 10,000 runs a day); Retry-After says when
POST/api/v1/packs/import
Import a pack as drafts
Needs rules:writeParameters
Idempotency-Key | header · string | The same key and body within 24 hours answers the first answer (Idempotent-Replayed: true); another body is 409 idempotency_conflict, and while the first runs, 409 idempotency_in_progress |
Body
packrequired | Pack | |
mapping | object | By uid: one of the organization's own team, group or endpoint ids, "new" for a new team, or null for nothing. Unmapped, each maps to what an earlier import made, else the one with its name, else (a team) a new one |
keep | array of string (uuid) | For a newer version, the items whose changes are written; all when absent |
Answers
201 Plan · PackPlan400 pack_invalid (with path, the place in the document), pack_mapping_required (with uids), and any refusal an item's own write answers, with the path to the item: too_many_fields, team_name_taken, invalid_field_value, constraint_invalid…401 key_required (no key, or a session's token), invalid_key (revoked, expired or none)402 entitlement_limit_reached: the plan that pays for the organization lapsed403 scope_missing, with scope: the scope the route needs429 rate_limited (10 a second, bursts of 50) or daily_cap (100,000 requests a day; an event write past the organization's 10,000 runs a day); Retry-After says when
Schemas
LocationInput
id | integer | |
name | string | |
address | string | |
latitude | number | |
longitude | number | |
place_id | string | |
provider | string | |
EventTemplate
id | string (uuid) | |
slug | string | |
name | string | |
color | string | |
category_keys | array of string | |
description | string, or null | |
sort_order | integer | |
created_by_public_id | string (uuid), or null | |
group_id | integer, or null | |
organization_id | string (uuid), or null | The organization that owns the template; such a template has no created_by_public_id |
contact | Contact | An organization's template's: whom to ask about its own constraints. Null for any other |
override_teams | array of string (uuid) | An organization's template's: the teams that may override its own constraints (its admins always may) |
custom_fields | array of OrganizationField | An organization's template's: the live fields of its organization, in its order, each of which `fields` carries a `custom.<field id>` pair for — display shown or hidden (hidden with no default until an admin shows or fixes it), a default in the kind's shape, and the constraints the kind takes. Empty for any other template. |
wizard_preset_id | string, or null | |
workflow | string | |
favorite | boolean | |
updated_at | string (date-time) | |
fields | object | |
subtask_defaults | object, or null | |
subtask_noun | SubtaskNoun | |
claim_label | string, or null | Renames the whole-event claim call to action ("I'm in charge of soccer practice"). Null keeps the built-in wording. |
poll_options | integer, or null | |
find_time_window | string, or null | |
series_dates_count | integer, or null | |
TemplateField
displayrequired | one of shown, hidden, locked | |
valuerequired | object, or null | |
required | boolean | event.location, event.notes, and a custom field of any kind but yes_no: the creator must give one |
options | array of LocationInput or string (uuid) | event.location and a custom location field: the only venues it may be, matched by place_id when the venue has one, else by name and address. A custom choice field: the only choice ids it may be, a subset of its live choices |
min | number | event.capacity, event.max_party_size (people), event.duration (minutes): whole numbers. A custom number field: a decimal |
max | number | event.capacity, event.max_party_size (people), event.duration (minutes): whole numbers. On capacity and party size, no limit breaks a max. A custom number field: a decimal |
notice_hours | integer | event.start_time: how far ahead of now an event may start |
weekdays | array of integer | event.start_time: the ISO weekdays (Monday = 1) an event may start on, a timed start read on the event's own timezone |
earliest_start | string (date-time) | Served beside notice_hours: the earliest timed start it allows as of the read, to the minute |
earliest_date | string (date-time) | Served beside notice_hours: the earliest all-day date it allows as of the read, with the server's day of grace |
repeats | array of one of weekly, monthly_weekday | Served beside weekdays that leave a day out: the only repeats that cannot land on one (weekly on allowed days, monthly on the nth of one) |
SubtaskNoun
singular | string | |
plural | string | |
OrganizationField
id | string (uuid) | |
label | string | |
kind | one of text, number, yes_no, choice, date, person, location | |
multiline | boolean | text |
unit | string, or null | number |
multiple | boolean | choice: several may be picked |
help | string, or null | |
visibility | one of everyone, organization | Who reads the value on an event: anyone who may read the event, or the organization's roster and anyone who may update the event |
choices | array of OrganizationFieldChoice | choice: the live choices, in order |
OrganizationFieldChoice
id | string (uuid) | |
label | string | |
ApiEvent
id | integer | |
url | string | |
sequence | integer | |
title | string | |
cancelled | boolean | |
all_day | boolean | |
start | string (date-time) | A timed event's; an all-day event has date instead |
end | string (date-time) | |
date | string (date) | An all-day event's floating date, never an instant |
timezone | string, or null | |
repeats | string, or null | RFC 5545 RRULE |
occurrence | string, or null | |
location | object, or null | |
notes | string, or null | |
template | object, or null | |
groups | array of object | |
custom_fields | array of object | |
approval | one of pending, declined, lapsed, or null | With the held opt-in: null for an event going ahead |
updated_at | string (date-time), or null | When the event's history last had a line |
hosts | array of object | With the hosts opt-in |
attendees | array of object | With the attendees opt-in |
Pack
formatrequired | one of pointperson.pack | |
format_versionrequired | one of 1 | |
uidrequired | string (uuid) | The pack's, kept across exports |
versionrequired | integer | |
namerequired | string | |
description | string, or null | |
exported_from | object | |
teams | array of object | |
groups | array of object | |
webhooks | array of object | |
fields | array of object | |
templates | array of object | Each a uid and the body POST /event-templates takes, every id a uid: token |
rules | array of object | Each a uid and the body POST /organizations/{id}/rules takes, every id a uid: token |
PackPlan
pack | object | |
teams | array of object | |
groups | array of object | |
webhooks | array of object | |
fields | array of object | |
templates | array of object | |
rules | array of object | |
mapping_required | array of string (uuid) | Teams and groups a condition or an approval names that map to nothing |
Contact
user | object | |
team | object | |
admins | boolean | |
note | string | |
Error