Developers

ChurchBright REST API & webhooks

Connect your website, connect cards, accounting package or data warehouse to your church account. Simple JSON over HTTPS, keys with fine-grained permissions, and signed real-time webhooks.

Quick start

  1. In your church account open Settings → API & webhooks and create a key. Copy it — it is shown once.
  2. Call the API from your server with the key in the Authorization header.
  3. Add a webhook to be told about changes as they happen instead of polling.

Base URL: https://churchbright.com/api/v1

export CHURCHBRIGHT_API_KEY=cb_live_your_key_here

curl "https://churchbright.com/api/v1/people?per_page=5&status=first_timer" \
  -H "Authorization: Bearer $CHURCHBRIGHT_API_KEY"

Authentication

Every request needs an API key. Keys look like cb_live_ followed by 32 letters and digits. Send it as a bearer token:

Authorization: Bearer cb_live_…

Each key has permissions per resource — for example people:read, people:write, contributions:read or messages:write — and can be limited to one branch and the branches under it. A key limited to a branch only sees and creates records in those branches.

If your tool cannot set headers you may pass ?api_key=… instead, but headers are safer because URLs end up in logs. Keys belong on servers only: never in browser JavaScript, mobile apps or public repositories. Revoke a key the moment you think it has leaked.

Requests & responses

  • Send JSON with Content-Type: application/json (form-encoded bodies also work).
  • Every response is JSON with "ok". Successful responses have "data" (and "meta" for lists).
  • Timestamps are UTC in ISO 8601 (2026-09-28T09:14:03Z). Calendar dates such as given_on or dob are YYYY-MM-DD in the church’s own time zone.
  • Money is an integer in minor units: 150050 means 1,500.50 in the currency given. amount_base is always in the church’s currency.
  • Send an Idempotency-Key header (any unique string up to 120 characters) on POST requests. Retrying with the same key returns the first response instead of creating a duplicate — important for gifts.
{
    "ok": true,
    "data": {
        "id": 42,
        "first_name": "Ngozi",
        "…": "…"
    },
    "meta": {
        "page": 1,
        "per_page": 25,
        "total": 214,
        "total_pages": 9,
        "has_more": true
    }
}

Pagination & filters

Lists return 25 records per page by default. Use ?page= and ?per_page= (up to 100). meta tells you the total and whether there is another page.

To keep another system in sync, remember when you last synced and ask only for what changed since then with ?updated_since=2026-09-01T00:00:00Z. For people, add include_deleted=1 so you also learn about removals.

curl "https://churchbright.com/api/v1/people?updated_since=2026-09-01T00:00:00Z&include_deleted=1&per_page=100&page=2" \
  -H "Authorization: Bearer $CHURCHBRIGHT_API_KEY"

Errors

Errors use normal HTTP status codes and a body with "ok": false, a machine-readable "error" and a human "message". Validation errors add "errors" with one message per field.

StatuserrorMeaning
400invalid_json, invalid_updated_since, invalid_status…The request is malformed — check the message.
401unauthorized, invalid_api_keyNo key, or the key is wrong or revoked.
403insufficient_scope, api_disabled, church_inactive, plan_limit_reachedThe key is valid but not allowed to do this.
404not_found, unknown_resourceThe record does not exist or is outside the key’s branch.
405method_not_allowedThat HTTP method is not supported on this URL.
409duplicate_reference, idempotency_key_reusedConflicts with an earlier request.
422validation_failed, send_failed, recipient_skippedThe data is not valid; "errors" lists each field.
429rate_limitedToo many requests — wait for the Retry-After seconds.
500resource_errorSomething went wrong on our side. Retry later.
{
    "ok": false,
    "error": "validation_failed",
    "message": "Some fields are not valid.",
    "errors": {
        "email": "Enter a valid email address."
    }
}

Rate limits

Each key may make 120 requests per minute (and each IP address 600). Above that you get HTTP 429 with a Retry-After header. Use updated_since and webhooks rather than polling.

Endpoints

Your key

GET /api/v1

Check your key · needs any valid key

Returns the church, the key’s permissions and every resource it can reach. Use it to test your setup.

curl "https://churchbright.com/api/v1" \
  -H "Authorization: Bearer $CHURCHBRIGHT_API_KEY"
