CRM API integration recipes

Connect client accounts, synchronize CRM contacts and receive signed webhooks with Chirply API examples, permissions and verification steps.

Reviewed by Chirply ·

Prepare one account and a read-scoped key

Use the API for an integration you operate for your own account. Open Developers in that account and follow Authentication to create a key with read scope for these examples. Store it on your server in CHIRPLY_API_KEY. The curl snippets use POSIX-shell syntax and assume that environment variable is already set. Keep the credential in your secret store; published code and browser-side JavaScript should contain only placeholders. For an app distributed to other businesses, follow the OAuth installation guide.

curl · verify account
curl --fail-with-body https://app.chirply.io/api/v1 \
  -H "Authorization: Bearer $CHIRPLY_API_KEY"

First request GET /api/v1 and compare data.org_id with the intended account. Check data.scopes before continuing. A successful identity request establishes which account your key reaches; it does not establish that every plan-dependent operation is available. The examples below read account data. Creating contacts, changing client accounts and registering outbound webhooks are separate write operations with their own effects.

List client accounts through the API

Chirply's client-account API uses the subaccounts domain. Call subaccounts.list from an agency account with the Reseller client-account entitlement to retrieve its child accounts and allowance. The product calls them client accounts; the stable API names remain subaccounts.list, subaccounts.create and subaccounts.update.

1. Verify the parent account

Use the identity request above with the agency's credential. Confirm the returned account ID before loading its client inventory. A client-account key identifies that client account; listing from an agency returns only children of that agency. Treat each credential as an account-specific connection in your integration.

2. Read the client inventory

Send an empty JSON object to subaccounts.list. Read data.result.total, data.result.max_subaccounts and data.result.subaccounts. Each returned client includes id, name, slug, status and created_at. Store the ID as the durable integration key, and use the name as a display label. This operation returns the agency's client inventory; it does not accept limit or offset.

curl · read-only
curl --fail-with-body -X POST \
  https://app.chirply.io/api/v1/actions/subaccounts.list \
  -H "Authorization: Bearer $CHIRPLY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{}'

3. Plan account changes deliberately

Creating a client account requires write scope, admin-level authorization and available plan allowance. subaccounts.create accepts name and derives the slug. Updating requires the client's id; name and status are optional. Setting status to suspended locks that client account for everyone in it, and active restores it. Use the action reference to review the fields before performing either write.

4. Check the result

Compare the returned IDs and statuses with the expected client inventory. If access returns 403, confirm the parent is an agency with the required Reseller entitlement and that the credential has the needed scope. If creation returns a limit error, review the account's allowance. Listing child IDs does not grant a credential permission to read those clients' contacts; authenticate for the intended client account separately.

Success check

You have verified the parent account, recorded its client IDs and current allowance, and identified the credential needed for the next account-specific task.

Match CRM contacts before synchronizing records

A CRM contact integration should identify the account, search existing records, reconcile identity and then apply an intentional write. Chirply's contacts.list supports query, limit and offset; the response puts contact records inside data.result.contacts. Keep a mapping from your external record ID to Chirply's contact ID for subsequent updates.

1. Search with a known identifier

Run the read-only example with a test contact's email in query. The search covers names, business name, email, phone and location fields, so a returned row is a candidate rather than proof of an exact identity match. Compare the actual normalized email or phone before associating records. Use the verified consent record to decide which messages are appropriate for that person.

curl · read-only
curl --fail-with-body -X POST \
  https://app.chirply.io/api/v1/actions/contacts.list \
  -H "Authorization: Bearer $CHIRPLY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "limit": 25,
  "offset": 0,
  "query": "alex@example.com"
}'

2. Page through the relevant records

limit defaults to 25 and accepts 1 through 100; offset defaults to 0. For the next page with limit 25, send offset 25, then 50. Keep filters consistent and use data.result.total alongside the returned contacts. Store records by their ID so repeated reads update your local mapping. Offset pagination observes live data: concurrent additions or edits can shift pages, so reconcile again before treating a bulk read as a complete export.

