Skip to main content
Everything runs on the Tomorro REST API: three counterparty endpoints and one picklist endpoint. How you read and write the ERP depends on your ERP.

1. Technical prerequisites

1

1.1 - Create Tomorro superadmin account

An existing admin creates a dedicated superadmin account from Settings > Members (e.g. automation@customer.com), not a personal account.
  • The API key is bound to a member, not to the organization. Every write performed through the API is attributed to that member and inherits its permissions.
  • Consequence: the counterparty history shows this account as the author of every creation and update made by the integration. A named account such as “ERP automation” keeps it readable.
  • Recommended: no personal mailbox behind it, and exclude it from Tomorro notification settings.
2

1.2 - API key

Generate the API key from that superadmin account. It does not expire. It is sent on every REST call in the x-api-key header: Step 1: Get your API key
3

1.3 - Counterparty smart fields in Tomorro

Every ERP field other than the name needs a smart field on the counterparty.
  • Libraries > Dynamic components > Smart fields > New, with Data related to = Counterparty smart field.
  • Pick the type matching the ERP: Text for SIRET, address and city, Single-choice selector for the industry (options = the ERP values, see 3.5).
  • Copy each smart field id from the URL of the field (last segment) next to your mapping (Non-Technical scoping):
4

1.4 - ERP: add the ID tomorro column

Add a text column ID tomorro to the counterparty table, empty for every counterparty. The integration fills it; users must not edit it. If the ERP supports it, make it read-only for users.

2. Flows

Flow 0 - [ERP → Tomorro → ERP] Initialisation

1

Step 0 - Triggered by hand

Run once, when the integration goes live. Take every counterparty whose ID tomorro is empty (and that matches your scope, see Non-Technical scoping). Re-running it is safe: linked counterparties are skipped.
2

Step 1 - Get the picklist option ids

Once per run, for each picklist smart field:
Response 200:
  • Build a label → id table from data[].translations[].value and data[].id. Match labels case-insensitively.
  • Up to 50 options per page: follow pagination.next_cursor with after if there are more.
  • integrationMappings can hold your ERP codes for each option, to translate on codes instead of labels.
3

Step 2 - Create the counterparty in Tomorro, one call per ERP row

Response 201:
  • name is the only required field. status defaults to active.
  • fields keys are smart field ids (1.3). Text values as strings, picklists as the option id (step 1, 3.5). Leave a field out rather than sending an empty string.
  • The body is strict: an unknown top-level key is refused with a 400. An unknown smart field id is refused too.
  • Read the new id under data.id. In the response, each field comes back as { type, value }, one entry per counterparty smart field of the workspace, filled or not.
  • Duplicates: Tomorro does not deduplicate counterparties. Calling this endpoint twice creates two counterparties. This is why Flows 0 and 1 only take counterparties with an empty ID tomorro.
4

Step 3 - Write the Tomorro id back to the ERP

Out of scope (depends on the ERP). Write data.id from step 2 into the ID tomorro column, straight away: until it is written, a new run would create the counterparty a second time.
Rate limit: no need to slow the calls down. If Tomorro answers 429, retry with backoff: the Make example retries automatically, 3 times, 1 minute apart.

Flow 1 - [ERP → Tomorro → ERP] Counterparty created in the ERP

1

Step 0 - Triggered by the ERP

Out of scope. A counterparty is created in the ERP: ERP event or webhook if it has one, otherwise poll the counterparties created since the last run. Skip it if its ID tomorro is already filled or its name is empty.
2

Steps 1 to 3 - Same as Flow 0

Get the option ids, create the counterparty, write data.id back to the ERP.

Flow 2 - [ERP → Tomorro] Counterparty updated in the ERP

1

Step 0 - Triggered by the ERP

Out of scope. A counterparty is updated in the ERP. Only counterparties with an ID tomorro go further.
2

Step 1 - Read the current counterparty and the option ids

Response 200: same shape as the creation response. Read data.name and data.fields["<smart field id>"].value. Get the option ids as in Flow 0 step 1.
3

Step 2 - Compare, then update only what changed