Example response
{
    "ok": true,
    "data": {
        "church": {
            "id": 1,
            "name": "Grace Assembly",
            "slug": "grace",
            "country": "NG",
            "currency": "NGN",
            "timezone": "Africa/Lagos"
        },
        "key": {
            "id": 3,
            "name": "Website forms",
            "prefix": "cb_live_Ab3d",
            "scopes": [
                "people:read",
                "people:write"
            ],
            "branch_id": null,
            "created_at": "2026-09-01T10:00:00Z"
        },
        "resources": [
            {
                "name": "people",
                "url": "https://churchbright.com/api/v1/people",
                "allowed": [
                    "read",
                    "write"
                ],
                "module": "core"
            }
        ]
    }
}
People

GET /api/v1/people

List people · needs people:read

Members, visitors and first-timers, oldest first. Deleted people are left out unless include_deleted=1.

Query parameterDescription
statusOne status or a comma list: first_timer, visitor, new_convert, regular, member, worker, leader, inactive, transferred, deceased
branch_idOnly this branch and its sub-branches
family_idOnly this household
qSearch name, email or member number
emailExact email match
phoneExact phone match (any format)
updated_sinceChanged at or after this time (ISO 8601)
created_sinceAdded at or after this time
include_deleted1 to include removed people (with deleted_at set) — useful for syncing
sortid, -id, updated_at, -updated_at, last_name
curl "https://churchbright.com/api/v1/people" \
  -H "Authorization: Bearer $CHURCHBRIGHT_API_KEY"
Example response
{
    "ok": true,
    "data": [
        {
            "id": 42,
            "member_no": "GA-00042",
            "title": "Mrs",
            "first_name": "Ngozi",
            "middle_name": null,
            "last_name": "Okafor",
            "full_name": "Ngozi Okafor",
            "gender": "female",
            "dob": "1988-04-12",
            "marital_status": "married",
            "anniversary": "2012-11-24",
            "email": "ngozi@example.com",
            "phone": "+2348031234567",
            "phone2": null,
            "whatsapp": null,
            "address": "4 Admiralty Way",
            "city": "Lekki",
            "state": "Lagos",
            "country": "NG",
            "postal_code": null,
            "occupation": "Pharmacist",
            "employer": null,
            "status": "member",
            "branch_id": 1,
            "family_id": 7,
            "family_role": "spouse",
            "membership_date": "2019-03-03",
            "baptism_date": null,
            "salvation_date": null,
            "first_visit_date": "2018-11-11",
            "source": "invited",
            "sms_opt_in": true,
            "email_opt_in": true,
            "whatsapp_opt_in": true,
            "photo_url": null,
            "custom": {},
            "created_at": "2026-01-14T09:21:00Z",
            "updated_at": "2026-09-02T17:45:10Z",
            "deleted_at": null
        }
    ],
    "meta": {
        "page": 1,
        "per_page": 25,
        "total": 214,
        "total_pages": 9,
        "has_more": true
    }
}

GET /api/v1/people/{id}

Get a person · needs people:read

curl "https://churchbright.com/api/v1/people/42" \
  -H "Authorization: Bearer $CHURCHBRIGHT_API_KEY"
Example response
{
    "ok": true,
    "data": {
        "id": 42,
        "member_no": "GA-00042",
        "title": "Mrs",
        "first_name": "Ngozi",
        "middle_name": null,
        "last_name": "Okafor",
        "full_name": "Ngozi Okafor",
        "gender": "female",
        "dob": "1988-04-12",
        "marital_status": "married",
        "anniversary": "2012-11-24",
        "email": "ngozi@example.com",
        "phone": "+2348031234567",
        "phone2": null,
        "whatsapp": null,
        "address": "4 Admiralty Way",
        "city": "Lekki",
        "state": "Lagos",
        "country": "NG",
        "postal_code": null,
        "occupation": "Pharmacist",
        "employer": null,
        "status": "member",
        "branch_id": 1,
        "family_id": 7,
        "family_role": "spouse",
        "membership_date": "2019-03-03",
        "baptism_date": null,
        "salvation_date": null,
        "first_visit_date": "2018-11-11",
        "source": "invited",
        "sms_opt_in": true,
        "email_opt_in": true,
        "whatsapp_opt_in": true,
        "photo_url": null,
        "custom": {},
        "created_at": "2026-01-14T09:21:00Z",
        "updated_at": "2026-09-02T17:45:10Z",
        "deleted_at": null
    }
}

