POST /v1/actions/search-contacts
Find contacts by name/phone/email substring, or by tag. Returns up to 50 results.
Search contacts by free-text query (name/phone/email substring, case-insensitive), and/or filter by tag and exact email. Returns up to 50 results ordered by last_message_at DESC.
POST /api/v1/actions/search-contacts
Request body
| Field | Type | Required | Notes |
|---|---|---|---|
query |
string | no | Substring match against name, phone, email (Postgres ILIKE) |
tag |
string | no | Exact tag name |
email |
string | no | Exact email match |
All filters are AND-combined. Empty body returns the 50 most-recently-active contacts.
curl -X POST https://www.qyvo.io/api/v1/actions/search-contacts \
-H "Authorization: Bearer YOUR_TOKEN_HERE" \
-H "Content-Type: application/json" \
-d '{"query": "smith", "tag": "vip"}'
const contacts = await fetch('https://www.qyvo.io/api/v1/actions/search-contacts', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.QYVO_TOKEN}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ query: 'smith', tag: 'vip' }),
}).then((r) => r.json());
$contacts = Http::withToken(env('QYVO_TOKEN'))
->post('https://www.qyvo.io/api/v1/actions/search-contacts', [
'query' => 'smith',
'tag' => 'vip',
])
->json();
import os, httpx
contacts = httpx.post(
'https://www.qyvo.io/api/v1/actions/search-contacts',
headers={'Authorization': f"Bearer {os.environ['QYVO_TOKEN']}"},
json={'query': 'smith', 'tag': 'vip'},
).json()
Response — 200 OK
[
{
"id": "01J1Y...",
"phone": "+14155550123",
"name": "Jane Smith",
"email": "[email protected]",
"source": "shopify",
"tags": ["vip"],
"last_message_at": "2026-05-07T08:14:23+00:00",
"created_at": "2026-04-15T10:32:00+00:00"
}
]
The result is a flat array — empty [] when nothing matches. See Pagination for the larger-result-set pattern.
