Extension points

External ID

Map OnePageCRM contacts, companies, and deals to records in your own system with a unique External ID custom field.

Last updated Jul 17, 2026

External ID lets your integration store its own stable identifier against OnePageCRM records. Use it to:

  • Keep a bidirectional mapping between OnePageCRM IDs and IDs in your system without maintaining a separate lookup table.
  • Find the right CRM record from a webhook, an API response, or a support ticket in a single lookup.
  • Avoid duplicates when syncing: upsert by your ID instead of guessing by name or email.

How it works

An External ID is a custom field type (external_id), available on contacts, companies, and deals. You define one External ID field per external system, then store one string value per record.

Two properties make it different from a plain text field:

  • Unique — a value can exist on only one record per field. Writing a duplicate is rejected.
  • Exact lookup — because values are unique, filtering by External ID returns exactly one record or none, never a list to disambiguate.
ConstraintValue
Resourcescontacts, companies, deals
Value typestring
Max value length312 characters (longer values are truncated)
Values per record per field1
Uniquenessone record per (field, value) pair
Field name lengthup to 35 characters

1. Create the field (one-time, admin)

Creating the field is a one-time setup step, done by an account admin in the app: open Contact Fields (or Company / Deal Fields) in your account settings and click + Add. Set a Field name, choose External ID as the Field type, and optionally paste a Third-party app URL template — your app’s record URL with the unique identifier replaced by [ID] (see linking back). Mandatory works like any other custom field and defaults to Not required.

The New custom field form with field type External ID and a third-party app URL template input

If you’re scripting account setup with an admin’s API key, the field can also be created via the API — POST /api/v3/custom_fields.json (company_fields / deal_fields for the other resources) with { "name": "Acme ID", "type": "external_id" }. Two caveats:

  • Not available to OAuth apps. Field management requires API-key auth from an admin user; an OAuth token gets 403 regardless of scope. If you’re building a third-party integration, make field creation part of your customer’s onboarding instructions instead.
  • No URL template. The API accepts only name and type; the template can only be set in the in-app form above.

A field’s type cannot be changed after creation.

2. Find the field’s id

Everything else your integration does works with either auth method. List the fields and find yours by name — do this once at install time and store the id:

curl -H "Authorization: Bearer ACCESS_TOKEN" \
  https://app.onepagecrm.com/api/v3/custom_fields.json

3. Set a value

Pass the field and value in the custom_fields array when creating or updating a contact (use company_fields on companies and deal_fields on deals). The flat item shape works on all three resources:

curl -u "USER_ID:API_KEY" \
  -X PUT "https://app.onepagecrm.com/api/v3/contacts/CONTACT_ID.json?partial=true" \
  -H "Content-Type: application/json" \
  -d '{
    "custom_fields": [
      { "id": "FIELD_ID", "value": "cus_8c1ab2" }
    ]
  }'

There’s also a nested item shape, where the field reference is wrapped in a resource-specific key — custom_field on contacts, company_field on companies, deal_field on deals — with value alongside the wrapper:

{ "custom_field": { "id": "FIELD_ID" }, "value": "cus_8c1ab2" }

Prefer the flat shape: it’s identical on every resource.

You can reference the field by name instead of id if you prefer. To clear a value, send an empty string.

If the value already exists on another record, the write fails with a validation error:

External ID value='cus_8c1ab2' for custom field ID=FIELD_ID is already taken

That’s your duplicate detection. Treat it as “this record is already mapped” and look the existing record up instead.

4. Look up a record by External ID

Filter any list endpoint with custom_field_id + custom_field_value:

curl -u "USER_ID:API_KEY" \
  "https://app.onepagecrm.com/api/v3/contacts.json?custom_field_id=FIELD_ID&custom_field_value=cus_8c1ab2"

The same pair of parameters works on /companies.json and /deals.json. Because values are unique, the result contains either exactly one record or none.

5. Read it back

Custom field values come back on every record read, with the full field definition alongside the value:

{
  "custom_fields": [
    {
      "custom_field": {
        "id": "5aad9b039007ba28c9ebad56",
        "name": "Acme ID",
        "type": "external_id"
      },
      "value": "cus_8c1ab2"
    }
  ]
}

Responses use the same resource-specific wrapper keys: custom_field on contacts, company_field on companies, deal_field on deals.

Sync pattern: idempotent upsert

That uniqueness makes upserts safe to retry. For each record in your system:

  1. Look up by External ID (?custom_field_id=...&custom_field_value=...).
  2. Found? Update that record by its OnePageCRM id.
  3. Not found? Create the record with the External ID set in the same request.
  4. Create failed with “already taken”? Another worker beat you to it — go back to step 1.

Running the same sync twice produces the same result. No duplicate contacts, no separate mapping table to keep consistent.

For the reverse direction, webhook payloads include the record’s custom field values — read your External ID straight out of the event to find the matching record on your side.

An External ID field can carry a URL template. Set one and OnePageCRM renders the value as a clickable link on the record — one click from a contact to the same customer in your app:

https://billing.example.com/customers/[ID]

[ID] is replaced with the field’s value — for example, https://app.service.com/[ID] renders the value 12abc34def as a link to https://app.service.com/12abc34def.

Set the template in the Third-party app URL template input when an admin creates or edits the field in the OnePageCRM web app; the API returns it as a read-only url_template attribute on the field.

See also

  • Custom Button — deep-link from a contact or deal into your app using template variables, including custom field values.
  • Webhook payloads — events carry the record’s custom field values, so you can read your External ID straight out of the payload.