> 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/place-an-order.md).

# Place an order

## Pricing

Energy is priced per unit, and the unit price depends on how long you hold the energy. Renting it from SaveFee typically costs **65–70% less** than burning TRX for the same resource on-chain.

| `durationSec` | Duration   | Unit price                    |
| ------------- | ---------- | ----------------------------- |
| `60`          | 1 minute   | Base unit price               |
| `300`         | 5 minutes  | Base unit price               |
| `900`         | 15 minutes | Slightly above the base price |
| `3600`        | 60 minutes | The highest of the four       |

```
totalCostSun = amount × unit price
```

{% hint style="info" %}
**There is no fixed price list, and nothing here should be hard-coded.** Every tier is derived from a base unit price that moves with the market.

Quote each order at runtime from **`GET /v1/public/pricing`**, and use `totalCostSun` from the `201` response as the amount you were charged.
{% endhint %}

## How much you can buy

`amount` is between **64,000 and 200,000** energy units inclusive, per item.

The floor is a minimum billable size, not a suggestion: a transaction that only needs 15,000 energy still costs a 64,000-unit order. Batch small payouts into one transaction where you can, and read **Broadcast** if what you actually want is for SaveFee to size and pay for the resource itself — that path has its own, wider bounds.

## How long the energy lasts

`durationSec` is how long the delegated energy stays with the receiver. When it elapses the energy is reclaimed, and **60 minutes is the longest window available**. There is no renewal: an address that needs energy continuously is topped up by placing another order for the next window.

So treat an order as cover for work you are about to do, not as funding an address leaves in place. Buy the duration you need to spend the energy in — a hot wallet sending transactions all day is a stream of short orders, not one long one.

## Request

```
POST /v1/orders
Authorization: Bearer sf_live_…
Idempotency-Key: <unique per logical order>
Content-Type: application/json
```

```json
{
  "items": [
    {
      "toAddress": "T…",
      "amount": 64000,
      "resource": "ENERGY",
      "durationSec": 3600
    }
  ]
}
```

| Field         | Type    | Rules                                                                                     |
| ------------- | ------- | ----------------------------------------------------------------------------------------- |
| `toAddress`   | string  | A valid, **activated** TRON address. Checksum is verified.                                |
| `amount`      | integer | Between **64,000 and 200,000** inclusive. Must be a whole number — `64000.5` is rejected. |
| `resource`    | string  | `ENERGY`.                                                                                 |
| `durationSec` | integer | One of `60`, `300`, `900`, `3600`. Sent as a number, not a string.                        |

`Idempotency-Key` is **required** on this endpoint. It may be up to 128 characters.

## Batches

`items[]` accepts up to **100** entries in one request, and a batch is **all or nothing**.

```json
{
  "items": [
    { "toAddress": "T…A", "amount": 64000,  "resource": "ENERGY", "durationSec": 3600 },
    { "toAddress": "T…B", "amount": 200000, "resource": "ENERGY", "durationSec": 900 }
  ]
}
```

The total cost of every item is summed and checked against your balance **before** anything is charged. If the total exceeds your balance, no order is created and nothing is debited.

Validation works the same way: the batch is accepted or rejected as a whole. Validate your items before sending, and keep batches to a size you can re-check easily.

## Idempotency

Send the same `Idempotency-Key` twice with the **same body** and you get the original order back with status `200` instead of `201`. Nothing is charged twice. This is what makes a network-timeout retry safe.

```
first  POST  →  201  { "orders": [ { "orderId": "65f1a2b3…" } ] }
retry  POST  →  200  { "orders": [ { "orderId": "65f1a2b3…" } ] }   same order, charged once
```

| Situation                                           | You get                                                                 |
| --------------------------------------------------- | ----------------------------------------------------------------------- |
| Same key, same body, first request already finished | `200` with the original order. Charged once.                            |
| Same key, same body, first request still running    | `409 idempotency.in_progress`, with `Retry-After: 2`. Retry after that. |
| Same key, **different** body                        | `422 idempotency.key_reuse`. Nothing is charged. Use a new key.         |

Rules worth knowing:

* Concurrent requests sharing one key resolve to a single order.
* A **`402` does not consume the key.** Top up and retry with the same key.
* A **`422` receiver rejection does not consume the key either.** Fix the address and retry with the same key.

{% hint style="warning" %}
**Retry within the replay window.** A completed result is replayed for **24 hours**, and a key held by an in-flight request is reserved for **10 minutes**. Past that window the same key is treated as a fresh request, which places — and charges for — a second order. Retry promptly, and generate a new key for anything you decide to send later.
{% endhint %}

## Validation order

Guards run in this order, and the first failure wins:

```
1. field validation          → 400
2. receiver deliverability   → 422    (address must be an activated account)
3. idempotency reservation   → 200 / 409 / 422
4. balance                   → 402
```

Because the receiver check runs before the money, an undeliverable address costs you nothing — and neither the `402` nor the receiver `422` burns your key.

## Responses

| Status | Meaning                                                                               | What to do                                    |
| ------ | ------------------------------------------------------------------------------------- | --------------------------------------------- |
| `201`  | Order created and charged.                                                            | Store `orderId` and `totalCostSun`.           |
| `200`  | Idempotent replay.                                                                    | Same as above; you were charged once.         |
| `400`  | A field is invalid.                                                                   | Fix the request. Do not retry unchanged.      |
| `401`  | Key missing, invalid, or revoked.                                                     | Check the `Authorization` header.             |
| `402`  | Not enough balance. Read `requiredSun`.                                               | Top up, then retry with the same key.         |
| `409`  | The same key is still in flight.                                                      | Retry after `Retry-After` seconds.            |
| `413`  | Body larger than 1 MiB.                                                               | Send fewer items.                             |
| `422`  | The receiver cannot accept a delegation, or the key was reused with a different body. | Fix the address, or use a new key.            |
| `429`  | Rate limited.                                                                         | Back off for `Retry-After` seconds and retry. |
