Skip to content

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 Aug 27, 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.

FieldTypeFSAGDescription
idIDYYContact ID
first_namestringYYFirst name
last_namestringYYLast name
company_namestringYYCompany name (display text)
company_idIDYYLinked company record ID
job_titlestringYYJob title
statusstring (output only)Status display name. Not queryable — use status_id.
status_idstringYYYStatus system_id (e.g. lead, prospect, customer). Defaults to lead on create. On update, may propagate to every contact in the same company — see note below
owner_idIDYYOwner user ID
lead_sourcestring (output only)Lead source display name
lead_source_idstringYYYLead source system_id
tagsstring[]YYTag names. On update, may propagate to every contact in the same company — see note below
starredboolean (virtual)YStarred by the current user
pending_dealbooleanYYWhether the contact has at least one pending deal (read-only)
backgroundstringBackground text (select only)
addressstringYPrimary street address
citystringYYYPrimary address city
statestringYYYPrimary address state or region
zip_codestringYPrimary address postal code
country_codestringYYYISO 3166-1 alpha-2 country code
address_typestringYYOne of work, home, billing, delivery, other
created_attimeYYYRecord creation timestamp
modified_attimeYYYLast modification timestamp
last_activity_datetimeYYYMost recent activity (note, call, meeting, deal)
weightnumber (virtual)YAction Stream sort weight. Default sort field.
emailsarrayY{address, type} objects
phonesarrayY{number, type} objects
urlsarrayY{url, type} objects

Notes

  • Writing status_id or tags can change other contacts. If the contact belongs to a company with sync_status or sync_tags set, 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 on companies before writing either field.
  • Virtual fields (status, lead_source) are display labels resolved from their underlying _id field at query time. They are not queryable at all: you cannot select, filter, sort, or group by them. Use the _id field instead. Selecting one is rejected outright rather than silently ignored. To report the human-readable label, select the _id and map it through the matching context() list — statuses for status_id, lead_sources for lead_source_id.
  • tags uses bare-string equality for single-tag membership ({"tags": "VIP"}) and in for multi-tag overlap ({"tags": {"in": ["VIP", "Hot"]}}). Grouping by tags gives a per-tag breakdown: each tag is its own bucket, so a contact tagged both VIP and Hot is counted under each. count() per tag is exact; summing an unrelated field double-counts multi-tag contacts.
  • starred is per-user. The value reflects whether the calling user has starred the contact, not whether anyone has.
  • pending_deal is true when the contact has at least one deal still pending. Won and lost deals do not count, so false does 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, query deals with contact_id.
  • emails, phones, urls are 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 (via company_id). Pull the linked company record’s fields inline as company.<field> — for example company.name, company.city, or company.country_code — in select, where, and order_by. Always name a subfield: company on its own is a lookup, not a field, and selecting it bare is rejected. See Concepts › Lookups.
  • company_name vs the company lookup. company_name is text stored on the contact and is set even when no company record is linked; company.<field> reads the linked record. A contact with a company_name but no company_id returns null for every company.<field>.
  • Custom fields are queryable by name as custom_fields.<name> in select, where, and order_by; select custom_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>"] }), and min/max work on date custom fields. group_by works on custom fields whose type supports it (check describe); distinct does not — group by the field instead. Use describe to 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 }
}

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"]
}