---
title: "Recipe: send new orders to an ERP by HTTP request"
description: "Post a summary of every new order to your ERP or any API with a bearer token: secrets for URL and token, a JSON body with the json filter, retries."
canonical: "https://docs.workflow-suite.app/recipe-send-orders-to-erp"
---

# 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](https://docs.workflow-suite.app/secrets.md).
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**:

```liquid
{
  "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](https://docs.workflow-suite.app/liquid-in-fields.md).

## 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:

```liquid
{{ event.payload | json }}
```

2. **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.
3. 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.
4. **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](https://docs.workflow-suite.app/automatic-retries.md).

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:

```liquid
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](https://docs.workflow-suite.app/trigger-filters.md).

## The other direction

To let the ERP write to Shopify, for example stock by SKU, see [Recipe: let another system set stock by SKU](https://docs.workflow-suite.app/recipe-set-stock-by-sku-webhook.md).

> [!NOTE]
> **Personal data leaves your store here**
> An order contains personal data. When a workflow sends it to another system, you decide what is sent and to whom. Send only the fields the other system needs.
