VolunteerReminder API v1.0.0

REST API for VolunteerReminder — automated volunteer shift reminders by email, SMS, and calendar invite. Authentication: pass an API key as `Authorization: Bearer vrk_…` on every endpoint except the public `GET /pricing` and `POST /signups`. Keys are issued from the account security screen and carry scopes (`read`, `schedules:write`, `contacts:write`, `reminders:write`, `keys:manage`). Safety: agent-created accounts start in reminder **test mode** — reminders reroute to the owner's own address until a human flips live sending on from the dashboard. Nothing in this API can enable live sends, mutate billing, change the login email, or delete an account. Errors are always `{ "error": { "code", "message" } }`; branch on `code`.

Base URL: https://volunteerreminder.com · OpenAPI: https://volunteerreminder.com/openapi.json

Prefer machine-readable docs? Request this page with Accept: text/markdown.

Authentication

Send your API key as Authorization: Bearer vrk_… on every endpoint except the ones marked public. A 401 means the key is missing or invalid; a 403 (insufficient_scope) means it lacks a required scope. Errors are always { "error": { "code", "message" } }.

Endpoints

GET /api/v1/account API keyAccount

Get the current account

Plan, entitlements, current reminder mode, and usage vs limits for the account the API key belongs to. Requires the `read` scope.

POST /api/v1/billing/checkout-url API keyBilling

Get a Stripe Checkout URL for the human to complete

Create a Stripe-hosted Checkout session for a named plan/interval and return its URL for the ACCOUNT OWNER to open and pay — the agent never takes payment. Reuses the dashboard's session-creation logic, including the already-subscribed guard and idempotency key. Requires the `read` scope (this endpoint returns a URL and mutates no agent-managed data; the irreversible act, payment, stays with the human — agent-channel §3.4).

GET /api/v1/contacts API keyContacts

List volunteers

All non-deleted contacts on this account's roster, ordered by name. Requires `read`.

POST /api/v1/contacts API keyContacts

Add a volunteer

Add one contact to the roster. Blocked with `validation_error` when the account is already at its plan's volunteer limit (domain/volunteerCap.ts, the same rule the dashboard enforces). Requires `contacts:write`.

POST /api/v1/contacts/bulk API keyContacts

Add volunteers in bulk

Add up to 200 contacts in one call. ALL-OR-NOTHING: if the batch would push the account's active-volunteer count past its plan's limit, or any contact references a `group_id` that doesn't belong to this account, NOTHING is created and a `validation_error` names the limit, the account's current count, or the bad group id. Requires `contacts:write`.

PATCH /api/v1/contacts/{id} API keyContacts

Update a volunteer

Partial update — only the fields present in the body are changed. Requires `contacts:write`.

DELETE /api/v1/contacts/{id} API keyContacts

Remove a volunteer

Soft-deletes the contact (frees a volunteer-cap slot; removes it from any schedule rosters it was on). Requires `contacts:write`.

GET /api/v1/keys API keyKeys

List API keys

List this account's API keys (including revoked ones, so their status is visible). The secret is NEVER returned. Requires the `keys:manage` scope.

POST /api/v1/keys API keyKeys

Mint a new API key

Create a new API key for this account. The requested scopes must be a subset of the calling key's scopes (a key can never widen authority). Requires the `keys:manage` scope. The secret is returned exactly once.

DELETE /api/v1/keys/{id} API keyKeys

Revoke an API key

Soft-revoke one of this account's API keys. Idempotent per key; a revoked key can never authenticate again. Requires the `keys:manage` scope. Returns 404 for an unknown id, an already-revoked key, or another account's key.

GET /api/v1/open-days API keyReminders

Get unfilled slots (who do we still need?)

Wraps domain/openDays.ts (the same logic behind the public sign-up widget): calendar days with no attendable shift yet, plus recurring monthly slots not yet claimed by a schedule. Requires the `read` scope.

GET /api/v1/pricing publicPricing

Get the public plan catalog

