> For the complete documentation index, see [llms.txt](https://savefee.gitbook.io/savefee/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://savefee.gitbook.io/savefee/integration-guide/track-an-order.md).

# Track an order

## Reading one order

```bash
curl https://api.savefee.io/v1/orders/65f1a2b3c4d5e6f708192a3b \
  -H "Authorization: Bearer $SAVEFEE_API_KEY"
```

```json
{
  "order": {
    "orderId": "65f1a2b3c4d5e6f708192a3b",
    "status": "fulfilled",
    "receiver": "T…",
    "resource": "ENERGY",
    "resourceAmount": 50000,
    "remainAmount": 0,
    "isMatching": false,
    "durationSec": 3600,
    "totalCostSun": 1400000,
    "createdAt": "2026-08-07T03:47:44.439Z"
  }
}
```

Orders are scoped to their owner, so a key can only read the orders it created.

{% hint style="info" %}
Store the `orderId` from the `201` response when you place an order. It is how you read the order back later.
{% endhint %}

## Order lifecycle

```
pending  →  matching  →  executing  →  fulfilled
```

A typical order reaches `fulfilled` in well under a minute.

| `status`    | Finished | Meaning                                           |
| ----------- | -------- | ------------------------------------------------- |
| `pending`   | no       | Order accepted and paid for; not yet matched.     |
| `matching`  | no       | Being matched against available energy.           |
| `executing` | no       | Energy is being delegated.                        |
| `fulfilled` | **yes**  | Energy has been delegated. `remainAmount` is `0`. |

{% hint style="warning" %}
**`fulfilled` is the only finished state.** An order that cannot be delegated on the first attempt goes back to `pending` and is matched again, so a status moving backwards is normal and nothing is lost.

Keep polling on every value except `fulfilled`, and treat a status you do not recognise the same way. Writing your handler this way keeps it working as the service evolves.
{% endhint %}

## Knowing when it is done

Two fields tell you, and they agree:

* `status` is `fulfilled`
* `remainAmount` is `0` and `isMatching` is `false`

## Polling versus webhooks

**Webhooks** are the low-latency path: SaveFee calls you when the order is created and again when it is fulfilled. See **Webhooks**.

**Polling** is the simple path, and it is worth keeping as a fallback even when you consume webhooks — your endpoint may be mid-deployment when an event fires.

A reasonable polling strategy:

```
poll after 5s, then every 5s, give up after 5 minutes
```

Do not poll in a tight loop.

## If an order is slow

How quickly an order is matched depends on the energy available in the pool at that moment, so an order can sit in a non-final state longer than usual. If one has not reached `fulfilled` after a few minutes, log it and raise an alert for a human to look at.

{% hint style="warning" %}
**Do not place a replacement order for one that looks stuck.** The original is still live and its energy will still be delegated — a second order buys the same energy twice and charges you twice. There is no cancel; the right move is an alert, not another `POST`.
{% endhint %}
