Skip to main content

Overview

When Spree is connected to other systems, the same product lives in several places at once. Your ERP knows it as MAT-100, your PIM as SKU-88412, and Spree as prod_86Rf07xd4z. External references are how Spree remembers those other keys. Each record can carry one key per system, and every integration can then find, create and update records using the key it already knows — without ever storing a Spree ID. They solve three problems that come up in every integration:
  • Mapping. Which Spree product is ERP item MAT-100?
  • Repeatable feeds. A nightly import cannot know whether Spree has seen a row before. Sending the same row twice must update the record, not create a duplicate.
  • Several systems at once. A PIM sync must never erase the key the ERP wrote.

How references are stored

An external reference has three parts: Two rules keep the mapping unambiguous, and the database enforces both:
  • One key per system per record. A product has at most one erp key.
  • One record per key. Within a store, erp:MAT-100 names exactly one product.

System keys

A system key is a short lowercase name made of letters, digits and underscores, such as erp, akeneo or legacy_pim. Spree lowercases and trims what you send, so ERP and erp are the same system. The system does not have to be a connected integration. A nightly CSV from a legacy system that has no live connection still needs somewhere to record its keys. When a connector does exist, use the same name it uses, so the connector, its references and its settings page all agree.

What can carry external references

Customers are deliberately absent. A customer account can shop in more than one store, so a store-level key for it has no single owner. In B2B, the buyer’s ERP identity belongs on their company instead.

Writing references

Send external_references with any create or update on the Admin API. It accepts the same map the API returns:
A list is accepted too, which some feeds find more natural:
What a write changes:
  • Systems you name are set. A system the record has no key for gets one; a system it already has gets the new key.
  • Systems you don’t name are left alone. A PIM sending only pim never touches the erp key.
  • A blank key removes the reference. Send { "erp": "" } to unlink a record from the ERP.

Reading references

Admin API responses for every record above except sellers include external_references as a flat map — the same shape you send:
Response
External references never appear in the Store API. Which ERP a merchant runs, and the keys records have in it, is back-office information. In the dashboard, references show in the JSON view on each record’s detail page. There is no form for editing them: they are written by integrations and read by whoever is debugging a sync.

Addressing records by your keys

For any record type listed in What can carry external references, you can write external:<system>:<key> in the path instead of its Spree ID. An integration that only ever learned the ERP’s key can then read, update and delete without first asking Spree for the record’s ID.
The lookup follows the same rules as a Spree ID. It only finds records in the current store, and an API key or admin user that cannot see the record gets a 404, exactly as they would for its Spree ID.
Use this form only for keys made of letters, digits, dashes, underscores and colons. A key containing a slash or a dot cannot be part of a URL path; address that record by its Spree ID instead.

Repeatable feeds

A create that names a key Spree already knows updates that record instead of creating a new one. A feed can therefore send every row on every run, and the result is the same as if it had sent each row once.
The update needs the same permission an ordinary update would, so a key that may create records but not edit them cannot use a create to change one. Image feeds work the same way. Media created from a URL with external_references is recorded under those keys, and a later run with the same key finds the existing image instead of adding a second copy.

When a key is already taken

If an update names a key that already belongs to a different record, Spree keeps the record’s other changes and answers with 422:
Response
This usually means two records in Spree map to one record in the other system — for example, a product that was duplicated by hand. Remove the reference from one of them (send a blank key), then retry.

Filtering companies by key

Companies can be filtered by their references, which helps when reconciling a list of accounts against an ERP:
For every other record, look it up by its key with the external:<system>:<key> path form above.

References belong to a store

A reference is owned by the store its record belongs to. Two stores can each map erp:MAT-100 to their own product without colliding, and a key from one store never finds a record in another. A feed that serves several stores sends its rows to each store separately.

External references, custom fields or metadata?

All three can hold “an ID from another system”, but only one is built for it. If an integration needs to find a record again by a key it owns, use an external reference. If a merchant should see and edit the value, use a custom field. Anything else your code needs to remember belongs in metadata.
  • ERP — feeding stock and orders from an ERP
  • PIM — syncing product content from a PIM
  • Imports & Exports — file-based feeds
  • Companies — B2B accounts and their ERP identity
  • Admin SDK — the TypeScript client used in the examples