Recipe: send new orders to an ERP

Goal: every new order is posted to your ERP, or any other API that expects a bearer token: number, total, email and line items.

Template: Send new orders to an API with a token (category Data sync). Steps: 1. Needs: access to orders, Shopify's approval for protected customer data, and the URL and token of the other system.

Create it

  1. Open Secrets and create two secrets: ORDER_API_URL with the URL that should receive the order, and ORDER_API_TOKEN with the token. See Secrets.
  2. In Browse templates, search for token and select Use template on Send new orders to an API with a token.

How it is built

Part Setting
Trigger Order created
HTTP request Method POST, URL {{ secrets.ORDER_API_URL }}
Header Content-Type: application/json
Header Authorization: Bearer {{ secrets.ORDER_API_TOKEN }}

The Body:

{
  "number": {{ event.payload.name | json }},
  "total": {{ event.payload.total_price | json }},
  "currency": {{ event.payload.currency | json }},
  "email": {{ event.payload.email | json }},
  "lines": [{% for line in event.payload.line_items %}{ "sku": {{ line.sku | json }}, "quantity": {{ line.quantity }} }{% unless forloop.last %},{% endunless %}{% endfor %}]
}

Every text value goes through the json filter, which adds the quotes and escapes what would break JSON. The unless forloop.last puts a comma between the lines, but not after the last one. See Liquid in every field.

Make it yours

  1. Shape the body the way your ERP expects it. The variable button next to the field lists every field of the order. To send the whole order as Shopify delivers it, the body is one line:
{{ event.payload | json }}
  1. Test as a preview. No request is sent; the step shows the URL, headers and body it would have sent, with the secrets masked. Check that the body is valid JSON.
  2. Choose Run for real once, against a test endpoint of your ERP if it has one. Afterwards the variable picker offers the real fields of the response.
  3. Save and Turn on.

When the ERP is down

Under If it fails, the step retries automatically, 3 extra tries by default:

  • 425, 429 and 503 mean the ERP did not work on the request. It is sent again.
  • A timeout or another 5xx answer leaves open whether the order arrived. A POST is not sent again, because that could create the order twice.

In that case the run ends as Failed and you get the failure alert. When the ERP is back, open the run and select Run again. See Automatic retries.

If your ERP accepts an idempotency key, add a header with a value that is the same for every attempt for this order, for example:

order-{{ event.payload.id }}

Then a repeated request is harmless on the ERP's side, and Run again is always safe.

Use the answer

Many ERPs answer with their own id. Save it on the order so both systems can find each other:

  1. Add Set order metafield after the request.
  2. Order id {{ event.payload.admin_graphql_api_id }}, a Namespace and Key of your choice, and as value the id from the response, for example {{ steps.send.output.body.id }}.

Only paid orders, or only some

  • Use the trigger Order paid instead, as the template Send paid orders to another system does.
  • Add a trigger filter, for example only orders with a certain tag or from one sales channel. Filtered orders start nothing and are not counted. See Trigger filters.

The other direction

To let the ERP write to Shopify, for example stock by SKU, see Recipe: let another system set stock by SKU.