Public, unauthenticated plan/pricing/entitlement catalog. The payload an agent comparison-shopping on a user's behalf reads; no API key required.

GET /api/v1/reminder-settings API keyReminders

Get the reminder lead times and channel availability

The account-wide default lead time, any per-job overrides, and which channels (email/SMS) are available on the current plan. Requires the `read` scope.

PUT /api/v1/reminder-settings API keyReminders

Update the reminder lead times

Set the account-wide default lead time and/or a per-job override. Requires the `reminders:write` scope. Fails validation (no writes performed) if neither `global_default` nor `job_override` is provided, if a lead time leaves all three fields at zero, if `job_override.job_id` is not a job on this account, or if `channels.require_sms` is true on a plan without SMS.

DELETE /api/v1/reminder-settings/global-default API keyReminders

Clear the account-wide default reminder

Soft-delete the account-wide default reminder lead time. Returns the updated reminder configuration. 404 if no active default is set. Requires the `reminders:write` scope.

DELETE /api/v1/reminder-settings/job-overrides/{id} API keyReminders

Remove a per-job reminder override

Soft-delete the reminder lead-time override for one job (addressed by JOB id). Returns the updated reminder configuration. 404 if the job has no active override on this account. Requires the `reminders:write` scope.

POST /api/v1/reminders/test API keyReminders

Send a test reminder to the account owner

Send ONE sample reminder to the account OWNER's own email so they can preview what a reminder looks like. It NEVER reaches volunteers — it always targets the owner — so it respects the test-mode safety model trivially. Requires the `reminders:write` scope.

GET /api/v1/schedules API keySchedules

List schedules

All active (non-archived) schedules for the account. Requires the `read` scope.

POST /api/v1/schedules API keySchedules

Create a schedule

Creates a schedule and materializes its upcoming occurrences. Validation mirrors the dashboard's add-schedule form. Requires the `schedules:write` scope.

POST /api/v1/schedules/preview API keySchedules

Preview upcoming occurrence dates for a recurrence config

PURE and side-effect-free: no schedule is read or written. Wraps domain/recurrence.ts + domain/timezone.ts to show the next occurrence dates a recurrence configuration would produce, so an agent can confirm with the human before calling POST /schedules. Requires the `read` scope.

GET /api/v1/schedules/{id} API keySchedules

Get a schedule

Requires the `read` scope.

PATCH /api/v1/schedules/{id} API keySchedules

Update a schedule

Partial update — only send the fields you want to change. Unset fields keep their current value. Recomputes and re-materializes future occurrences when recurrence fields change. Does NOT change the roster: use `POST /schedules/{id}/roster` for that. Requires the `schedules:write` scope.

DELETE /api/v1/schedules/{id} API keySchedules

Archive a schedule

Soft-deletes (archives) the schedule; past reminder history is preserved. Requires the `schedules:write` scope.

GET /api/v1/schedules/{id}/occurrences API keySchedules

List upcoming shifts for a schedule

Occurrences in [from, to] plus the schedule's roster and each date's attendance/exception status. Requires the `read` scope.

POST /api/v1/schedules/{id}/roster API keyContacts

Replace a schedule's roster

Assign contacts to a schedule. REPLACES the schedule's whole roster (matches the dashboard's save-the-form semantics) — send the complete desired set of contact ids, not a delta. Every id must belong to this account or the whole request is rejected. Requires `contacts:write`.

GET /api/v1/send-log API keyReminders

Get recent reminder send outcomes

Recent reminder outcomes merged from the sent log and the dead-letter failure log, newest first. Requires the `read` scope.

POST /api/v1/signups publicSignups

Create an account (pending email verification)

Public, unauthenticated. Creates an inert trial account for the supplied email and sends the owner a verification link — no API key is returned. The human must click the link to activate; agent-created accounts start with reminders in the safe test posture and can never reach real volunteers until a human turns live sending on from the dashboard. Idempotent on a repeat email (same response, no second account) and heavily rate-limited.