OQL · Entities
Contacts
OQL field reference for contacts. The people in your CRM and their associated company, communication details, and metadata.
Maintained by the OnePageCRM engineering team · Last updated Oct 1, 2026
Contacts are the people in your CRM and their associated company, communication details, and metadata.
Default sort: weight descending. When you omit order_by,
contacts return in Action Stream priority
order (the same
order the OnePageCRM app uses).
Fields
Legend: F filterable, S sortable, A aggregatable, G groupable.
| Field | Type | F | S | A | G | Description |
|---|---|---|---|---|---|---|
id | ID | Y | Y | — | — | Contact ID |
first_name | string | Y | Y | — | — | First name |
last_name | string | Y | Y | — | — | Last name |
company_name | string | Y | Y | — | — | Company name (display text) |
company_id | ID | Y | — | — | Y | Linked company record ID |
job_title | string | Y | Y | — | — | Job title |
status | string | Y | — | — | Y | Status name (Lead, Customer, …). The same column as status_id, read and written by name. |
status_id | string | Y | Y | — | Y | Status system_id (e.g. lead, prospect, customer). Defaults to lead on create. On update, may propagate to every contact in the same company. |
owner_id | ID | Y | — | — | Y | Owner user ID |
lead_source | string | Y | — | — | Y | Lead source name. The same column as lead_source_id, read and written by name. |
lead_source_id | string | Y | Y | — | Y | Lead source system_id |
tags | string[] | Y | — | — | Y | Tag names. On update, may propagate to every contact in the same company. |
starred | boolean (per user) | Y | — | — | — | Starred by the calling user. Writable. |
sales_cycle_closed | boolean (per user) | Y | — | — | — | Whether the calling user closed the sales cycle with this contact (read-only) |
pending_deal | boolean | Y | — | — | Y | Whether the contact has at least one pending deal (read-only) |
background | string | — | — | — | — | Background text. Select only, plus contains search. |
address | string | Y | — | — | — | Primary street address |
city | string | Y | Y | — | Y | Primary address city |
state | string | Y | Y | — | Y | Primary address state or region |
zip_code | string | Y | — | — | — | Primary address postal code |
country_code | string | Y | Y | — | Y | ISO 3166-1 alpha-2 country code |
address_type | string | Y | — | — | Y | One of work, home, billing, delivery, other |
created_at | time | Y | Y | — | Y | Record creation timestamp |
modified_at | time | Y | Y | — | Y | Last modification timestamp |
last_activity_date | time | Y | Y | — | Y | Most recent activity (note, call, meeting, deal) |
weight | number (virtual) | — | Y | — | — | Action Stream sort weight. Default sort field. |
emails | array | Y | — | — | — | {address, type} objects |
phones | array | Y | — | — | — | {number, type} objects |
urls | array | Y | — | — | — | {url, type} objects |
Notes
- Writing
status_idortagscan change other contacts. If the contact belongs to a company withsync_statusorsync_tagsset, that write applies to every contact in the company, not just the one you addressed. Tags are replaced wholesale rather than merged, so the other contacts’ tags are overwritten. Check the flags oncompaniesbefore writing either field. statusandstatus_idare one field, the name and the id, and so arelead_sourceandlead_source_id:{"status": "Customer"}and{"status_id": "customer"}are the same filter. See Concepts › Names and ids for the rules. If two statuses share a display name the name covers both: filtering returns contacts on either, grouping merges them, and a write keeps whichever id the contact already has.tagsuses bare-string equality for single-tag membership ({"tags": "VIP"}) andinfor multi-tag overlap ({"tags": {"in": ["VIP", "Hot"]}}). Grouping bytagsgives a per-tag breakdown: each tag is its own bucket, so a contact tagged bothVIPandHotis counted under each.count()per tag is exact; summing an unrelated field double-counts multi-tag contacts.starredis per-user. The value reflects whether the calling user has starred the contact, not whether anyone has. Writingtrueorfalsestars or unstars it for that user alone.sales_cycle_closedis per-user too, and read-only here. It is true when the calling user closed the sales cycle with the contact, which also deleted that user’s open next actions on it. So a contact with no next action is either closed (true) or stalled (false). A colleague may still have the cycle open. Assigning a new action reopens it.pending_dealis true when the contact has at least one deal stillpending. Won and lost deals do not count, sofalsedoes not mean the contact has never had a deal — it means none are open right now. It is a flag, not a figure: for values, querydealswithcontact_id.emails,phones,urlsare arrays of objects. Filter using dotted subfields:emails.address,emails.type(work,home,other)phones.number,phones.type(work,mobile,home,direct,fax,other)urls.url,urls.type(website,blog,twitter,linkedin,facebook,instagram,xing,other)
- Lookups:
company(viacompany_id). Pull the linked company record’s fields inline ascompany.<field>— for examplecompany.name,company.city, orcompany.country_code— inselect,where, andorder_by. Always name a subfield:companyon its own is a lookup, not a field, and selecting it bare is rejected. See Concepts › Lookups. company_namevs thecompanylookup.company_nameis text stored on the contact and is set even when no company record is linked;company.<field>reads the linked record. A contact with acompany_namebut nocompany_idreturnsnullfor everycompany.<field>.- Custom fields are queryable by name as
custom_fields.<name>inselect,where, andorder_by; selectcustom_fields.*(or*) to return all of them. Filterability and sortability depend on the field’s type. Numeric custom fields can also be aggregated ({ "sum": ["custom_fields.<name>"] }), andmin/maxwork on date custom fields.group_byworks on custom fields whose type supports it (checkdescribe);distinctdoes not — group by the field instead. Usedescribeto discover an account’s custom-field names and types.
Example queries
Open leads owned by me, top of stream:
{
"from": "contacts",
"where": { "owner_id": "ME()", "status_id": "lead" },
"limit": 25
}
Contacts I’ve starred:
{
"from": "contacts",
"where": { "starred": true }
}
My customers, by name rather than by id:
{
"from": "contacts",
"select": ["first_name", "last_name", "status", "lead_source"],
"where": { "status": "Customer", "owner_id": "ME()" }
}
Contacts I have not finished with that mention golf:
{
"from": "contacts",
"where": {
"owner_id": "ME()",
"sales_cycle_closed": false,
"background": { "contains": "golf" }
}
}
Contacts whose linked company is in Ireland, with the company’s city:
{
"from": "contacts",
"select": ["first_name", "last_name", "company_name", "company.city"],
"where": { "company.country_code": "IE" },
"order_by": [{ "company.name": "asc" }]
}
Contacts at an Irish phone number, with no activity in the last 30 days:
{
"from": "contacts",
"where": {
"phones.number": { "like": "+353%" },
"last_activity_date": { "<": { "DAYS_AGO": [30] } }
}
}
Contacts by country:
{
"from": "contacts",
"select": ["country_code", "count()"],
"where": { "country_code": { "is not": null } },
"group_by": ["country_code"]
}