Developer API · v1
CRM Contacts API
Synchronize leads and members from one RxApp affiliate into a CRM through a tenant-scoped, read-only API.
Last reviewed 25 September 2026
Overview
The Contacts API is intended for server-to-server CRM integrations. It exports contact and membership state but never accepts writes.
The API key determines the affiliate. Do not send an affiliate ID: a key can only read contacts belonging to its own tenant.
- Production base URL: https://api.rxapp.io
- API version: v1
- Scope: contacts:read
- Formats: JSON requests and responses; RFC 3339 UTC timestamps
Authentication
An RxApp affiliate owner or RxApp support provides a tenant-specific API key. Send it as a Bearer token on every request.
Keep the key in a server-side secret manager. Never place it in browser code, mobile bundles, source control, URLs, or application logs.
Authorization: Bearer rx_live_...Quick start
Request the first page of contacts:
curl "https://api.rxapp.io/v1/contacts?limit=100" \
-H "Authorization: Bearer $RXAPP_CRM_API_KEY"Example response with fictional data:
{
"items": [
{
"id": "11111111-1111-4111-8111-111111111111",
"contactType": "member",
"firstName": "Alex",
"lastName": "Example",
"email": "alex@example.com",
"membershipStatus": "active",
"subscriptionPlanCode": "unlimited",
"subscriptionPlanName": "Unlimited",
"subscriptionStartedAt": "2026-09-01T00:00:00.000Z",
"subscriptionEndsAt": null,
"firstMembershipStartedAt": "2026-09-01T00:00:00.000Z",
"version": 3,
"updatedAt": "2026-09-25T12:00:00.000Z",
"deletedAt": null
}
],
"page": {
"nextCursor": null,
"hasMore": false
},
"sync": {
"watermark": "2026-09-25T12:05:00.000Z"
}
}Contact model
Use id as the external identity and version to ignore stale updates. Internal RxApp user IDs are never exposed.
| Field | Meaning |
|---|---|
id | Stable UUID for this contact. |
contactType | lead or member. A converted member never becomes a lead again. |
membershipStatus | active, pending, inactive, or null for a lead or tombstone. |
subscription* | Current membership plan and its start/end timestamps. |
firstMembershipStartedAt | Earliest qualifying membership start; never moves later. |
version | Monotonically increasing contact version. |
updatedAt | Timestamp used by incremental synchronization. |
deletedAt | Non-null means tombstone; remove locally stored personal data. |
Endpoints
Both public endpoints require a contacts:read key.
| Method | Path | Purpose |
|---|---|---|
GET | /v1/contacts | List a stable page of contacts. |
GET | /v1/contacts/{contactId} | Read one contact within the authenticated tenant. |
List parameters
| Parameter | Meaning |
|---|---|
updatedAfter | Exclusive RFC 3339 UTC checkpoint, for example 2026-09-25T12:05:00Z. |
contactType | Optional lead or member filter. |
limit | Page size from 1 through 500; default 100. |
cursor | Opaque continuation cursor. It must be the only query parameter. |
Retrieve one contact by its exported UUID:
curl "https://api.rxapp.io/v1/contacts/11111111-1111-4111-8111-111111111111" \
-H "Authorization: Bearer $RXAPP_CRM_API_KEY"Synchronize safely
A watermark is a checkpoint for a completely processed page chain. Never advance it after a partial synchronization.
- Start with GET /v1/contacts and optional filters or the last committed updatedAfter watermark.
- Upsert every item by id. Ignore an item when its version is not newer than the locally stored version.
- If page.nextCursor is present, request only ?cursor=... and repeat until hasMore is false.
- Verify that sync.watermark remains identical on every page in the chain.
- Commit sync.watermark only after the final page has been processed successfully.
- Use the committed watermark as updatedAfter for the next run.
- If a cursor expires, discard it and restart from the last committed watermark.
Errors and rate limits
Error responses contain a stable code and X-Request-Id. Keep the request ID when contacting support.
| Status | Developer action |
|---|---|
400 | Correct the request or restart an invalid cursor from the last watermark. |
401 | Stop and replace the missing, expired, or revoked API key. |
403 | The key lacks the contacts:read scope. |
404 | The contact does not exist within the authenticated tenant. |
429 | Wait for Retry-After before retrying. |
500/503 | Retry with bounded exponential backoff; report persistent failures with X-Request-Id. |
Authenticated responses expose X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset. Limits are configured per key; do not assume a fixed value.
Downloads and support
The Postman collection contains only read-only requests. Set crmApiKey only as a local Current value and do not export a populated collection.
For access or integration support, email support@rxapp.io.