curl --request GET \
--url https://api.ciarem.ai/v1/contacts \
--header 'Authorization: Bearer <token>'import requests
url = "https://api.ciarem.ai/v1/contacts"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://api.ciarem.ai/v1/contacts', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.ciarem.ai/v1/contacts",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.ciarem.ai/v1/contacts"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://api.ciarem.ai/v1/contacts")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.ciarem.ai/v1/contacts")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Bearer <token>'
response = http.request(request)
puts response.read_body{
"items": [
{
"id": "<string>",
"first_name": "<string>",
"last_name": "<string>",
"email": "<string>",
"phone": "<string>",
"country": "<string>",
"city": "<string>",
"instagram": "<string>",
"messenger": "<string>",
"whatsapp_username": "<string>",
"origin": "SOCIAL",
"sub_origin_id": "<string>",
"whatsapp_status": "verified",
"funnel_stage_id": "<string>",
"owner_id": "<string>",
"last_contacted_at": "2023-11-07T05:31:56Z",
"created_at": "2023-11-07T05:31:56Z",
"updated_at": "2023-11-07T05:31:56Z",
"properties": {}
}
],
"next_cursor": "<string>",
"total_count": 123
}{
"detail": "<string>"
}{
"detail": "<string>"
}{
"detail": [
{
"loc": [
"<string>"
],
"msg": "<string>",
"type": "<string>",
"input": "<unknown>",
"ctx": {}
}
]
}{
"detail": "<string>"
}List contacts
curl --request GET \
--url https://api.ciarem.ai/v1/contacts \
--header 'Authorization: Bearer <token>'import requests
url = "https://api.ciarem.ai/v1/contacts"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://api.ciarem.ai/v1/contacts', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.ciarem.ai/v1/contacts",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.ciarem.ai/v1/contacts"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://api.ciarem.ai/v1/contacts")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.ciarem.ai/v1/contacts")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Bearer <token>'
response = http.request(request)
puts response.read_body{
"items": [
{
"id": "<string>",
"first_name": "<string>",
"last_name": "<string>",
"email": "<string>",
"phone": "<string>",
"country": "<string>",
"city": "<string>",
"instagram": "<string>",
"messenger": "<string>",
"whatsapp_username": "<string>",
"origin": "SOCIAL",
"sub_origin_id": "<string>",
"whatsapp_status": "verified",
"funnel_stage_id": "<string>",
"owner_id": "<string>",
"last_contacted_at": "2023-11-07T05:31:56Z",
"created_at": "2023-11-07T05:31:56Z",
"updated_at": "2023-11-07T05:31:56Z",
"properties": {}
}
],
"next_cursor": "<string>",
"total_count": 123
}{
"detail": "<string>"
}{
"detail": "<string>"
}{
"detail": [
{
"loc": [
"<string>"
],
"msg": "<string>",
"type": "<string>",
"input": "<unknown>",
"ctx": {}
}
]
}{
"detail": "<string>"
}Authorizations
An org API key: Authorization: Bearer oak_….
Query Parameters
1 <= x <= 200Top-level acquisition category — how a contact entered the CRM.
Set once at first touch and never overwritten: a contact who joins the
waitlist (WEB) and later messages on WhatsApp keeps WEB; the channel
they messaged on lives on their ContactHandle, not here. The category is
a fixed, platform-owned vocabulary so analytics roll-ups, the AI prompt,
and inbound auto-assignment stay stable across orgs. The specific named
source within a category (e.g. "Waitlist", "SaaStr 2026", "WhatsApp") is
org-customizable — see the contact_sub_origins table. NULL for legacy
contacts whose origin predates this field. Replaces the old conversational-
only ContactSource (WHATSAPP/INSTAGRAM/MESSENGER), which collapsed
acquisition and channel into one field.
SOCIAL, ADS, WEB, EVENT, REFERRAL, OUTBOUND, IMPORT, MANUAL, API, OTHER Ordering applied to GET /contacts.
RECENT is the default (updated_at DESC, id DESC). The name / country /
city / origin sorts are ASC with NULLS LAST so contacts missing the
sorted column pool at the bottom rather than polluting the top.
recent, name, country, city, origin Direction for the active sort, toggled by the toolbar's asc/desc button. Omitted → per-sort default (time sorts newest-first / DESC; the text + enum sorts A→Z / ASC).
asc, desc