POST /api/v1/people

Create a person · needs people:write

first_name is required. Dates use YYYY-MM-DD, phone numbers are converted to international format using the church’s country. Send "dedupe": true to get the existing person back (HTTP 200, meta.duplicate = true) when the email or phone is already on record.

curl -X POST "https://churchbright.com/api/v1/people" \
  -H "Authorization: Bearer $CHURCHBRIGHT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"first_name":"Ngozi","last_name":"Okafor","email":"ngozi@example.com","phone":"0803 123 4567","status":"first_timer","source":"online","dedupe":true}'
Example response
{
    "ok": true,
    "data": {
        "id": 42,
        "member_no": "GA-00042",
        "title": "Mrs",
        "first_name": "Ngozi",
        "middle_name": null,
        "last_name": "Okafor",
        "full_name": "Ngozi Okafor",
        "gender": "female",
        "dob": "1988-04-12",
        "marital_status": "married",
        "anniversary": "2012-11-24",
        "email": "ngozi@example.com",
        "phone": "+2348031234567",
        "phone2": null,
        "whatsapp": null,
        "address": "4 Admiralty Way",
        "city": "Lekki",
        "state": "Lagos",
        "country": "NG",
        "postal_code": null,
        "occupation": "Pharmacist",
        "employer": null,
        "status": "member",
        "branch_id": 1,
        "family_id": 7,
        "family_role": "spouse",
        "membership_date": "2019-03-03",
        "baptism_date": null,
        "salvation_date": null,
        "first_visit_date": "2018-11-11",
        "source": "invited",
        "sms_opt_in": true,
        "email_opt_in": true,
        "whatsapp_opt_in": true,
        "photo_url": null,
        "custom": {},
        "created_at": "2026-01-14T09:21:00Z",
        "updated_at": "2026-09-02T17:45:10Z",
        "deleted_at": null
    }
}

PATCH /api/v1/people/{id}

Update a person · needs people:write

Send only the fields to change. PUT and POST to the same URL work too. Custom fields are merged.

curl -X PATCH "https://churchbright.com/api/v1/people/42" \
  -H "Authorization: Bearer $CHURCHBRIGHT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"status":"member","membership_date":"2026-09-28","custom":{"department":"Choir"}}'
Example response
{
    "ok": true,
    "data": {
        "id": 42,
        "member_no": "GA-00042",
        "title": "Mrs",
        "first_name": "Ngozi",
        "middle_name": null,
        "last_name": "Okafor",
        "full_name": "Ngozi Okafor",
        "gender": "female",
        "dob": "1988-04-12",
        "marital_status": "married",
        "anniversary": "2012-11-24",
        "email": "ngozi@example.com",
        "phone": "+2348031234567",
        "phone2": null,
        "whatsapp": null,
        "address": "4 Admiralty Way",
        "city": "Lekki",
        "state": "Lagos",
        "country": "NG",
        "postal_code": null,
        "occupation": "Pharmacist",
        "employer": null,
        "status": "member",
        "branch_id": 1,
        "family_id": 7,
        "family_role": "spouse",
        "membership_date": "2019-03-03",
        "baptism_date": null,
        "salvation_date": null,
        "first_visit_date": "2018-11-11",
        "source": "invited",
        "sms_opt_in": true,
        "email_opt_in": true,
        "whatsapp_opt_in": true,
        "photo_url": null,
        "custom": {},
        "created_at": "2026-01-14T09:21:00Z",
        "updated_at": "2026-09-02T17:45:10Z",
        "deleted_at": null
    }
}
Families

GET /api/v1/families

List families · needs families:read

Query parameterDescription
qSearch by name
branch_idOnly this branch
updated_sinceChanged since
curl "https://churchbright.com/api/v1/families" \
  -H "Authorization: Bearer $CHURCHBRIGHT_API_KEY"
Example response
{
    "ok": true,
    "data": [
        {
            "id": 7,
            "name": "The Okafor family",
            "address": "4 Admiralty Way, Lekki",
            "phone": null,
            "branch_id": 1,
            "member_count": 4,
            "created_at": "2026-01-14T09:20:00Z",
            "updated_at": null
        }
    ],
    "meta": {
        "page": 1,
        "per_page": 25,
        "total": 88,
        "total_pages": 4,
        "has_more": true
    }
}

