Overview
When Spree is connected to other systems, the same product lives in several places at once. Your ERP knows it asMAT-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
erpkey. - One record per key. Within a store,
erp:MAT-100names exactly one product.
System keys
A system key is a short lowercase name made of letters, digits and underscores, such aserp, 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
Sendexternal_references with any create or update on the Admin API. It accepts the same map the API returns:
- 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
pimnever touches theerpkey. - 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 includeexternal_references as a flat map — the same shape you send:
Response
Addressing records by your keys
For any record type listed in What can carry external references, you can writeexternal:<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.
404, exactly as they would for its Spree ID.
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.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 with422:
Response
Filtering companies by key
Companies can be filtered by their references, which helps when reconciling a list of accounts against an ERP: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 maperp: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.
Related
- 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

