<apiKey>\n<siteID> — the plugin splits it and reports a configuration error before any request if it is malformed.
- Credentials travel in the query string, not a header. Every route takes
apiKeyandsiteIDas query parameters; there is no bearer token. The plugin adds both to every call, so a bare key is rejected up front rather than failing with an obscure 404. InsertEventis the exception. It carries the credentials in the body asAPIKeyandSiteID, which the plugin fills in from the same packed key. The query still holds them, but the body’s copy is what the route reads.- A bad key is usually a 400. Some malformed keys get a plain 401, but WaiverFile normally answers
{"Message":"Invalid"}(orInvalidService…fromPing) with HTTP 400 for a wrong key or a site the key does not belong to — the same status as a genuine validation failure. The plugin reads the message to tell them apart, so a credential problem is reported as an auth error and a real 400 stays a validation error. - Errors have no code. The body is
{"Message": "..."}with a capital M. There is nothing else to branch on, which is why the handlers rely on the status plus that one message. - A missing route is also a 404. Because everything is addressed by query parameter, a 404 means the path is wrong rather than the object missing — a misspelled endpoint reads exactly like a deleted waiver.
pageIndexconventions differ. The waiver lists (waivers.list,waivers.listLite) are zero-based and cappageSizeat 500.waivers.datais one-based and allows up to 1000. Getting this wrong silently returns the wrong page, so each schema documents and enforces its own.consolidateParticipantsis reserved. The API accepts it and ignores it; rows still come back one per participant.- Two deletes are not
DELETE.events.deleteis aGET /DeleteEventandeventCategories.deleteis aPOST /DeleteEventCategory— so neither is safe to replay on a timeout, despite one looking like a read. - Three serialisations, one shape. Events, forms, categories and the site come back as serialised .NET objects (lowerCamelCase columns under
me); the waiver reads come back as XML converted to JSON, with every value a string ("true","0") and a single item sent as an object instead of an array;Ping, the counts and the webhook routes answer bare values. The plugin flattens all of them into the PascalCase names the reference uses (WaiverID,WaiverEventID,Name) and always returns lists as arrays. Participants on the waiver reads keep WaiverFile’s spellingParticpants;events.waiversuses standard JSON, so there they areParticipantsand booleans are real booleans. events.inviteManagersalways sends both optional parameters. The route 404s unlessmanagerEmailMessageandskipSendingEmailIfAccountExistsare present, so the plugin sends an empty message andfalsewhen they are omitted. Withfalse, every address is emailed.- There is no single-event read. The v1 API has no
GetEventroute; read an event throughevents.byDateRange,events.byCategoryor the answer of the write you just made. events.updatereplaces the attached forms. OmittingwaiverFormIDs, or sending an empty list, attaches every active form; pass the event’s current form IDs to keep them. Send the empty GUID aseventCategoryIDfor no category.- The webhook triggers are path segments. Subscribing is
POST /subscribe/<trigger>?targetUrl=…and unsubscribing isDELETE /deletesubscribe/<trigger>with the same URL, one route per trigger. The twelve triggers arenewwaiver,newevent,newcheckin,newqrscan,newbookingcheckin,bookingcheckinundone,bookingcheckedin,newmembercheckin,membercheckinundone,editwaiver,editeventandeditcheckin. There is no signing secret, so the receiving host verifies by its own means. - A waiver PDF is a file, not JSON.
waivers.pdfdownloads the bytes directly and returns them base64-encoded incontent, with the content type and the real byte length. - A waiver holds personal data. Date of birth, email and phone are on the record, so the plugin never writes them to the event log. It does log identifiers (waiver, event and category IDs), counts, byte counts and flags, the site, event and category names, and a webhook target’s origin and path (never its query string). Error messages have the API key removed, because WaiverFile echoes the request URL in some error bodies.
- 31 typed API operations
Setup
1
Install
2
Add the plugin
corsair.ts
multiTenancy: true, scope calls with corsair.withTenant(id). See Quick start for KEK + Hub keys, and Multi-tenancy for account isolation.3
Choose authentication
- API Key (Recommended)
No setup required yet. When you make your first request as a tenant, Corsair prompts for the API key.More: API Key
4
Connect a tenant
Mint a connect link and send the tenant to it. Hub hosts the page and delivers the result to your app — see Connect / OAuth.
Example API calls
Read a signed waiverWhat’s next
API reference
Every
waiverfile.api.* operation with input and output types.Connect / OAuth
createLink, Hub delivery, and tenant connect flows.
Use with agents
Expose this plugin’s operations as MCP tools.