GET /api/v1/families/{id}

Get a family with its members · needs families:read

curl "https://churchbright.com/api/v1/families/42" \
  -H "Authorization: Bearer $CHURCHBRIGHT_API_KEY"
Example response
{
    "ok": true,
    "data": {
        "id": 7,
        "name": "The Okafor family",
        "address": "4 Admiralty Way, Lekki",
        "phone": null,
        "branch_id": 1,
        "member_count": 2,
        "created_at": "2026-01-14T09:20:00Z",
        "updated_at": null,
        "members": [
            {
                "id": 41,
                "first_name": "Chinedu",
                "last_name": "Okafor",
                "family_role": "head",
                "status": "worker"
            },
            {
                "id": 42,
                "first_name": "Ngozi",
                "last_name": "Okafor",
                "family_role": "spouse",
                "status": "member"
            }
        ]
    }
}

POST /api/v1/families

Create a family · needs families:write

curl -X POST "https://churchbright.com/api/v1/families" \
  -H "Authorization: Bearer $CHURCHBRIGHT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name":"The Mensah family","address":"12 Allen Avenue, Ikeja","branch_id":2}'
Example response
{
    "ok": true,
    "data": {
        "id": 89,
        "name": "The Mensah family",
        "address": "12 Allen Avenue, Ikeja",
        "phone": null,
        "branch_id": 2,
        "member_count": 0,
        "members": [],
        "created_at": "2026-09-28T08:00:00Z",
        "updated_at": "2026-09-28T08:00:00Z"
    }
}
Branches & funds

GET /api/v1/branches

List branches · needs branches:read

The whole tree: parent_id links a branch to the one above it.

curl "https://churchbright.com/api/v1/branches" \
  -H "Authorization: Bearer $CHURCHBRIGHT_API_KEY"
Example response
{
    "ok": true,
    "data": [
        {
            "id": 1,
            "parent_id": null,
            "depth": 0,
            "name": "Lekki (Headquarters)",
            "code": null,
            "is_hq": true,
            "level": "Headquarters",
            "pastor_name": null,
            "email": null,
            "phone": null,
            "address": null,
            "city": "Lagos",
            "state": null,
            "country": "NG",
            "currency": "NGN",
            "timezone": "Africa/Lagos",
            "status": "active",
            "created_at": "2026-01-01T00:00:00Z",
            "updated_at": null
        }
    ],
    "meta": {
        "page": 1,
        "per_page": 25,
        "total": 4,
        "total_pages": 1,
        "has_more": false
    }
}

GET /api/v1/funds

List funds · needs funds:read

Query parameterDescription
active1 = active funds only, 0 = inactive only
curl "https://churchbright.com/api/v1/funds" \
  -H "Authorization: Bearer $CHURCHBRIGHT_API_KEY"
Example response
{
    "ok": true,
    "data": [
        {
            "id": 1,
            "name": "Tithe",
            "slug": "tithe",
            "description": null,
            "kind": "general",
            "target_amount": null,
            "currency": "NGN",
            "is_online": true,
            "is_default": true,
            "is_active": true,
            "created_at": "2026-01-01T00:00:00Z",
            "updated_at": null
        }
    ],
    "meta": {
        "page": 1,
        "per_page": 25,
        "total": 8,
        "total_pages": 1,
        "has_more": false
    }
}
Contributions

GET /api/v1/contributions

List contributions · needs contributions:read

Amounts are integers in minor units (kobo, cents). meta.sum_amount_base totals every matching gift in the church currency.

Query parameterDescription
fromGiven on or after (YYYY-MM-DD)
toGiven on or before
fund_idOne fund
person_idOne giver
methodcash, bank_transfer, pos, online, ach, cheque, ussd, mobile_money, text, in_kind, other
sourcemanual, online, import, api, …
statusposted (default), void or all
branch_idThis branch and its sub-branches
updated_sinceChanged since
sortid, -id, given_on, -given_on
curl "https://churchbright.com/api/v1/contributions" \
  -H "Authorization: Bearer $CHURCHBRIGHT_API_KEY"
