Chamber Culture Chamber Culture CRM
Developers

Chamber Data API

Read and write access to a chamber's own data - members, contacts, events, invoices, payments and Hot Deals - plus REST Hooks so a tool can subscribe itself to outbound webhook events. Every API key is scoped to exactly one chamber; there is no cross-tenant surface anywhere in this API. This page and the machine-readable spec below are generated from the same file, so they cannot disagree.

Authenticate

Mint a key from Settings โ†’ Website โ†’ Developers (chamber_admin only). The plaintext key (cck_ + 40 characters) is shown exactly once, at creation. Send it as a bearer token on every request - there is no session and no chamber id in the URL; the key alone determines which chamber's data you see.

GET /api/v1/members HTTP/1.1 Host: crm.yourchamber.example Authorization: Bearer cck_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

Versioning

The API is versioned by URL path segment, as a matter of convention: /api/v1 today. There is no version header and no content negotiation. If a breaking change is ever needed, it ships as /api/v2 while /api/v1 keeps running unchanged - that is a stated engineering convention this team follows, not something the code enforces, so it is a commitment rather than a contractual guarantee.

Permissions (scopes)

Every key carries an explicit list of scopes, chosen when it is minted. Absence means denial - a key with no scopes can do nothing. Calling an endpoint without its scope returns 403 naming the missing scope.

ResourceScopeWhat it allows
Members members:read Read the member roster
Members members:write Create and update members
Contacts contacts:read Read contacts
Contacts contacts:write Create and update contacts, and add subscribers
Events events:read Read events and registrations
Events events:write Create and update events
Deals deals:read Read member deals
Deals deals:write Create and update deals
Invoices invoices:read Read invoices
Invoices invoices:write Create draft invoices and issue them
Payments payments:read Read payments
Payments payments:write Record payments against invoices
Automations hooks:write Let a tool subscribe itself to events (needed for Zapier)

Automations breaks the read/write pairing on purpose - there is no hooks:read. A webhook subscription is configuration, not chamber data, so GET /api/v1/hooks is gated on hooks:write like every other hooks endpoint.

Endpoints

Every list endpoint paginates 100 rows per page under {data, meta}; a single resource returns {data} with no meta. There is no way to delete a chamber, a member, or a financial record through this API - the one delete endpoint removes a webhook subscription, which is how an automation unsubscribes itself.

Members

MethodPathScope requiredWhat it does
GET /api/v1/members members:read List members
POST /api/v1/members members:write Create a member
GET /api/v1/members/search members:read Find a member by email or name
GET /api/v1/members/{member} members:read Get one member
PATCH /api/v1/members/{member} members:write Update a member

Contacts

MethodPathScope requiredWhat it does
GET /api/v1/contacts contacts:read List contacts
POST /api/v1/contacts contacts:write Create a contact
GET /api/v1/contacts/search contacts:read Find a contact by email
PATCH /api/v1/contacts/{contact} contacts:write Update a contact
POST /api/v1/subscribers contacts:write Newsletter opt-in

Events

MethodPathScope requiredWhat it does
GET /api/v1/events events:read List events
POST /api/v1/events events:write Create an event
PATCH /api/v1/events/{event} events:write Update an event
GET /api/v1/events/{event}/registrations events:read List an event's registrations

Invoices

MethodPathScope requiredWhat it does
GET /api/v1/invoices invoices:read List invoices
POST /api/v1/invoices invoices:write Create a draft invoice
POST /api/v1/invoices/{invoice}/issue invoices:write Issue a draft invoice

Payments

MethodPathScope requiredWhat it does
POST /api/v1/invoices/{invoice}/payments payments:write Record a payment against an invoice
GET /api/v1/payments payments:read List payments

Deals

MethodPathScope requiredWhat it does
GET /api/v1/deals deals:read List Hot Deals
POST /api/v1/deals deals:write Create a Hot Deal
PATCH /api/v1/deals/{deal} deals:write Update a Hot Deal

Connection

MethodPathScope requiredWhat it does
GET /api/v1/me none (valid key only) Check the connection

Webhooks

MethodPathScope requiredWhat it does
GET /api/v1/hooks hooks:write List webhook subscriptions
POST /api/v1/hooks hooks:write Subscribe to webhook events
DELETE /api/v1/hooks/{hook} hooks:write Unsubscribe a webhook

Webhooks

Subscribe an external URL from Settings โ†’ Website โ†’ Developers, or programmatically via POST /api/v1/hooks (REST Hooks, above). The signing secret is shown exactly once, at creation.

Event catalog

member.created member.updated contact.created invoice.issued invoice.paid event.registration.created deal.approved

Delivery headers

POST https://your-callback-url X-CC-Event: invoice.paid X-CC-Signature: <hex HMAC-SHA256 of the exact raw request body, keyed with your subscription secret>

A delivery is retried up to 3 times (with backoff) before it counts as one failed delivery against the subscription. After 20 consecutive failed deliveries the subscription auto-deactivates (visible in the Developers card, with the last-failure timestamp); a single successful delivery resets the failure count to zero.

Rate limits

120 requests per minute per API key, across the whole /api/v1 group, and 25,000 requests per key over a rolling 24 hours. A 429 means back off, not retry immediately.

The limits are keyed on the key rather than on your IP address, so an integration behind shared egress (Zapier, a shared web host) has its own budget instead of one shared with every other chamber on that address. If a legitimate sync needs more headroom than the daily ceiling allows, ask and it can be raised.

Errors

StatusMeaningBody
401Missing, malformed or revoked key. No further detail given.{"message": "..."}
403Valid key, missing scope. The message names the scope.{"message": "..."}
404No row with that id in this chamber's own data.{"message": "..."}
422Request validation failed - two distinct shapes depending on the endpoint.{"message", "errors": {field: [...]}} (standard Laravel validation), or {"message"} alone (the hand-built business-rule shape returned only by invoice issue and payment recording)
429Rate limited.{"message": "..."}

Machine-readable spec

Everything on this page is generated from one OpenAPI 3.1 document - import it into Postman, Insomnia, or a codegen tool, or just read it directly.

GET /openapi.json โ†—