Developer

API reference

The Reach API gives you read-only REST access to your account's data over JSON, authenticated with a bearer token. Every endpoint is a GET; the deals endpoint is reserved and returns a 501 until a later release.

The Reach API is read-only. Every route under /api/v1 accepts only GET requests, returns JSON, and requires a bearer token. Create a token first (see API tokens), then pass it on every request to the base URL https://reach.mercleo.com/api/v1.

Authenticating requests

Send the token as a bearer credential in the Authorization header on every request. Tokens carry the prefix mrl_.

bash
Authorization: Bearer mrl_<your-token>

Tokens are account-scoped and grant only the scopes you select when you create them. Each endpoint requires a specific scope, named in the reference below. If the header is missing or malformed, the request returns 401 missing_token. A revoked, expired, or unknown token returns 401 invalid_token, and a call that requires a scope the token does not carry returns 403 insufficient_scope.

Rate limits

The API allows 100 requests per minute per account. Every successful response includes X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset headers so you can track your remaining budget.

Exceeding the limit returns 429 rate_limited with a Retry-After header giving the backoff in seconds. Wait that long before retrying.

Endpoints

Every endpoint is a GET. Each one names the scope the token must carry.

Contacts

  • GET /api/v1/contacts: a paginated list of contacts. Scope contacts:read. Query params: limit (1–500, default 50), cursor (opaque), lifecycle_stage (matches the lifecycle stage label), tag (tag UUID), and q (substring match across name and email).
  • GET /api/v1/contacts/[id]: a single contact by id. Scope contacts:read. A contact that does not belong to your account returns 404 not_found.
bash
curl -H 'Authorization: Bearer mrl_…' \
  'https://reach.mercleo.com/api/v1/contacts?limit=50'

Companies

  • GET /api/v1/companies: a paginated list of companies (organizations). Scope companies:read. Query params: limit (1–500, default 50), cursor (opaque), and q (substring match on name and domain).
  • GET /api/v1/companies/[id]: a single company by id. Scope companies:read. A company that does not belong to your account returns 404 not_found.

Lists

  • GET /api/v1/lists: every contact list owned by your account. Scope lists:read. Returns each list's id, name, description, and type. There is no single-list GET; only the collection and its resolved contacts below.
  • GET /api/v1/lists/[id]/contacts: the resolved member set for one list. Scope lists:read. Returns members for static lists and evaluated matches for dynamic lists. Query params: limit (1–1000, default 100) and cursor (opaque). A list id that does not belong to your account returns 404 not_found.

Objects

These two endpoints expose the schema of your account's custom object types: their fields, and the stage sets and stages defined on them.

  • GET /api/v1/objects: every custom object type installed on the account. Scope objects:read. No query params. Returns each type's key, singular and plural display names, icon, colour, default view, primary relation, and whether it's a system template.
  • GET /api/v1/objects/[key]: one object type by its key (for example gift or sales_deal), including its full field list and its stage sets with their stages. Scope objects:read. An unknown key returns 404 object_type_not_found.

Records

  • GET /api/v1/records: a paginated list of records for one object type. Scope records:read. Requires ?type=<object-type-key>; omitting it returns 400 type_required, and a type key not installed on your account returns 404 object_type_not_found. Other query params: limit (1–500, default 50) and cursor (opaque). Each record includes its field values, its stage (if it belongs to a stage set), and its links to a contact, organization, or household.
  • GET /api/v1/records/[id]: a single record by id, including its relations to other records. Scope records:read. An unknown id returns 404 record_not_found.

Deals

GET /api/v1/deals and GET /api/v1/deals/[id] are reserved and not yet implemented. Both routes exist and the deals:read scope is grantable today, but every call currently returns 501 not_implemented. Do not build against it yet.

Paginating with cursors

Paginated responses carry a pageInfo object that includes a nextCursor value. To fetch the next page, pass that value back as the cursor query param on your next request. When nextCursor is null, you have reached the end of the result set.

Error shape

Errors return a consistent JSON envelope with a machine-readable code and a human-readable message.

json
{
  "error": {
    "code": "invalid_token",
    "message": "Token is invalid, revoked, or expired"
  }
}
Error codes and what they mean.
StatusCodeMeaning
400type_requiredRecords collection called without ?type=
400invalid_cursorCursor is malformed
401missing_tokenAuthorization header missing or malformed
401invalid_tokenToken is invalid, revoked, or expired
403insufficient_scopeToken lacks the scope the endpoint requires
404not_foundContact, company, or list is missing or not in your account
404object_type_not_foundNo custom object type with that key on this account
404record_not_foundNo record with that id on this account
429rate_limitedOver 100 req/min; see Retry-After header
501not_implementedDeals endpoint; reserved for a later release

Updated