Example response
{
    "ok": true,
    "data": [
        {
            "id": 981,
            "person_id": 42,
            "fund_id": 1,
            "fund_name": "Tithe",
            "branch_id": 1,
            "amount": 5000000,
            "currency": "NGN",
            "amount_display": "₦50,000.00",
            "amount_base": 5000000,
            "method": "bank_transfer",
            "given_on": "2026-09-27",
            "reference": "TRF-88213",
            "note": null,
            "source": "api",
            "payment_id": null,
            "donor_name": null,
            "donor_email": null,
            "donor_phone": null,
            "is_anonymous": false,
            "status": "posted",
            "created_at": "2026-09-27T12:02:11Z",
            "updated_at": "2026-09-27T12:02:11Z"
        }
    ],
    "meta": {
        "page": 1,
        "per_page": 25,
        "total": 1203,
        "total_pages": 49,
        "has_more": true,
        "sum_amount_base": 1843250000,
        "base_currency": "NGN"
    }
}

GET /api/v1/contributions/{id}

Get a contribution · needs contributions:read

curl "https://churchbright.com/api/v1/contributions/42" \
  -H "Authorization: Bearer $CHURCHBRIGHT_API_KEY"
Example response
{
    "ok": true,
    "data": {
        "id": 981,
        "person_id": 42,
        "fund_id": 1,
        "fund_name": "Tithe",
        "branch_id": 1,
        "amount": 5000000,
        "currency": "NGN",
        "amount_display": "₦50,000.00",
        "amount_base": 5000000,
        "method": "bank_transfer",
        "given_on": "2026-09-27",
        "reference": "TRF-88213",
        "note": null,
        "source": "api",
        "payment_id": null,
        "donor_name": null,
        "donor_email": null,
        "donor_phone": null,
        "is_anonymous": false,
        "status": "posted",
        "created_at": "2026-09-27T12:02:11Z",
        "updated_at": "2026-09-27T12:02:11Z"
    }
}

POST /api/v1/contributions

Record a contribution · needs contributions:write

amount is required, in minor units. fund_id defaults to the church’s default fund, given_on to today, method to online. A reference already recorded through the API returns 409. Send an Idempotency-Key header so retries never record a gift twice.

curl -X POST "https://churchbright.com/api/v1/contributions" \
  -H "Authorization: Bearer $CHURCHBRIGHT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"amount":5000000,"fund_id":1,"person_id":42,"method":"bank_transfer","given_on":"2026-09-27","reference":"TRF-88213"}'
Example response
{
    "ok": true,
    "data": {
        "id": 981,
        "person_id": 42,
        "fund_id": 1,
        "fund_name": "Tithe",
        "branch_id": 1,
        "amount": 5000000,
        "currency": "NGN",
        "amount_display": "₦50,000.00",
        "amount_base": 5000000,
        "method": "bank_transfer",
        "given_on": "2026-09-27",
        "reference": "TRF-88213",
        "note": null,
        "source": "api",
        "payment_id": null,
        "donor_name": null,
        "donor_email": null,
        "donor_phone": null,
        "is_anonymous": false,
        "status": "posted",
        "created_at": "2026-09-27T12:02:11Z",
        "updated_at": "2026-09-27T12:02:11Z"
    }
}
Messages

POST /api/v1/messages

Send a message · needs messages:write

channel is sms, email, whatsapp or push. Send to person_id, up to 100 person_ids, or a raw "to" phone number/email. Merge tags like {first_name} work. Opt-outs are respected and SMS units are charged as usual.

curl -X POST "https://churchbright.com/api/v1/messages" \
  -H "Authorization: Bearer $CHURCHBRIGHT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"channel":"sms","person_id":42,"body":"Hi {first_name}, thank you for worshipping with us today!"}'
Example response
{
    "ok": true,
    "data": {
        "id": 5521,
        "person_id": 42,
        "status": "sent",
        "error": null,
        "channel": "sms"
    }
}

GET /api/v1/messages

Message log · needs messages:read

Query parameterDescription
channelsms, email, whatsapp, voice, push
statussent, delivered, failed, skipped
person_idOne person
sourceWhere it came from, e.g. api, followup
updated_sinceChanged since
curl "https://churchbright.com/api/v1/messages" \
  -H "Authorization: Bearer $CHURCHBRIGHT_API_KEY"
