Sync contacts
Contacts are the core CRM record in CRM Solid. This guide walks through creating a contact and then listing and searching your contacts via the Public API.
All requests go to the base URL https://api.crmsolid.com and must include your API
key as a bearer token. If you haven’t set that up yet, start with the
Quickstart and Authentication guides.
Create a contact
Section titled “Create a contact”Send a POST to /v1/contacts. At least one of name, username, or phone
must be provided. platform defaults to telegram if you omit it.
-
Build the request body. Only the fields you want to set are required — everything is optional as long as one identifier is present.
Field Type Notes platformstring telegram(default) ortwitter.namestring Display name. usernamestring Handle with or without a leading @— the@is stripped server-side.phonestring Phone number in any format. notesstring Free-text notes attached to the contact. -
Send the request.
Terminal window curl -X POST https://api.crmsolid.com/v1/contacts \-H "Authorization: Bearer csk_live_..." \-H "Content-Type: application/json" \-d '{"platform": "telegram","name": "Acme Inc.","username": "john_doe","notes": "Met at conference"}'const res = await fetch("https://api.crmsolid.com/v1/contacts", {method: "POST",headers: {Authorization: "Bearer csk_live_...","Content-Type": "application/json",},body: JSON.stringify({platform: "telegram",name: "Acme Inc.",username: "john_doe",notes: "Met at conference",}),});const contact = await res.json();console.log(contact.id);import requestsres = requests.post("https://api.crmsolid.com/v1/contacts",headers={"Authorization": "Bearer csk_live_..."},json={"platform": "telegram","name": "Acme Inc.","username": "john_doe","notes": "Met at conference",},)contact = res.json()print(contact["id"]) -
Read the response. A successful create returns 201 Created with the full contact record:
{"id": 101,"platform": "telegram","name": "Acme Inc.","username": "john_doe","phone": null,"email": null,"company": null,"notes": "Met at conference","stage": "Lead","leadScore": null,"leadScoreIsAi": false,"assignedToUserId": null,"createdAt": "2024-03-01T10:00:00Z","lastMessageAt": null,"hasUnreadMessages": false}
List and search contacts
Section titled “List and search contacts”Send a GET to /v1/contacts. The endpoint is cursor-paginated: each page
returns a nextCursor that you pass back as after to fetch the next page.
Query parameters
Section titled “Query parameters”| Param | Type | Notes |
|---|---|---|
after | integer | Cursor — returns contacts with an id strictly less than this value. Omit for the first page. |
limit | integer | Page size, clamped to 1–100. Defaults to 25. |
platform | string | Filter by telegram or twitter. |
q | string | Case-insensitive substring search across name, username, and phone. |
curl "https://api.crmsolid.com/v1/contacts?limit=10&q=acme" \ -H "Authorization: Bearer csk_live_..."const params = new URLSearchParams({ limit: "10", q: "acme" });
const res = await fetch( `https://api.crmsolid.com/v1/contacts?${params}`, { headers: { Authorization: "Bearer csk_live_..." } },);
const page = await res.json();console.log(page.items, page.nextCursor, page.hasMore);import requests
res = requests.get( "https://api.crmsolid.com/v1/contacts", headers={"Authorization": "Bearer csk_live_..."}, params={"limit": 10, "q": "acme"},)
page = res.json()print(page["items"], page["nextCursor"], page["hasMore"])The response is a paginated list. nextCursor is null when hasMore is false:
{ "items": [ { "id": 101, "platform": "telegram", "name": "Acme Inc.", "username": "john_doe", "phone": null, "notes": null, "stage": "Lead", "createdAt": "2024-03-01T10:00:00Z", "lastMessageAt": null, "hasUnreadMessages": false } ], "nextCursor": 101, "hasMore": false}Paginating through all pages
Section titled “Paginating through all pages”Keep requesting with after=nextCursor until hasMore is false:
let after;const all = [];
do { const params = new URLSearchParams({ limit: "100" }); if (after) params.set("after", String(after));
const res = await fetch( `https://api.crmsolid.com/v1/contacts?${params}`, { headers: { Authorization: "Bearer csk_live_..." } }, ); const page = await res.json();
all.push(...page.items); after = page.nextCursor;} while (after != null);import requests
after = Noneall_contacts = []
while True: params = {"limit": 100} if after is not None: params["after"] = after
res = requests.get( "https://api.crmsolid.com/v1/contacts", headers={"Authorization": "Bearer csk_live_..."}, params=params, ) page = res.json()
all_contacts.extend(page["items"]) after = page["nextCursor"] if after is None: breakFetch a single contact
Section titled “Fetch a single contact”To read one contact by id, GET /v1/contacts/{id}. This response also includes
the contact’s tags array, which is omitted from list responses. A 404 is
returned if the contact doesn’t exist or belongs to another workspace.
curl https://api.crmsolid.com/v1/contacts/101 \ -H "Authorization: Bearer csk_live_..."Next steps
Section titled “Next steps”- Message a contact directly — see Send a Telegram message.
- Browse every field, scope, and error code in the full API reference.