Your own ids
Push and look up vehicles, listings, contacts, businesses, deals and tasks by the ids your own systems use, so a bridge keeps no mapping table of its own.
TL;DRAI summary
You can use your own existing IDs for vehicles, listings, and other records in Cypress. This chapter shows you how to send your IDs to Cypress and how to look up records using your IDs, so you don't have to keep track of Cypress's internal IDs.
Your systems already have ids for what they send us: a unit number in a fleet
database, a stock number in a DMS, a customer number in an ERP. Send them as
externalIds, and Cypress keeps the mapping for you: you push and look up by
your own id, and never keep a table of Cypress ids on your side. Since 1.5.0.
The shape
"externalIds": [
{ "source": "fox-access", "id": "U-10442" },
{ "source": "erp", "id": "CUST-0093" }
]source is your name for the system: letters, digits, dot, dash or underscore,
up to 40 characters. id is that system's id for the record, up to 128
characters. A record has one id per source, at most ten sources.
The rules
| Rule | What it means |
|---|---|
| Unique per source in your organization | Two contacts of your book can't both be erp:CUST-0093. Another organization's same id is its own. |
| Set or replaced per source | Sending erp:CUST-0094 for a contact that had erp:CUST-0093 replaces it. |
| Never removed by omission | A write that leaves externalIds out, or names fewer sources, keeps the ids it doesn't mention. |
| Refused, not moved | An id another record of the same kind holds answers 409 EXTERNAL_ID_TAKEN, and nothing is written. taken names the record that holds it (vehicleId, listingId, contactId, businessId, dealId or taskId). |
| Gone with the record | Deleting a record deletes its ids. |
A contact or a business POST opens the record your book already has (the same
address, the same name or domain). If that record holds the id you send, the
write goes ahead; if another record does, it is refused.
Where they go
| Record | Set on | Read on | Look up |
|---|---|---|---|
| Vehicle | POST /api/v1/vehicles, /vehicles/bulk, PATCH /vehicles/{id} | every vehicle | GET /api/v1/vehicles?externalId=<source>:<id> |
| Listing | POST /api/v1/listings, PATCH /listings/{id} | every listing | GET /api/v1/listings?externalId= |
| Contact | POST /api/v1/contacts, PATCH /contacts/{id} | every contact | GET /api/v1/contacts?externalId= |
| Business | POST /api/v1/businesses, PATCH /businesses/{id} | every business | GET /api/v1/businesses?externalId= |
| Deal | POST /api/v1/deals, PATCH /deals/{id} | every deal | GET /api/v1/deals?externalId= |
| Task | POST /api/v1/tasks, PATCH /tasks/{id} | every task | GET /api/v1/tasks?externalId= |
A lookup answers a list of zero or one item, so "not mapped yet" is an empty
list, never a 404. The first colon separates the source from the id: an id may
contain colons.
A PATCH with externalIds alone changes only your ids. On a dry run
(?dryRun=true), the ids are checked and listed in the changes, and nothing is
written.
Many at once
POST /api/v1/contacts/bulk, /businesses/bulk, /tasks/bulk and
/listings/bulk take up to 100 rows, { "items": [ … ] }, each the body a
single POST takes. A listing row that names a listing changes its prices
and channels under the same price rules as a PATCH (its vehicle and
listingMode stay); one that names none is listed on its vehicleId. Each row is
matched by its externalIds:
| The row's ids | What happens | Row status |
|---|---|---|
| Name a record of your organization | That record is changed, as a PATCH would change it | 200 |
| Name none | A new record is made (a contact or business may open the one your book already has, by address or name, as a POST does) | 201 (200 when opened) |
| Name two different records | The row is refused, EXTERNAL_ID_TAKEN | 409 |
Every row goes through the same rules as one at a time, in order, so a later row
sees what an earlier one wrote. One bad row never fails the batch: it answers
its own status, code and errors, and the request answers 200 with
created, updated and refused counts. A matched task changes its title,
notes, due date, channel, assignee and business; what else it is about is set
when it is made. ?dryRun=true checks every row and writes nothing. An
Idempotency-Key makes a retry of the whole request answer the same, once.
{
"items": [
{ "index": 0, "status": 201, "id": "cm…" },
{ "index": 1, "status": 200, "id": "cm…" },
{ "index": 2, "status": 422, "code": "INVALID", "errors": ["email: Required"] }
],
"created": 1, "updated": 1, "refused": 1
}Two writers at once
When two pushes claim the same id at the same moment, the first one keeps it.
The other record is still written, and its answer carries a warnings line
naming the ids that were not saved. Look the id up, then fix the mapping on your
side.