Example response
{
    "ok": true,
    "data": [
        {
            "id": 5521,
            "channel": "sms",
            "person_id": 42,
            "to": "+2348031234567",
            "subject": null,
            "body": "Hi Ngozi, thank you for worshipping with us today!",
            "status": "delivered",
            "units": 1,
            "error": null,
            "source": "api",
            "sent_at": "2026-09-28T11:02:00Z",
            "delivered_at": "2026-09-28T11:02:09Z",
            "created_at": "2026-09-28T11:02:00Z"
        }
    ],
    "meta": {
        "page": 1,
        "per_page": 25,
        "total": 5521,
        "total_pages": 221,
        "has_more": true
    }
}
More resources
These resources come from the features your church has switched on. They follow the same authentication, pagination and error rules.

GET /api/v1/prayer_requests

List Prayer requests · needs prayer_requests:read

Provided by the Care & prayer module.

Query parameterDescription
pagePage number
per_pageUp to 100
updated_sinceChanged since (when supported)
curl "https://churchbright.com/api/v1/prayer_requests" \
  -H "Authorization: Bearer $CHURCHBRIGHT_API_KEY"

GET /api/v1/prayer_requests/{id}

Get one Prayer requests record · needs prayer_requests:read

curl "https://churchbright.com/api/v1/prayer_requests/42" \
  -H "Authorization: Bearer $CHURCHBRIGHT_API_KEY"

POST /api/v1/prayer_requests

Create Prayer requests · needs prayer_requests:write

curl -X POST "https://churchbright.com/api/v1/prayer_requests" \
  -H "Authorization: Bearer $CHURCHBRIGHT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '[]'

GET /api/v1/gifts

List Gifts · needs gifts:read

Provided by the Giving module.

Query parameterDescription
pagePage number
per_pageUp to 100
updated_sinceChanged since (when supported)
curl "https://churchbright.com/api/v1/gifts" \
  -H "Authorization: Bearer $CHURCHBRIGHT_API_KEY"

GET /api/v1/gifts/{id}

Get one Gifts record · needs gifts:read

curl "https://churchbright.com/api/v1/gifts/42" \
  -H "Authorization: Bearer $CHURCHBRIGHT_API_KEY"

GET /api/v1/sermons

List Sermons · needs sermons:read

Provided by the Media module.

Query parameterDescription
pagePage number
per_pageUp to 100
updated_sinceChanged since (when supported)
curl "https://churchbright.com/api/v1/sermons" \
  -H "Authorization: Bearer $CHURCHBRIGHT_API_KEY"

GET /api/v1/sermons/{id}

Get one Sermons record · needs sermons:read

curl "https://churchbright.com/api/v1/sermons/42" \
  -H "Authorization: Bearer $CHURCHBRIGHT_API_KEY"

Webhooks

Add endpoints under Settings → API & webhooks → Webhooks and choose the events you want. When one happens we send an HTTPS POST with a JSON body like this:

{
    "id": "evt_5b1c0f3e9a7d44c2b8e1a0f2",
    "event": "person.created",
    "created_at": "2026-09-28T09:14:03Z",
    "api_version": "v1",
    "church": {
        "id": 1,
        "slug": "grace",
        "name": "Grace Assembly"
    },
    "data": {
        "id": 42,
        "member_no": "GA-00042",
        "title": "Mrs",
        "first_name": "Ngozi",
        "middle_name": null,
        "last_name": "Okafor",
        "full_name": "Ngozi Okafor",
        "gender": "female",
        "dob": "1988-04-12",
        "marital_status": "married",
        "anniversary": "2012-11-24",
        "email": "ngozi@example.com",
        "phone": "+2348031234567",
        "phone2": null,
        "whatsapp": null,
        "address": "4 Admiralty Way",
        "city": "Lekki",
        "state": "Lagos",
        "country": "NG",
        "postal_code": null,
        "occupation": "Pharmacist",
        "employer": null,
        "status": "member",
        "branch_id": 1,
        "family_id": 7,
        "family_role": "spouse",
        "membership_date": "2019-03-03",
        "baptism_date": null,
        "salvation_date": null,
        "first_visit_date": "2018-11-11",
        "source": "invited",
        "sms_opt_in": true,
        "email_opt_in": true,
        "whatsapp_opt_in": true,
        "photo_url": null,
        "custom": {},
        "created_at": "2026-01-14T09:21:00Z",
        "updated_at": "2026-09-02T17:45:10Z",
        "deleted_at": null
    }
}