3. Choose the write that fits the workflow

For an existing match, inspect contacts.update and change only the fields your integration owns. contacts.create rejects an existing email or normalized phone with a conflict. Review contacts.import for machine intake that should attach to existing records, and check its matching rules and schema before choosing it. Preserve consent and communication preferences from their verified source; use a successful API match for identity and the verified consent record for communication decisions.

4. Verify downstream effects

A successful contacts.create can trigger Contact created automations, including real email or SMS through connected providers. Accounts requiring API email confirmation can send a confirmation email immediately. Review those settings and provider costs before using a write-capable credential. Test a deliberate write with an authorized test contact, read that contact back by its returned ID, and confirm the intended fields and automation history.

Success check

One external record maps to the intended Chirply contact ID, repeated reads preserve that mapping, and every planned write has an understood communication effect.

Receive and reconcile CRM webhook events

A CRM webhook sends an event to your HTTPS receiver when something happens in the account. Chirply signs each delivery, reuses its delivery ID on retries and exposes a delivery log. Verify the raw request body, persist the accepted delivery and process it idempotently so a retry produces the same business outcome.

1. Inspect subscriptions and available events

With a read-scoped API key, GET /api/v1/webhooks lists this account's subscriptions and available_events. The example reads the first 25 subscriptions. Use limit and offset to inspect further pages. Choose the exact event from the returned catalog. For your own API-key integration, registering an HTTPS endpoint uses POST /api/v1/webhooks with write scope; installed apps manage events through their manifest.

curl · read-only
curl --fail-with-body \
  "https://app.chirply.io/api/v1/webhooks?limit=25&offset=0" \
  -H "Authorization: Bearer $CHIRPLY_API_KEY"

2. Authenticate the received bytes

Save the signing secret returned once when you register the subscription. Read X-Webhook-Signature, containing t=<unix>,v1=<hex>. Calculate HMAC-SHA256 over the timestamp, a period and the raw request body; compare the digest with a constant-time function. Validate timestamp freshness with a five-minute tolerance as described in the verification guide. Verify before parsing JSON. X-Chirply-Signature carries the identical value for integrations using that header name.

3. Persist, acknowledge and deduplicate

Use X-Webhook-Delivery as the unique delivery key; X-Chirply-Delivery is its equivalent header. Durably store a verified delivery before returning a 2xx response within the ten-second delivery window. Process from your queue and make the business operation idempotent. If storage fails, return a failure so delivery can retry. An early success response without durable storage can lose work when your receiver restarts.

4. Trace a controlled event

After an authorized test event, inspect GET /api/v1/webhooks/{id}/deliveries for the subscription's status, attempt count and last error. A delivery can be attempted up to six times; retries become eligible five minutes after the preceding failure and are picked up by the worker. Check your receiver log using the same delivery ID. Exercise duplicate delivery handling locally, and use the reconciliation guidance in the webhook reference to recover missed processing.

Success check

A verified event is durably recorded, the delivery log shows its outcome, and replaying the same delivery does not repeat the business action.

Integration questions

Where do Chirply API calls go?

Send authenticated requests to https://app.chirply.io/api/v1. Public documentation lives on chirply.io/api-docs. An action uses POST /api/v1/actions/<name>, including read-only actions such as contacts.list.

Can I use these recipes with an AI assistant?

The same registered actions are available through Chirply's MCP server with an authorized credential. Action dots become underscores, such as subaccounts_list and contacts_list. Check the tool's input schema, account context and effects before running it. API and MCP callers authorize writes through their credentials; the in-app Copilot has its own approval step for actions marked confirm.

How should an integration handle errors?

Inspect the HTTP status and structured error response. For 401, verify the credential; for 403, check scope, account context and applicable entitlement. Resolve a duplicate or limit conflict before trying the same write again. For 429, follow Retry-After and the documented rate-limit guidance. Keep logs free of API keys and limit stored contact data to what the integration needs.