Compare every mapped ERP value with the Tomorro value (picklists on the option id). If nothing differs, stop: the ERP change was on another column, or it is the echo of Flow 1 or Flow 3 (3.3). Otherwise:
Response 200: the updated counterparty.
  • Only the keys you send change. Send name only if it changed, and only the smart fields that changed.
  • null clears a smart field (the value was emptied in the ERP).
  • 404: the counterparty no longer exists in Tomorro (deleted, or wrong ID tomorro). Apply the rule chosen in 3.6.
  • To archive a counterparty deactivated in the ERP, send { "status": "archived" }; { "status": "active" } restores it.

Flow 3 - [Tomorro → ERP] Counterparty updated in Tomorro

1

Step 0 - Scheduled, every day at 8:00

Read the last updatedAt you processed, saved at the end of the previous run. On the first run, look back 24 hours.
2

Step 1 - List the counterparties updated since the last run

One call returns the latest updates first:
Keep the counterparties whose updatedAt is after the saved value, then save the newest updatedAt for the next run. Get the option ids once (Flow 0 step 1).
  • updatedAt moves on every change of the counterparty, smart fields included.
  • If all 50 counterparties of the page changed since the last run, more are waiting: follow pagination.next_cursor with after.
  • Counterparties changed by Flow 2 come back here too: the comparison of step 2 finds nothing to write (3.3).
3

Step 2 - Update the ERP with the values that differ

Out of scope (depends on the ERP). For each Tomorro counterparty, find the ERP row whose ID tomorro equals that counterparty’s id. No row: the counterparty exists only in Tomorro, ignore it (see Non-Technical scoping). Otherwise translate picklist option ids back to labels, compare with the ERP and write only the differences. No difference, no write: an unnecessary write would fire Flow 2 again.

3. Technical references

Reference material: conventions, the counterparty object and error handling. Read it once, then come back to it while implementing the flows above.

3.1 - API conventions

  • REST only. The whole integration runs on the public REST API.
  • Base URL: https://api.tomorro.com/v2
  • Authentication: x-api-key: <your api key> on every call. A missing or unknown key returns 401.
  • Versioning: optional tomorro-version header, defaults to the latest version.
  • Rate limit: a 429 means too many calls in a short time. Retry with backoff.
  • Sandbox: available on request. It is an empty sandbox, not a copy of your production workspace.
  • Content type: application/json
  • Response envelope: every successful JSON response is wrapped in a data object (errors come as { error, meta }, see 3.4). Read data.id, data.fields and so on.
  • Full reference: Counterparties - Tomorro API

3.2 - Counterparty endpoints and fields

3.3 - Loops and conflicts

Flows 1 and 3 write into the ERP (so Flow 2 sees an updated counterparty), Flow 2 writes into Tomorro (so Flow 3 reads a different counterparty). Without care, a change bounces forever.
  • Compare before writing, in both directions. Flow 2 only sends a PATCH when an ERP value differs from Tomorro; Flow 3 only writes the ERP when a Tomorro value differs. The echo of a write finds identical values and stops.
  • Compare normalised values: trim spaces, treat empty and null the same, compare picklists on the option id.
  • Same-day conflict: if a field is changed in both systems between two runs of Flow 3, the ERP value wins, since Flow 2 runs first.

3.4 - Error handling

Every endpoint follows the standard error format of the REST API. Error envelope
  • error.statusCode is a string, not a number.
  • meta.requestId is the value to quote to Tomorro support when reporting a failing call. Log it.

3.5 - Picklists

  • A picklist value is stored as the option id, not its label. Send "Logistics" and the API accepts it, but Tomorro shows an empty field.
  • Get the ids with GET /v2/smart-fields/b25c969a-2a1c-4903-be86-10269aeb5e84/options and translate label ↔ id in the integration, in both directions.
  • Align the labels on both sides first (here, Software & Saas in Tomorro renamed Software & SaaS). A label missing from Tomorro is left empty, never invented.

3.6 - Edge cases

  • Link: an ID tomorro column in the ERP. Never match on name or SIRET.
  • Existing counterparties before Flow 0: clean them up, or link them by filling ID tomorro by hand (Flow 0 skips linked rows).
  • Counterparty deactivated in the ERP: archive the counterparty (status: archived) or ignore.
  • Counterparty deleted in Tomorro: Flows 2 and 3 get a 404. Alert, or clear ID tomorro.
  • Loops: every update flow compares before writing, so the echo of a write stops by itself (3.3).
  • Triggers: prefer an ERP webhook or event, so Flows 1 and 2 run as soon as a counterparty changes. Without one, poll the counterparties changed since the last run, e.g. every 15 minutes.