"data" is shaped like the matching REST resource. Update events also include "previous" with the values before the change. Every request carries these headers:

X-ChurchBright-EventThe event name, e.g. person.created
X-ChurchBright-Event-IdUnique per event — store it to ignore duplicates, because a redelivery reuses it.
X-ChurchBright-DeliveryThe delivery attempt id shown in your delivery log.
X-ChurchBright-Signaturet=<unix time>,v1=<HMAC-SHA256 of "<t>.<raw body>" using your signing secret, hex>
  • Answer with any 2xx status within 10 seconds. Do slow work after answering.
  • Anything else is retried 4 more times with growing gaps (2, 4, 8 and 16 minutes). You can redeliver any event from the delivery log.
  • Endpoints that fail 20 deliveries in a row are paused and administrators are notified. Switch them back on once fixed.
  • Use “Send test event” to receive a ping event while you build your endpoint.

Verifying signatures

Compute the HMAC-SHA256 of the timestamp, a dot and the raw request body with your signing secret (the whole whsec_… string), compare it with v1 in constant time, and reject timestamps older than five minutes.

<?php
// Verify a ChurchBright webhook (plain PHP, no libraries needed).
$secret  = getenv('CHURCHBRIGHT_WEBHOOK_SECRET');           // whsec_… from Settings → API & webhooks
$payload = file_get_contents('php://input');                  // the raw body, before json_decode
$header  = $_SERVER['HTTP_X_CHURCHBRIGHT_SIGNATURE'] ?? '';   // "t=1727517600,v1=5f2c…"

$parts = [];
foreach (explode(',', $header) as $item) {
    [$k, $v] = array_pad(explode('=', trim($item), 2), 2, '');
    $parts[$k] = $v;
}
$t = (int)($parts['t'] ?? 0);
$expected = hash_hmac('sha256', $t . '.' . $payload, $secret);

if (!$t || abs(time() - $t) > 300 || !hash_equals($expected, $parts['v1'] ?? '')) {
    http_response_code(400);
    exit('Invalid signature');
}

