> ## Documentation Index
> Fetch the complete documentation index at: https://docs.jenzy.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Orders

> Change a stablecoin into a local currency for a bank account, or buy a stablecoin with a bank transfer. Get a quote, then create the order.

An order moves money between a stablecoin and a bank account in one of the
[supported currencies](#supported-currencies). The Jenzy desk fills each order by hand. An order takes hours or
days, not seconds.

There are two types of order. The stablecoin side of the pair sets the type.

* **A to-bank order** changes your USDT or USDC into a local currency. Jenzy
  pays the money to a bank account that you name.
* **A from-bank order** changes a local currency into USDT or USDC. You send a bank
  transfer to Jenzy. Jenzy credits the stablecoin to your balance.

<Note>
  Jenzy operations must enable the desk for your org. Until then, each
  `/v2/orders` request gets `403` with the code `corridor_not_enabled`.
</Note>

## Supported currencies

The desk trades USDT and USDC against these currencies:

| Currency | Code | Country | Decimal places |
| - | - | - | - |
| Angolan kwanza | `AOA` | Angola | 2 |
| Burundian franc | `BIF` | Burundi | 0 |
| Ethiopian birr | `ETB` | Ethiopia | 2 |
| Mozambican metical | `MZN` | Mozambique | 2 |
| Malawian kwacha | `MWK` | Malawi | 2 |

Send and read each amount with the decimal places in the table. A `BIF`
amount has no decimal places. To see the rates and the smallest order for each
currency now, read the corridors.

## Read the corridors

`GET /v2/orders/corridors` lists the currencies of the desk, with the rate in
each direction and the smallest order.

```bash theme={null}
curl https://api.jenzy.com/v2/orders/corridors \
  -H "Authorization: Bearer $JENZY_API_KEY"
```

```json theme={null}
{
  "corridors": [
    { "asset": "BIF", "rate_off_ramp": "2850.5", "rate_on_ramp": "2900", "min": "1000", "open": true },
    { "asset": "AOA", "rate_off_ramp": null, "rate_on_ramp": "915", "min": "500", "open": true }
  ]
}
```

* `rate_off_ramp` is the rate for a to-bank order. `rate_on_ramp` is the rate
  for a from-bank order. Each rate is units of `asset` for one stablecoin.
* A `null` rate means that the desk does not take orders in this direction
  now.
* `open` is `false` when you cannot get a quote in this corridor.
* `min` is the smallest order, on the stablecoin side.
* The rate includes all costs. An order has no `fee` field.

## Get a quote

`POST /v2/orders/quotes` takes `from_asset`, `to_asset`, and one amount. Send
`from_amount` to fix what you pay. Send `to_amount` to fix what you get. Send
one of the two, not both.

```bash theme={null}
curl -X POST https://api.jenzy.com/v2/orders/quotes \
  -H "Authorization: Bearer $JENZY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "from_asset": "USDT", "to_asset": "BIF", "to_amount": "2850500" }'
```

```json theme={null}
{
  "quote_id": "3e7c1b7a-0b1e-4b8f-9d2a-6f1c2e3d4a5b",
  "from_asset": "USDT",
  "to_asset": "BIF",
  "from_amount": "1000",
  "to_amount": "2850500",
  "rate": "2850.5",
  "expires_at": "2026-09-22T10:01:00.000Z"
}
```

* **The two amounts do not change.** Hermes calculates the other amount at
  the rate. Hermes rounds the local currency down, and the stablecoin up.
* **A quote expires after 60 seconds.** Read `expires_at`. Do not use a fixed
  time in your code.
* **A quote is for one order.** Get a new quote for each order.
* **A quote holds no money.** Hermes does not list quotes.

The pair must be one stablecoin and one corridor currency. A different pair
gets `unsupported_pair` (422). An amount below `min` gets
`amount_below_minimum` (422). A closed direction gets `rate_unavailable`
(503). When Jenzy closes the desk, a quote or a create request gets `503`
with `service_maintenance` or `service_incident`. See
[Errors](/v2/errors#order-codes).

## Create the order

`POST /v2/orders` takes `quote_id`, `client_ref`, and, for a to-bank order,
`beneficiary`. The request needs an **`Idempotency-Key`** header.

```bash theme={null}
curl -X POST https://api.jenzy.com/v2/orders \
  -H "Authorization: Bearer $JENZY_API_KEY" \
  -H "Idempotency-Key: 5b2d8c1e-7f3a-4e9b-8c6d-1a2b3c4d5e6f" \
  -H "Content-Type: application/json" \
  -d '{
    "quote_id": "3e7c1b7a-0b1e-4b8f-9d2a-6f1c2e3d4a5b",
    "client_ref": "inv-1042",
    "beneficiary": {
      "name": "Aline Niyonzima",
      "bank_name": "Banque de Crédit de Bujumbura",
      "account_number": "0001234567"
    }
  }'
```

* `client_ref` is your reference. It has a maximum of 64 characters. It must
  be unique across your orders. A used `client_ref` gets `client_ref_used`
  (409).
* `beneficiary` is the bank account that gets the money. Hermes has no list
  of banks for the local currencies. Write the bank name as text.
* `beneficiary` has `name`, `bank_name`, and `account_number`. `branch` is
  optional. Hermes keeps the text as you send it and does not check it.
* A to-bank order with no `beneficiary` gets `beneficiary_required` (422).
* A from-bank order with a `beneficiary` gets `beneficiary_not_allowed`
  (422).

A to-bank order holds `from_amount` from your stablecoin balance at once. If
your `available` is too low, you get `insufficient_funds` (402). A from-bank
order holds no money.

The response is the order. There is no webhook for the create step.

```json theme={null}
{
  "id": "8c1d2e3f-4a5b-4c6d-8e7f-9a0b1c2d3e4f",
  "client_ref": "inv-1042",
  "from_asset": "USDT",
  "from_amount": "1000",
  "to_asset": "BIF",
  "to_amount": "2850500",
  "rate": "2850.5",
  "status": "accepted",
  "failure": null,
  "beneficiary": {
    "name": "Aline Niyonzima",
    "bank_name": "Banque de Crédit de Bujumbura",
    "account_number": "0001234567"
  },
  "proofs": {},
  "created_at": "2026-09-22T10:00:30.000Z",
  "updated_at": "2026-09-22T10:00:30.000Z"
}
```

### Send the request again

* The same `Idempotency-Key` with the same body returns the first response.
  This is the safe way to send a request again after a timeout.
* The same quote with a different key gets `quote_used` (409).
* A quote after its `expires_at` gets `quote_expired` (422). Get a new quote.

## Status

Each order has one `status`. The two types of order use different steps.

### A to-bank order

`accepted` → `processing` → `completed`

| Status | Meaning |
| - | - |
| `accepted` | Hermes holds your stablecoin. The desk has your order. |
| `processing` | The desk pays the beneficiary in the local currency. |
| `completed` | The beneficiary got the money. |
| `failed` | The order did not complete. See `failure`. |
| `cancelled` | Jenzy operations cancelled the order. Hermes released the hold. |

### A from-bank order

`awaiting_instructions` → `awaiting_funds` → `proof_submitted` →
`funds_confirmed` → `completed`

| Status | Meaning |
| - | - |
| `awaiting_instructions` | The desk prepares the bank details for your transfer. |
| `awaiting_funds` | The order has `funding`. Send your bank transfer, then upload a proof. |
| `proof_submitted` | You uploaded a proof. The desk checks it. |
| `funds_confirmed` | The desk found your transfer. The stablecoin comes next. |
| `completed` | Hermes credited `to_amount` to your stablecoin balance. |
| `expired` | The funding deadline passed before you uploaded a proof. |
| `failed` | The order did not complete. See `failure`. |
| `cancelled` | Jenzy operations cancelled the order. |

### There is no cancel endpoint

You cannot cancel an order through the API. To stop an order, contact Jenzy
operations.

## When an order fails

A `failed` order has `failure: { code, message }`. The `message` for each
code does not change.

| Code | Meaning |
| - | - |
| `unable_to_fill` | The desk could not fill the order. Create a new order if you still need it. |
| `beneficiary_rejected` | The bank refused the beneficiary details. Check them and create a new order. |
| `funds_not_received` | Your transfer did not arrive before the funding deadline. |
| `not_delivered` | The stablecoin for this order did not arrive. Jenzy operations will contact you. |
| `other` | The order failed for a different reason. Jenzy operations will contact you. |

### Refund of a to-bank order

A to-bank order can fail after `processing`. Then the order gets a `refund`
object:

* `{ "status": "pending" }` — your stablecoin comes back to you.
* `{ "status": "returned" }` — Hermes credited the stablecoin to your balance
  as a collection.

A to-bank order that fails before `processing` has no `refund`. Hermes released
the hold, and no money left your balance.

## Fund a from-bank order

When the desk prepares the bank details, the order moves to `awaiting_funds`.
Hermes sends `order.awaiting_funds`. The order now has a `funding` block:

```json theme={null}
{
  "funding": {
    "bank_name": "Banco de Fomento Angola",
    "account_name": "Jenzy Desk",
    "account_number": "0040 0000 1234 5678 1019 1",
    "reference": "8c1d2e3f",
    "amount": "915000",
    "asset": "AOA",
    "deadline": "2026-09-23T10:00:30.000Z"
  },
  "expires_at": "2026-09-23T10:00:30.000Z"
}
```

1. Send `funding.amount` in `funding.asset` to the account in `funding`.
2. Write `funding.reference` on the transfer. The desk uses it to find your
   money.
3. Do these steps before `funding.deadline`. `deadline` and `expires_at` are
   the same time.

If the deadline passes before you upload a proof, the order becomes
`expired`.

## Upload a funding proof

After the transfer, upload the proof of the transfer. Send the file as the
request body, with its `Content-Type`.

```bash theme={null}
curl -X PUT https://api.jenzy.com/v2/orders/8c1d2e3f-4a5b-4c6d-8e7f-9a0b1c2d3e4f/proofs/funding \
  -H "Authorization: Bearer $JENZY_API_KEY" \
  -H "Content-Type: application/pdf" \
  --data-binary @transfer.pdf
```

* The file must be a PDF, a JPEG, or a PNG. Hermes reads the bytes of the
  file. A different file type gets `unsupported_media_type` (415).
* The maximum size is 10 MiB. A larger file gets `payload_too_large` (413).
* You can upload only when the order is `awaiting_funds`. At a different
  time you get `proof_not_expected` (409).
* An upload has no `Idempotency-Key`. If you send the upload again after a
  timeout and get `proof_not_expected`, read the order. If the status is
  `proof_submitted`, the order has a funding proof. The portal or a different
  API key can also upload. To see which file the order has,
  [download the funding proof](#download-a-funding-proof).

The response is the order, with the status `proof_submitted` and
`proofs.funding.uploaded_at`. Hermes sends `order.proof_submitted`.

If the desk refuses your proof, the order goes back to `awaiting_funds`.
Hermes sends `order.awaiting_funds` again. `proofs.funding.rejected_reason`
tells you why. Upload a new file. Hermes keeps your earlier files.

## Download a funding proof

`GET /v2/orders/{id}/proofs/funding` returns a link to your newest proof.

```json theme={null}
{ "url": "https://…", "expires_at": "2026-09-22T12:05:00.000Z" }
```

The link stops at `expires_at`, 300 seconds after the request. Send the
request again for a new link. Before you upload a proof, you get `404`.

## Read your orders

* `GET /v2/orders/{id}` returns one order.
* `GET /v2/orders` lists your orders, newest first, with keyset pagination.
  Filter with `status`, or with `asset`. `asset` matches `from_asset` or
  `to_asset`.

## Webhooks

Hermes sends one event for each change of status that you can see. Each
delivery has `api_version: "v2"`. `data` is the order, as
`GET /v2/orders/{id}` shows it. See [Webhooks](/webhooks) for the wrapper
and the signature.

| Event | When |
| - | - |
| `order.processing` | A to-bank order moved to `processing`. |
| `order.awaiting_funds` | A from-bank order has `funding`. Hermes sends it again after the desk refuses a proof. |
| `order.proof_submitted` | You uploaded a funding proof. |
| `order.funds_confirmed` | The desk found your transfer. |
| `order.completed` | The order completed. |
| `order.failed` | The order failed. `failure` tells you why. |
| `order.expired` | The funding deadline passed before a proof arrived. |
| `order.cancelled` | Jenzy operations cancelled the order. |
| `order.refunded` | The stablecoin of a failed to-bank order came back to your balance. |

* There is no event when you create an order. The response to the create
  request is your record.
* `order.refunded` does not change `status`. The status stays `failed`.
  Only `refund.status` changes to `returned`.

## Receipts

The API has no receipt route. The order has all the fields of a receipt. The
Jenzy portal prints a receipt for a `completed` to-bank order.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.