> ## Documentation Index
> Fetch the complete documentation index at: https://docs.thefaithapp.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Zapier and Make Automations

> Authenticate scoped automation connections, browse church records, subscribe to documented event payloads, and safely retry actions.

<Note>
  Zapier is available by invitation and remains private. Make is also available
  by invitation while its public directory review is pending. For invitation
  access and church setup, see [Platform, Access and
  Integrations](/product/platform-access-integrations#automate-with-zapier-or-make).
</Note>

Automation connections use dedicated keys created in **Platform > Developers**.
Send the full secret as `X-API-Key`. These keys are different from the public
church API key used by member applications. Keys are bound to a church, have
explicit scopes, and can expire or be revoked. The issuing staff member's
current permissions also limit delegated access.

The production API base URL is `https://api.thefaithapp.com/api/automation/v1`.
All paths below are relative to that base unless shown in full. Send
`Accept: application/json`; JSON writes also use `Content-Type: application/json`.
The church is selected by the key. Do not send a church ID to switch tenants.
The church's plan must include Platform Integrations.

## Verify a Connection

`GET /auth` returns HTTP `200` for an active connection:

```json theme={null}
{
  "data": {
    "id": "5fc07b7b-0f8a-48fa-a027-1dff582e1249",
    "name": "Example Church",
    "key_id": "7dbbccdc-4737-4d97-86ad-ce529e82cb5a",
    "scopes": ["triggers:read", "members:read", "people:write"]
  }
}
```

| Response field | Type | Meaning |
| - | - | - |
| `data.id` | UUID string or `null` | The church's public identifier; a legacy church may not have one |
| `data.name` | string | Church name, suitable for the connection label |
| `data.key_id` | UUID string | Public identifier of the automation key; never the secret |
| `data.scopes` | array of strings | Scopes allowed by both the key and its issuing staff member's current permissions |

This endpoint does not require a trigger or action scope. An expired or revoked
key returns `401`; a church plan without Platform Integrations returns `403`.
Successful authenticated requests update the key's last-used timestamp.

## Browse People, Groups, and Events

These read-only endpoints provide IDs and names for workflow selectors:

| Method and path | Required scope: at least one listed | Records returned |
| - | - | - |
| `GET /options/members` | `members:read` or `people:write` | People in the key's church |
| `GET /options/groups` | `groups:write` | Active community groups in the key's church |
| `GET /options/events` | `events:read` or `events:write` | Events in the key's church |

Each endpoint accepts the same optional query parameters:

| Parameter | Type | Rules |
| - | - | - |
| `search` | string or `null` | Maximum 100 characters; matches the person's/group's name or event title |
| `page` | integer | At least `1`; default `1` |

Results are sorted by name or event title, with up to 100 records per page.
Soft-deleted records are excluded. The events list is a selector, so a listed
event is not a guarantee that registration is available. Registration rules
are checked when an action runs.

For example, `GET /options/members?search=Example&page=1` returns HTTP `200`:

```json theme={null}
{
  "data": [{ "id": 123, "name": "Example Person" }],
  "meta": { "current_page": 1, "has_more": false }
}
```

| Response field | Type | Meaning |
| - | - | - |
| `data` | array | Matching records; empty when there are no matches |
| `data[].id` | integer | Numeric person, group, or church event ID to map into an action |
| `data[].name` | string | Person/group name, or the event title |
| `meta.current_page` | integer | The page returned |
| `meta.has_more` | boolean | Request `page + 1` when `true` |

The same response shape applies to all three endpoints. Unknown resource paths
return `404`; a missing effective scope returns `403`; invalid query parameters
return `422`.

## Connection and Triggers

| Method and path | Purpose |
| - | - |
| `GET /api/automation/v1/auth` | Verify the connection and return its church and effective scopes |
| `GET /api/automation/v1/events?type={type}` | Poll recent events of one allowed trigger type |
| `GET /api/automation/v1/events/{uuid}` | Read one retained event owned by the church, subject to its trigger scopes |
| `POST /api/automation/v1/subscriptions` | Subscribe a public HTTPS target to one trigger |
| `DELETE /api/automation/v1/subscriptions/{uuid}` | Stop a subscription owned by this key |

Supported trigger types are `member.created`, `visitor.created`,
`giving.received`, `event.registration.created`, `prayer.request.created`,
`volunteer.assignment.accepted`, `volunteer.assignment.declined`, and
`form.submitted`. Trigger access requires `triggers:read` and the corresponding
`members:read`, `visitors:read`, `giving:read`, `events:read`, `prayer:read`,
`volunteers:read`, or `forms:read` scope.

Polling returns an array in `data`. Each event has a stable `id` for provider
deduplication and a numeric `cursor_id`. Without `since_id`, results are newest
first. With `since_id`, results are ascending after that cursor. Advance the
cursor only after durable processing. `limit` is at most 100. Events remain
available for the configured retention window, 30 days by default; polling is
not a full historical export.

| Polling query parameter | Type | Rules |
| - | - | - |
| `type` | string | Required; one of the eight supported trigger types |
| `limit` | integer | `1`–`100`; default `100` |
| `since_id` | integer | Optional cursor, at least `0`; use a prior numeric `cursor_id` |
| `event_id` | UUID string | Optional filter for one retained automation event |

The list response also contains `meta.next_cursor` (the largest returned
numeric cursor, or `null` for an empty list) and `meta.retention_days` (integer).
For example:

```json theme={null}
{
  "data": [
    {
      "id": "e317e867-bc2b-4e2b-b23c-8a275ef7cb67",
      "type": "member.created",
      "created_at": "2026-10-08T09:00:00.000Z",
      "data": {
        "member_id": 123,
        "uuid": "7dbbccdc-4737-4d97-86ad-ce529e82cb5a",
        "name": "Example Person",
        "email": "person@example.org",
        "phone": null,
        "source": "admin"
      },
      "cursor_id": 456
    }
  ],
  "meta": { "next_cursor": 456, "retention_days": 30 }
}
```

The optional `event_id` query parameter accepts one UUID and filters this same
list response to that retained event. Use it with `type` for a fixed-path
readback request; a missing or foreign event returns an empty `data` array.
Malformed identifiers return `422`. Make uses this form so incoming webhook
values never become part of its request path.

Create a REST hook with this body:

```json theme={null}
{
  "event_type": "visitor.created",
  "target_url": "https://receiver.example.com/thefaithapp",
  "name": "Visitor welcome"
}
```

The response contains `data.id` and `data.signing_secret`. Store the secret
securely and verify [webhook signatures](/api-reference/platform-access-and-webhooks#verify-a-delivery).
Repeated subscriptions for the same key, event type, and target reuse the
existing subscription. Targets must pass the public HTTPS address checks.
Revoking a key stops its subscriptions and pending deliveries.

The native Make connector uses its dedicated webhook URL and fetches the
canonical event through authenticated event readback before processing it.
Keep that URL private and deduplicate external workflow steps by event ID.
Authenticated readback does not prevent an exposed URL from replaying a known
event. Generic webhook receivers should verify the signed body as described above.

Prayer and form events omit private text and answers. Giving events omit donor
identity. Keep event identifiers when retrying and deduplicate at the receiver.

## Trigger Payload Contracts

All eight trigger types use this common event envelope. The tables below
describe the fields inside its `data` object; they are not additional top-level
fields. Examples on this page are illustrative, not customer records.

| Envelope field | Type | Meaning |
| - | - | - |
| `id` | UUID string | Stable automation event ID, used for deduplication and readback |
| `type` | string | Exact trigger type |
| `created_at` | ISO 8601 date-time string | Time the automation event was recorded |
| `data` | object | The trigger-specific snapshot described below |
| `cursor_id` | integer | Numeric polling cursor, present in `GET /events` list results only |

A webhook delivery contains `id`, `type`, `created_at`, and `data`.
`GET /events/{uuid}` returns that event inside `{"data": {...}}`, without a
`cursor_id`. Polling and the fixed-path `GET /events?type=...&event_id=...`
readback return a list, with `cursor_id` on each event. The automation event
UUID is different from `data.event_id`, which identifies a church event.
Treat each payload as the snapshot recorded when the event was published.

Zapier's instant triggers use the event UUID and signed snapshot. Their setup
samples remove only the list-specific `cursor_id` so they match live webhook
results. The numeric cursor remains available to direct API polling clients.

### New Member: `member.created`

Requires `triggers:read` and `members:read`. Published when a person is created
in a church or assigned to a destination church. Later profile edits do not
replace the original snapshot.

| Data field | Type | Meaning |
| - | - | - |
| `member_id` | integer | Numeric person ID |
| `uuid` | UUID string or `null` | Person's public identifier |
| `name` | string | Person's name |
| `email` | string or `null` | Recorded email address |
| `phone` | string or `null` | Recorded phone number |
| `source` | string or `null` | Source recorded on the person |

### New Visitor: `visitor.created`

Requires `triggers:read` and `visitors:read`.

| Data field | Type | Meaning |
| - | - | - |
| `visitor_id` | integer | Numeric visitor ID |
| `uuid` | UUID string | Visitor's public identifier |
| `member_id` | integer or `null` | Linked person, if present |
| `first_name` | string | Visitor's first name |
| `last_name` | string or `null` | Visitor's last name |
| `email` | string or `null` | Recorded email address |
| `phone` | string or `null` | Recorded phone number |
| `source` | string | Recorded source, such as `connect_card` |
| `email_consent` | boolean | Whether email consent was recorded |
| `sms_consent` | boolean | Whether SMS consent was recorded |

Recorded contact details alone are not consent to send messages. Filter a
welcome workflow on the relevant consent value.

### Donation Received: `giving.received`

Requires `triggers:read` and `giving:read`. Published for settled general gifts
and outreach donations marked `donated`. The `source` value distinguishes two
payload variants; source-specific fields are absent from the other variant.

| Data field | Type | Meaning |
| - | - | - |
| `source` | string | `general` or `outreach_campaign` |
| `id` | integer | Donation ID within that source; use `source` together with this ID |
| `reference` | string or `null` | Recorded gift/payment reference |
| `status` | string | Recorded donation status |
| `amount` | decimal string | Recognized amount, or recorded amount when no recognized amount is set |
| `currency` | string or `null` | Recorded currency code |
| `refunded_amount` | decimal string | Refunded amount recorded in this snapshot |
| `settled_at` | ISO 8601 date-time string or `null` | Recorded settlement time |
| `fund_id` | integer or `null` | General gifts only: fund ID |
| `disputed_amount` | decimal string | General gifts only: recorded disputed amount |
| `campaign_id` | integer | Outreach donations only: campaign ID |
| `type` | string | Outreach donations only: `cash` or `item` |

For example, the `data` object for a general gift is:

```json theme={null}
{
  "source": "general",
  "id": 123,
  "reference": "EXAMPLE-GIFT",
  "status": "completed",
  "fund_id": 1,
  "amount": "25.00",
  "currency": "USD",
  "refunded_amount": "0.00",
  "disputed_amount": "0.00",
  "settled_at": "2026-10-08T09:00:00.000Z"
}
```

Donor names, email addresses, member IDs, and payment credentials are excluded.
This trigger is a received-gift snapshot, not a stream of subsequent refunds
or disputes.

### New Event Registration: `event.registration.created`

Requires `triggers:read` and `events:read`.

| Data field | Type | Meaning |
| - | - | - |
| `id` | integer | Registration ID |
| `public_uuid` | UUID string | Registration's public identifier |
| `event_id` | integer | Church event ID; different from the envelope's automation event UUID |
| `event_public_uuid` | UUID string or `null` | Church event's public identifier |
| `occurrence_date` | `YYYY-MM-DD` string or `null` | Registered occurrence |
| `status` | string | Registration status, such as `registered` or `waitlist` |
| `payment_status` | string | Recorded payment status, such as `not_required` or `pending` |
| `party_size` | integer | One registrant plus guest count |
| `checked_in` | boolean | Check-in state in the creation snapshot |

Registrant identity, contact details, and registration notes are excluded.

### New Prayer Request: `prayer.request.created`

Requires `triggers:read` and `prayer:read`. This is a metadata-only trigger.

| Data field | Type | Meaning |
| - | - | - |
| `prayer_request_id` | integer | Prayer request ID |
| `visibility` | string | Recorded visibility, such as `pastoral` |
| `is_anonymous` | boolean | Whether the request is anonymous |
| `status` | string | Recorded request status |

The payload excludes names, member IDs, prayer text, and pastoral notes,
including for requests that are not anonymous.

### Serving Assignment Accepted: `volunteer.assignment.accepted`

Requires `triggers:read` and `volunteers:read`. Published when the assignment
has a recorded response time and the status is `confirmed`.

| Data field | Type | Meaning |
| - | - | - |
| `assignment_id` | integer | Assignment ID |
| `public_uuid` | UUID string | Assignment's public identifier |
| `member_id` | integer or `null` | Assigned person |
| `service_plan_id` | integer | Service plan ID |
| `status` | string | `confirmed` |
| `response` | string | `accepted` |
| `responded_at` | ISO 8601 date-time string | Recorded response time |

### Serving Assignment Declined: `volunteer.assignment.declined`

Requires `triggers:read` and `volunteers:read`. Published when the assignment
has a recorded response time and the status is `declined`.

| Data field | Type | Meaning |
| - | - | - |
| `assignment_id` | integer | Assignment ID |
| `public_uuid` | UUID string | Assignment's public identifier |
| `member_id` | integer or `null` | Assigned person |
| `service_plan_id` | integer | Service plan ID |
| `status` | string | `declined` |
| `response` | string | `declined` |
| `responded_at` | ISO 8601 date-time string | Recorded response time |

Serving response payloads exclude private leader notes and instructions.

### Form Submitted: `form.submitted`

Requires `triggers:read` and `forms:read`. Published when a submission has a
recorded submission time and is not marked as spam.

| Data field | Type | Meaning |
| - | - | - |
| `submission_id` | integer | Submission ID |
| `public_uuid` | UUID string | Submission's public identifier |
| `form_id` | integer | Form ID |
| `completion_status` | string | Recorded completion status |
| `submitted_at` | ISO 8601 date-time string | Recorded submission time |

Answers, attachments, member identities, and care information are excluded.

## Actions and Retry Safety

Use `POST /api/automation/v1/actions/{action}` with JSON input and an
`Idempotency-Key` header. The key must contain 1–200 printable ASCII characters
without spaces or other whitespace
and stay the same for every retry of that source event and action.

| Action | Required scope |
| - | - |
| `person.upsert` | `people:write` |
| `person.tag` | `people:write` |
| `group.add_member` | `groups:write` |
| `event.register` | `events:write` |
| `message.send` | `messages:send` |

The native connectors also offer **Return Success**. Both versions return
`{"id":"thefaithapp-return-success","success":true}` without changing church
records or creating an automation action run. Neither uses a backend action
endpoint or requires an action scope.

Zapier's publication version 1.0.4 and Make require the selected church
connection and check it with read-only `GET /api/automation/v1/auth`. They return
success only after HTTP 200, without exposing the authentication response or
key. This check can update the key's last-used metadata. Neither version
confirms that another action would succeed. The private Zapier version 1.0.3
returns success locally without checking authentication.

For example:

```http theme={null}
POST /api/automation/v1/actions/person.upsert
X-API-Key: <automation-secret>
Idempotency-Key: <visitor-event-id>
Content-Type: application/json
```

```json theme={null}
{
  "name": "Example Visitor",
  "email": "visitor@example.com"
}
```

`person.upsert` creates new people with the `automation` source. When updating
an existing person by member ID or matching email, it preserves their original
source. Email matching is case-insensitive within the key's church.

Retries with identical input return the saved response with
`Idempotency-Replayed: true`. Reusing a key with changed input returns `409`.
A request already processing also returns `409`; do not use a new key to
bypass it. The claim is scoped to the church, credential, and action.

External email and SMS providers may accept a message before a network failure
prevents confirmation. Such actions are marked `review_required` and replay
their saved failure rather than sending again. Review the provider outcome
before intentionally submitting a new request. A new idempotency key is a new
action and can create a duplicate.

Message actions use the church's existing channel configuration. Email honors
recorded opt-outs; SMS requires confirmed consent. Visitor welcome workflows
should filter on recorded email consent before sending follow-up.
Event registrations respect capacity, deadline, occurrence, and
registration settings. Resource IDs must belong to the key's church.

## Action Request and Response Contracts

All five endpoints below require `X-API-Key`, an `Idempotency-Key` header, and
a JSON body. The source ID belongs in the header, not in the JSON body.
Successful requests return HTTP `200` with this envelope:

```json theme={null}
{
  "data": { "id": 123, "member_id": 123, "tag": "Welcome" },
  "run_id": "e317e867-bc2b-4e2b-b23c-8a275ef7cb67"
}
```

`run_id` is the UUID of the saved automation action run. The fields inside
`data` depend on the action as documented below. An idempotent replay returns
the original saved result and original HTTP status, with
`Idempotency-Replayed: true`.

Optional fields may be omitted or sent as `null` unless a conditional
requirement is listed. Required numeric resource IDs are integers of at least
`1` and must belong to the key's church. These endpoints do not accept a church
override or an arbitrary recipient email/phone.

### Create or Update Person: `POST /actions/person.upsert`

Required scope: `people:write`.

| Input field | Type | Required | Rules |
| - | - | - | - |
| `member_id` | integer or `null` | No | Existing person ID, at least `1`; when supplied, selects the person to update |
| `name` | string | Yes | Maximum 255 characters; saved with leading/trailing whitespace removed |
| `email` | string or `null` | When `member_id` is empty | Valid email, maximum 255 characters; matched case-insensitively within this church |
| `phone` | string or `null` | No | Maximum 20 characters |

Without a member ID, a matching email updates that person; otherwise a new
person is created if the church has member capacity. Updating a person's
email to one already used by someone else in the church returns `422`.
Omitting email or phone on an ID-based update preserves that value; supplying
`null` clears it. New people use the `automation` source; updates preserve the
original source.

| Result field in `data` | Type | Meaning |
| - | - | - |
| `id` | integer | Person ID |
| `member_id` | integer | Same person ID, suitable for other actions |
| `uuid` | UUID string or `null` | Person's public identifier |
| `name` | string | Saved name |
| `email` | string or `null` | Saved email |
| `phone` | string or `null` | Saved phone |

### Add Person Tag: `POST /actions/person.tag`

Required scope: `people:write`.

| Input field | Type | Required | Rules |
| - | - | - | - |
| `member_id` | integer | Yes | Person ID, at least `1` |
| `tag` | string | Yes | Maximum 40 characters; must contain text |

Whitespace is trimmed and collapsed. Matching an existing tag is
case-insensitive and returns it without adding a duplicate. A person can have
up to 20 tags; adding a new tag at that limit returns `422`.

| Result field in `data` | Type | Meaning |
| - | - | - |
| `id` | integer | Saved tag record ID |
| `member_id` | integer | Person ID |
| `tag` | string | Saved tag text, including the existing spelling when reused |

### Add Person to Group: `POST /actions/group.add_member`

Required scope: `groups:write`.

| Input field | Type | Required | Rules |
| - | - | - | - |
| `member_id` | integer | Yes | Person ID, at least `1` |
| `group_id` | integer | Yes | Active community group ID, at least `1` |

An existing active membership is returned unchanged. A new membership uses
the `member` role and does not opt the person into the group directory.

| Result field in `data` | Type | Meaning |
| - | - | - |
| `id` | integer | Group membership ID |
| `member_id` | integer | Person ID |
| `group_id` | integer | Community group ID |
| `status` | string | Membership status, normally `active` |

### Create Event Registration: `POST /actions/event.register`

Required scope: `events:write`.

| Input field | Type | Required | Rules |
| - | - | - | - |
| `member_id` | integer | Yes | Person ID, at least `1`; recorded name and email supply registrant details |
| `event_id` | integer | Yes | Church event ID, at least `1` |
| `occurrence_date` | `YYYY-MM-DD` string or `null` | No | Must be a valid event occurrence; omission selects the next upcoming occurrence |
| `guests` | integer or `null` | No | `0`–`100`; default `0`; party size is `1 + guests` |
| `meal_count` | integer or `null` | No | `0`–`100`; default `0`; saved only when the event collects meal counts |
| `childcare_count` | integer or `null` | No | `0`–`100`; default `0`; saved only when the event collects childcare counts |
| `options` | array of strings or `null` | No | At most 50 values, each at most 100 characters; only configured event option keys are retained |
| `notes` | string or `null` | No | Maximum 2,000 characters; saved only when the event collects special notes |

Use an explicit occurrence date for predictable recurring-event workflows.
The event must support built-in registration and its deadline must not have
passed. Capacity and waitlist settings apply. Existing uncancelled registration
for the same person and occurrence is returned unchanged. A cancelled
registration can be reopened with the new input.

A paid registration can return `payment_status: "pending"`; this action does
not charge the person or complete payment. Paid registration requires the
church's Stripe connection to be ready. Read the returned status before
treating the person as registered or paid.

| Result field in `data` | Type | Meaning |
| - | - | - |
| `id` | integer | Registration ID |
| `public_uuid` | UUID string | Registration's public identifier |
| `member_id` | integer | Person ID |
| `event_id` | integer | Church event ID |
| `occurrence_date` | `YYYY-MM-DD` string or `null` | Resolved occurrence date |
| `status` | string | Saved registration status, such as `registered` or `waitlist` |
| `payment_status` | string | Saved payment status, such as `pending`, `paid`, or `not_required` |
| `amount_due` | decimal string | Recorded registration amount |
| `currency` | string | Recorded currency code |

### Send Message: `POST /actions/message.send`

Required scope: `messages:send`. The issuing staff member must also retain the
permission for the selected channel.

| Input field | Type | Required | Rules |
| - | - | - | - |
| `member_id` | integer | Yes | Person ID, at least `1`; destination comes from that person |
| `channel` | string | Yes | `in_app`, `email`, or `sms` |
| `subject` | string or `null` | For `in_app` and `email` | Maximum 255 characters; optional for SMS |
| `body` | string | Yes | Maximum 5,000 characters |

In-app messages create a notification for the selected person. Email requires
a valid recorded recipient, an active church email provider, a valid sender,
and no recorded subscriber opt-out. SMS requires a recorded phone number and
a subscribed SMS record with confirmed opt-in. Email/SMS actions make real
external sends through the church's provider.

| Result field in `data` | Type | Meaning |
| - | - | - |
| `id` | UUID string | Created in-app notification ID, or generated result ID for email/SMS; not a provider delivery receipt |
| `member_id` | integer | Person ID |
| `channel` | string | `in_app`, `email`, or `sms` |
| `status` | string | `sent`; the in-app notification was created or the provider confirmed the send request |

An email/SMS success does not prove that the person read or received the
message. Ambiguous provider failures return `502` with a saved action run that
needs review; use the retry guidance above before starting a new send.

## Make an API Call

Make's **Make an API call** module uses the selected connection and the
production Automation API. Enter a relative path such as `/v1/auth` or
`/v1/events`, and put filters in **Query string**. For an action request, map
the stable **Source event ID**; the module sends it as `Idempotency-Key`.

The optional **Headers** input accepts only `X-Request-ID` and
`X-Correlation-ID` for request tracing. The connection supplies `X-API-Key`,
`Accept`, and the JSON `Content-Type`; these and `Idempotency-Key` cannot be
overridden through **Headers**.

The output contains **Body**, **Status code**, and a **Headers** collection
limited to `Content-Type` and `Retry-After` when present. Other response headers,
including cookies and authentication or credential values, are excluded from
the module's mapped output. Log sanitization is separate from this restriction
on scenario bundles. Use `Retry-After` to guide retries when the API rate-limits
a request.

## Errors and Diagnostics

Error responses contain `message`. Validation failures can also contain
`errors`, whose keys identify invalid fields and whose values are arrays of
messages. Once an action run has been claimed, its response includes `run_id`;
authentication, scope, and initial input-validation failures can occur before
a run exists.

| HTTP status | Meaning | Next step |
| - | - | - |
| `401` | Key is invalid, expired, or revoked, or its issuing account no longer has access | Reconnect with an active authorized key |
| `403` | Effective scope, staff permission, channel permission, or church plan does not permit this request | Check the key, issuing staff permissions, and plan |
| `404` | Resource is missing, belongs to another church, or is no longer retained; or the action/path is unknown | Verify the resource and path in this church |
| `409` | Source ID was used with different input, or its action is still processing | Inspect the existing run; do not bypass it with a new source ID |
| `422` | Input, consent, capacity, occurrence, or provider settings need correction | Read `message` and any field-level `errors` |
| `429` | Request rate limit exceeded | Honor `Retry-After` when present and use exponential backoff with jitter |
| `502` | Action outcome could not be confirmed and the saved run needs review | Inspect the provider and run before deliberately submitting another send |

An empty `GET /events?event_id=...` list is HTTP `200` when the UUID does not
match a retained event for the requested type and church. Direct
`GET /events/{uuid}` readback returns `404` for a missing, foreign, or expired
event. Do not automatically retry a `review_required` message action as a new
request.

Integration administrators can review recent action runs in **Developers**
and webhook attempts in webhook diagnostics. Private provider invite links
are configured per deployment; an account or local app definition alone does
not make a provider app available to churches.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.