/v1/contacts/lookupbetaFind a contact by phone
- Needs
- Read your data
(mcp:read) - Plan
- Any plan with API access
- Limits
- 300 a minute per key
- Undo
- Nothing to undo: this only reads.
Looks a contact up by phone number instead of id. Use it when your own system only knows the number.
If part of the contact cannot be read right now, the answer still comes back with unavailable listing what is missing: profile_extras means starred, created_at, updated_at and web_visitor_id are null because they are unknown; conversations means the timeline is empty because it could not be read. Retry later for those parts.
Try it
Query (1)
International format, e.g. `+15555550123`.
This only reads. It uses your real data and changes nothing.
Code and response
curl -X GET 'https://mcp.wa-api.cloud/v1/contacts/lookup?phone=%2B15555550123' \ -H "Authorization: Bearer $API_KEY"
The code reads your key from $API_KEY.
Parameters
| Field | Type | What it is |
|---|---|---|
| phonerequired | string · query | International format, e.g. +15555550123.3–32 characters |
Headers
| Field | Type | What it is |
|---|---|---|
| Authorizationrequired | header | Bearer $API_KEY — your API key. |
| Api-Version | header | The API version to use, e.g. 2026-10-01. Default: the version your key is pinned to.one of: 2026-10-01 · pattern ^\d{4}-\d{2}-\d{2}$ |
Response 200
The contact.
| Field | Type | What it is |
|---|---|---|
| idrequired | string | |
| namerequired | string or null | |
| phonerequired | string or null | As the platform shows it to this staff member: E.164 digits, or masked (e.g. "*******12345") when the workspace hides numbers from agents. Never unmasked here. |
| phone_maskedrequired | boolean | |
| whatsapp_user_idrequired | string or null | |
| dndrequired | boolean | Do-not-disturb: the contact receives no broadcasts/marketing. |
| starredrequired | boolean or null | null only when it could not be read this time (unavailable includes profile_extras). |
| created_atrequired | string or null | |
| updated_atrequired | string or null | |
| string or null | ||
| web_visitor_id | string or null | |
| tags | array of object | |
| idrequired | string | |
| namerequired | string or null | |
| groups | array of object | |
| idrequired | string | |
| namerequired | string or null | |
| attributes | array of object | Every custom field value this staff member may see (manager-only fields are hidden from agents; deleted fields never appear), at most 100. Text values longer than 2000 characters are clipped. |
| keyrequired | string | The custom field key (as in GET /v1/custom-fields). |
| labelrequired | string or null | The field label shown in the panel. |
| typerequired | string or null | text, textarea, number, int, float, decimal, email, phone, url, select, radio, multiselect, checkbox, boolean, date or datetime. |
| valuerequired | any | The value as the panel shows it: text; checkbox/boolean "Yes"/"No"; date "YYYY-MM-DD"; datetime "YYYY-MM-DD HH:MM:SS" (UTC); multiselect "a, b"; int/float numbers; decimal a string with 8 decimals. |
| displayrequired | string or null | value as text. |
| typed_valuerequired | string | number | boolean | array of string or null | value typed by the field type: number/int/float/decimal → number; checkbox/boolean → true/false; date → "YYYY-MM-DD"; datetime → ISO-8601 UTC; multiselect → array of the chosen values; select/radio/text/… → string. null when empty or unreadable. |
| conversations | array of object | Newest first (at most 10), a timeline summary; read messages with the inbox tools. |
| idrequired | string | |
| channel_idrequired | string or null | |
| staterequired | string or null | |
| assignedrequired | boolean | |
| assigned_staff_idrequired | string or null | |
| created_atrequired | string or null | |
| last_activity_atrequired | string or null | |
| last_activity_at | string or null | Latest conversation activity (from the conversation list). |
| unavailable | array of string | Present only when part of the contact could not be read this time (retry later for it): profile_extras = starred, createdAt, updatedAt and webVisitorId are null because they are unknown, not empty; conversations = the timeline (and lastActivityAt) is empty because it could not be read, not because there are none. |
Errors
Errors are application/problem+json. Branch on code.
| Status | Code | When |
|---|---|---|
| 400 | invalid_input | A field is missing or has the wrong format. |
| 401 | unauthenticated | The Authorization header is missing, the key is unknown, expired or revoked. |
| 403 | entitlement_required | The workspace's plan does not include API access ( |
| 403 | insufficient_scope | The key does not have the permission this operation needs. |
| 404 | not_found | No contact has this number. |
| 429 | rate_limited | The key or workspace went over its rate limit. Wait for |
| 503 | upstream_unavailable | A service behind the API is briefly unavailable. Safe to retry with backoff. |
Examples
Look up by phone
Response 200
{
"id": "48213",
"name": "Jane Doe",
"phone": "+15555550123",
"phone_masked": false,
"email": "jane@example.com",
"dnd": false,
"starred": false,
"tags": [
{
"id": "17",
"name": "vip"
}
],
"groups": [
{
"id": "5",
"name": "Newsletter"
}
],
"created_at": "2026-09-20T08:14:03Z",
"updated_at": "2026-09-23T16:40:11Z",
"whatsapp_user_id": null
}Operation path
The same operation is also at POST /v1/ops/crm_get_contact, with every field in the JSON body.