$event = json_decode($payload, true);
switch ($event['event']) {
    case 'person.created':
        // $event['data'] is the person, shaped like GET /api/v1/people/{id}
        break;
    case 'contribution.recorded':
        // $event['data']['amount'] is in minor units
        break;
}
http_response_code(200); // answer quickly; do slow work in the background
Event catalogue
Core events plus events from the features installed on this platform. Subscribe with exact names or wildcards like person.*
EventFromWhen it is sent
pingCoreSent only when you press “Send test event”.
ai.output_createdBright AIBright AI wrote something in the writing studio (title and template only).
api.key_createdAPI & webhooksAn API key was created (the key itself is never included).
api.key_revokedAPI & webhooksAn API key was revoked.
api.webhook_goneAPI & webhooksEmitted by this feature.
attendance.checkinAttendance & check-inEmitted by this feature.
attendance.children_picked_upAttendance & check-inEmitted by this feature.
attendance.pickup_flaggedAttendance & check-inEmitted by this feature.
attendance.recordedCoreAttendance for a service or meeting was recorded.
automations.run_completedAutomationsA person finished an automation journey (the run and the automation).
billing.downgrade_scheduledPlan & billingEmitted by this feature.
billing.enterprise_enquiryPlan & billingEmitted by this feature.
billing.extras_pausedPlan & billingEmitted by this feature.
billing.extras_restoredPlan & billingEmitted by this feature.
billing.plan_changedPlan & billingEmitted by this feature.
billing.plan_expiredPlan & billingEmitted by this feature.
billing.sms_purchasedPlan & billingEmitted by this feature.
billing.subscription_activatedPlan & billingEmitted by this feature.
care.pathway_completedCare & prayerEmitted by this feature.
care.prayer_request_createdCare & prayerEmitted by this feature.
compete.badge_awardedCompetitionsEmitted by this feature.
compete.quiz_completedCompetitionsEmitted by this feature.
contribution.recordedCoreA gift was recorded — online, manual, imported or via the API.
contribution.voidedCoreA gift was voided.
dashboard.setup_completedDashboardEmitted by this feature.
dashboard.setup_step_doneDashboardEmitted by this feature.
events.checked_inEventsEmitted by this feature.
events.registeredEventsEmitted by this feature.
finance.expense_approvedFinanceEmitted by this feature.
finance.remittance_paidFinanceEmitted by this feature.
followup.guest_capturedFirst-timers & follow-upEmitted by this feature.
followup.stage_changedFirst-timers & follow-upEmitted by this feature.
followup.task_completedFirst-timers & follow-upEmitted by this feature.
forms.submittedFormsEmitted by this feature.
giving.batch_depositedGivingEmitted by this feature.
giving.gift_receivedGivingEmitted by this feature.
giving.pledge_createdGivingEmitted by this feature.
giving.recurring_cancelledGivingEmitted by this feature.
giving.recurring_createdGivingEmitted by this feature.
groups.join_requestedGroups & cellsEmitted by this feature.
groups.member_addedGroups & cellsEmitted by this feature.
groups.members_bulk_addedGroups & cellsEmitted by this feature.
groups.message_postedGroups & cellsEmitted by this feature.
groups.report_submittedGroups & cellsEmitted by this feature.
imports.completedImportsEmitted by this feature.
imports.undoneImportsEmitted by this feature.
integrations.feed_createdIntegrationsA Google Sheets feed was created.
integrations.feed_revokedIntegrationsA Google Sheets feed was revoked.
integrations.hook_subscribedIntegrationsA Zapier or Make trigger subscribed to an event.
integrations.hook_unsubscribedIntegrationsA Zapier or Make trigger unsubscribed.
media.live_endedMediaEmitted by this feature.
media.live_startedMediaEmitted by this feature.
media.sermon_deletedMediaEmitted by this feature.
media.sermon_publishedMediaEmitted by this feature.
media.studio_publishedMediaA sermon studio section (notes, questions or devotional) was published to the sermon page.
media.studio_unpublishedMediaA sermon studio section was taken off the sermon page.
member.app_installedMember appEmitted by this feature.
member.post_publishedMember appEmitted by this feature.
member.push_sentMember appEmitted by this feature.
member.registeredMember appEmitted by this feature.
member.testimony_approvedMember appEmitted by this feature.
member.testimony_submittedMember appEmitted by this feature.
message.sentCoreAn SMS, email, WhatsApp, voice or push message was sent.
messaging.campaign_sentMessagesEmitted by this feature.
messaging.inbox_receivedMessagesEmitted by this feature.
messaging.unsubscribedMessagesEmitted by this feature.
nativeapp.device_registeredNative appsA phone registered for push notifications in the native app.
payment.failedCoreAn online payment failed.
payment.succeededCoreAn online payment succeeded.
people.importedPeopleEmitted by this feature.
person.createdCoreA person was added.
person.deletedCoreA person was removed.
person.mergedCoreTwo duplicate records were merged ("data" is kept, "previous" was removed).
person.mergingPeopleEmitted by this feature.
person.status_changedCoreA person’s status changed, e.g. first-timer → member.
person.tag_addedAutomationsA tag was added to a person (the person and the tag).
person.tag_removedAutomationsA tag was removed from a person (the person and the tag).
person.updatedCoreA person’s details changed ("previous" holds the old values).
platform.announcement_publishedPlatform adminEmitted by this feature.
platform.church_plan_changedPlatform adminEmitted by this feature.
platform.church_status_changedPlatform adminEmitted by this feature.
platform.sender_id_decidedPlatform adminEmitted by this feature.
print.generatedLetters, labels & badgesEmitted by this feature.
reports.emailedReportsAn executive summary was emailed (scheduled or on demand).
school.attendance_closedSunday SchoolA class closed a Sunday school session (the session and the class).
school.promotion_appliedSunday SchoolPromotion Sunday was applied (the promotion and how many moved).
serve.assignment_acceptedServeEmitted by this feature.
site.lead_receivedMarketing siteEmitted by this feature.
user.invitedCoreA team member was invited.
ussd.pay_requestedUSSDEmitted by this feature.
ussd.session_endedUSSDEmitted by this feature.
website.message_receivedWebsiteEmitted by this feature.
website.page_publishedWebsiteEmitted by this feature.
website.template_appliedWebsiteEmitted by this feature.
website.translation_createdWebsiteEmitted by this feature.
x.yAPI & webhooksEmitted by this feature.

Versioning: this is version 1. We add fields and endpoints without notice, so ignore fields you do not know; anything that could break an integration will come as a new version.