REST API

Read, create, and update people in your organisation programmatically. The API returns JSON and is authenticated with a personal access token you generate in the dashboard.

Authentication

Every request is scoped to a single organisation, resolved from the host you call, and authorised with a personal access token sent as a bearer token. The token carries exactly the permissions and division scope of the admin who created it.

  1. In the dashboard, open your account menu → API / MCP.
  2. Under Personal access tokens, give the token a name and click Generate token.
  3. Copy the token immediately — it's only shown once. Revoke it any time from the same page.

Send it in the Authorization header:

curl -H "Authorization: Bearer <token>" \
  https://your-subdomain.cobberhq.com.au/api/v1/people
Base URL: https://<your-subdomain>.cobberhq.com.au/api/v1 (or your custom domain). A token only works against the organisation it was created for. Requests without a valid token return 401 Unauthorized.

Conventions

  • Requests and responses are JSON. Send Content-Type: application/json on writes.
  • Success returns 200 (reads/updates) or 201 (create).
  • Validation failures return 422 with { "error": "validation_failed", "messages": [...] }.
  • A person you can't access returns 404 (never leaks existence).
  • List endpoints paginate with page and per_page (default 100, max 200).
  • In curl examples, always quote URLs that include ? query params. On macOS, zsh treats bare ? as a glob and fails with zsh: no matches found.
GET/api/v1/people

Search and list people you can access. Supports the same filters as the People page — e.g. search, tags, state, membership_status, volunteer_status, donor_status, branch, plus sort/direction.

curl -H "Authorization: Bearer <token>" \
  "https://your-subdomain.cobberhq.com.au/api/v1/people?search=smith&state=QLD&page=1"

Response

{
  "total_count": 128,
  "page": 1,
  "per_page": 100,
  "people": [
    {
      "id": 42,
      "url": "https://your-subdomain.cobberhq.com.au/dashboard/people/42",
      "name": "Jane Smith",
      "email": "jane@example.com",
      "mobile_phone": "+61 400 000 000",
      "suburb": "Brisbane",
      "state": "QLD",
      "tags": "member,volunteer",
      "membership_status": "Active",
      "volunteer_status": "active"
    }
  ]
}
GET/api/v1/people/:id

Full detail for one person, including address, electorates, tags, custom fields, email preferences, all email addresses, and recent activity.

curl -H "Authorization: Bearer <token>" \
  https://your-subdomain.cobberhq.com.au/api/v1/people/42

Response (abridged)

{
  "id": 42,
  "first_name": "Jane",
  "last_name": "Smith",
  "display_name": "Jane Smith",
  "residential_suburb": "Brisbane",
  "residential_state": "QLD",
  "tags": "member,volunteer",
  "custom_fields": { "party_membership": "Member" },
  "email_preferences": { "newsletters": true, "events": false },
  "volunteer_status": "active",
  "membership_status": "Active",
  "emails": [
    { "id": 55, "email": "jane@example.com", "primary": true, "unsubscribed": false, "bounced": false }
  ],
  "recent_actions": [
    { "type": "donation_made", "at": "2026-02-01T03:12:00Z", "details": { "amount": "50.0" } }
  ]
}
POST/api/v1/people

Create a person. Provide email to set their primary email address. You can set contact fields, tags, volunteer_status, custom_fields, and email_preferences in the same call.

curl -X POST \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  https://your-subdomain.cobberhq.com.au/api/v1/people \
  -d '{
    "first_name": "Jane",
    "last_name": "Smith",
    "email": "jane@example.com",
    "tags": "member,volunteer",
    "custom_fields": { "party_membership": "Member" },
    "email_preferences": { "newsletters": true, "events": false }
  }'

Returns 201 with the created person in the same shape as Get a person.

PATCH/api/v1/people/:id

Update a person. Only the fields you include change. Notable fields:

  • email_preferences — an object of category => boolean for your organisation's email categories. When provided, the keys you send are merged into the person's existing preferences (other categories are kept). Omit it to leave preferences untouched.
  • unsubscribe_all_emailstrue unsubscribes every email address on the record.
  • custom_fields — when provided, the keys you send are merged into the person's existing custom fields (other keys are kept). Omit it to leave custom fields untouched. Only keys that have been set appear on a person's custom_fields in responses — use Custom field definitions to discover valid keys.
  • volunteer_status — one of interested, active, inactive, or core_team.
  • emails — array of { id?, email, primary?, remove? } to add/update/remove addresses.
curl -X PATCH \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  https://your-subdomain.cobberhq.com.au/api/v1/people/42 \
  -d '{
    "tags": "member,volunteer,lapsed",
    "email_preferences": { "newsletters": false },
    "unsubscribe_all_emails": true
  }'

Returns 200 with the updated person.

GET/api/v1/custom_fields

Lists your organisation's person custom field definitions — the valid field_key values, labels, types, and select options. Use this to discover which custom fields exist before reading or writing people. A person's custom_fields object in GET responses only includes keys that have been set at least once on that record, so older people won't show fields added later until a value is written.

curl -H "Authorization: Bearer <token>" \
  https://your-subdomain.cobberhq.com.au/api/v1/custom_fields

Response

{
  "groups": [
    {
      "name": "Custom Fields",
      "description": null,
      "fields": [
        {
          "field_key": "party_membership",
          "label": "Party Membership",
          "field_type": "select",
          "required": false,
          "options": ["None", "Member"]
        }
      ]
    }
  ]
}
POST/api/v1/payments

Record a payment captured outside the online (Stripe) flow — a cash or cheque donation, EFTPOS at a stall, or a merchandise sale. It is stored as a succeeded payment and appears in the Finances report and on the person's profile, just like an online payment. Requires the finances.read permission.

Fields:

  • person_id — required; the person the payment is attributed to (must be one you can access).
  • amount — required; a positive decimal.
  • payment_methodcash, cheque, bank_transfer, or other.
  • payment_typedonation (default) or other (e.g. merch).
  • received_on — optional date the money was received (defaults to today); the payment is dated to this.
  • description, reason, tax_deductible — optional.
curl -X POST \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  https://your-subdomain.cobberhq.com.au/api/v1/payments \
  -d '{
    "person_id": 42,
    "amount": "50.00",
    "payment_method": "cash",
    "payment_type": "donation",
    "received_on": "2026-02-01",
    "description": "Cash donation at the branch stall"
  }'

Response

{
  "id": 918,
  "person_id": 42,
  "amount": "50.0",
  "payment_type": "donation",
  "payment_method": "cash",
  "status": "succeeded",
  "processed_at": "2026-02-01T00:00:00Z",
  "metadata": { "manual_entry": true, "created_by_admin": "you@example.com" }
}

MCP (AI assistants)

The same data is available to AI assistants over the Model Context Protocol. Point an MCP client (Claude, ChatGPT, etc.) at https://<your-subdomain>.cobberhq.com.au/mcp and it will walk you through signing in. See API / MCP in the dashboard for client-by-client setup.