> For the complete documentation index, see [llms.txt](https://www.aevo.xyz/docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://www.aevo.xyz/docs/api-reference/builder-codes/placing-orders.md).

# Placing orders

To charge a builder fee, add two fields to the order and include them in the order signature.

| Field              | Type                               | Example                      |
| ------------------ | ---------------------------------- | ---------------------------- |
| `builder_id`       | string                             | `"builder_0123456789abcdef"` |
| `builder_fee_rate` | decimal string, at most 6 decimals | `"0.0003"` (3 bps)           |

The same fields work on REST `POST /orders`, `POST /orders/{order_id}` (edit), batch orders, and the websocket `create_order` / `edit_order` operations.

## Signing

Builder orders are signed with the account's **API signing key**, like any other order. The EIP-712 primary type is still `Order`, with two extra fields at the end:

```
Order(address maker,bool isBuy,uint256 limitPrice,uint256 amount,uint256 salt,uint256 instrument,uint256 timestamp,string builderId,uint256 builderFeeRate)
```

* `builderId` is your `builder_id` string.
* `builderFeeRate` is the **raw 6-decimal integer**: `"0.0003"` is signed as `300`.
* The domain is the same as for normal orders.

If `builder_id` is present, the signature must be over this type. A signature over the normal `Order` type is rejected.

## Example (REST)

```json
{
  "maker": "0xBuilderUserAddress",
  "is_buy": true,
  "instrument": 1,
  "limit_price": "2700000000",
  "amount": "1000000",
  "salt": "123456789",
  "timestamp": 1790000000,
  "signature": "0x...",
  "post_only": false,
  "reduce_only": false,
  "builder_id": "builder_0123456789abcdef",
  "builder_fee_rate": "0.0003"
}
```

With the Python SDK:

```python
aevo.rest_create_order(
    instrument_id=1,
    is_buy=True,
    limit_price=2700,
    quantity=1,
    post_only=False,
    builder="builder_0123456789abcdef",
    builder_fee_bps=3,
)
```

## Supported orders

Builder fields are accepted on **signed limit and market orders** for **perpetuals and options**.

Option orders with builder fields are rejected with `BUILDER_NOT_SUPPORTED` while the options builder settings are unset (`max_fee_rate_options` or `option_premium_cap` is `null` in `GET /builder-config`).

## Cancelling and editing

**Cancels** ([`DELETE /orders/{order_id}`](/docs/api-reference/urls/private-api/deleteordersorderid.md), [`DELETE /orders-all`](/docs/api-reference/urls/private-api/deleteordersall.md), [`DELETE /orders`](/docs/api-reference/urls/private-api/deleteorders.md) (up to 10 order IDs), websocket `cancel_order` / `cancel_all_orders`) work the same with or without a builder:

* They take no builder fields and need only the user's API key, no signature.
* They are free. A builder fee is charged only when an order fills; cancelling an unfilled order, or the unfilled rest of a partially filled order, charges nothing.
* A cancel applies to any of the user's orders, not only those your builder placed. `DELETE /orders-all` cancels every order in the chosen scope, including orders the user placed in the Aevo app or through other apps.

**Edits** ([`POST /orders/{order_id}`](/docs/api-reference/urls/private-api/postordersorderid.md), websocket `edit_order`) replace the order with a new signed order. Send `builder_id` and `builder_fee_rate` again on every edit, and include them in the new order's signature. If you leave them out, the edited order has no builder attribution and its fills pay no builder fee.

## Perpetuals vs options

You send the builder fee **the same way** on both: the same two fields, the same decimal format, and the same signed `Order` type. Only the instrument differs. What changes is how Aevo applies the rate when the order fills, and which protocol cap it is checked against.

|                           | Perpetual order                  | Option order                                                                      |
| ------------------------- | -------------------------------- | --------------------------------------------------------------------------------- |
| Fields                    | `builder_id`, `builder_fee_rate` | `builder_id`, `builder_fee_rate` (same)                                           |
| `builder_fee_rate` format | Decimal string, e.g. `"0.0003"`  | Decimal string, e.g. `"0.0003"` (same)                                            |
| Signed as                 | Raw integer, e.g. `300`          | Raw integer, e.g. `300` (same)                                                    |
| Rate is applied to        | Trade price × contracts          | **Index price** × contracts, capped at `option_premium_cap` × premium × contracts |
| Protocol cap checked      | `max_fee_rate_perps`             | `max_fee_rate_options`                                                            |

For an option order:

* **`builder_fee_rate` is a rate on index notional, not on the premium.** `"0.0003"` means 3 bps of `index price × contracts`, not 0.03% of the option price you are quoting in `limit_price`.
* **Don't calculate the premium cap yourself.** Send the rate; Aevo applies the premium cap on each fill and charges the smaller amount.
* **Never send a fee amount.** Only the rate is sent. The amount is worked out per fill.
* **Stay at or below `max_fee_rate_options` (3 bps)**, which is lower than the perpetuals cap (5 bps) and can be lower than the user's approved maximum. Above it, the order is rejected with `BUILDER_FEE_EXCEEDS_AEVO_LIMIT`.

### Sample payloads

Both are `POST /orders` bodies. Only `instrument` and `limit_price` differ; the builder fields are identical. Look up instrument IDs with [`GET /markets`](/docs/api-reference/urls/public-api/getmarkets.md); the IDs below are examples. `limit_price` and `amount` use 6 decimals.

#### Perpetual

Buy 1 ETH-PERP at $2,700 with a 3 bps builder fee:

```json
{
  "maker": "0xBuilderUserAddress",
  "is_buy": true,
  "instrument": 1,
  "limit_price": "2700000000",
  "amount": "1000000",
  "salt": "123456789",
  "timestamp": 1790000000,
  "signature": "0x...",
  "post_only": false,
  "builder_id": "builder_0123456789abcdef",
  "builder_fee_rate": "0.0003"
}
```

Builder fee on a full fill: `0.0003 × 2,700 × 1` = **$0.81**.

#### Option

Buy 1 ETH call at a $20 premium with a 3 bps builder fee (ETH index $2,700, option premium cap 5%):

```json
{
  "maker": "0xBuilderUserAddress",
  "is_buy": true,
  "instrument": 1234,
  "limit_price": "20000000",
  "amount": "1000000",
  "salt": "123456789",
  "timestamp": 1790000000,
  "signature": "0x...",
  "post_only": false,
  "builder_id": "builder_0123456789abcdef",
  "builder_fee_rate": "0.0003"
}
```

Builder fee on a full fill: `min(0.0003 × 2,700 × 1, 0.05 × 20 × 1)` = `min(0.81, 1.00)` = **$0.81**.

At a $5 premium, the same order pays `min(0.81, 0.25)` = **$0.25**: the premium cap applies.

In both cases the signature is over the builder `Order` type with `builderFeeRate` = `300` (see [Signing](#signing)). See [Perpetuals vs Options Fees](/docs/aevo-products/aevo-builder-codes/perps-vs-options-fees.md) for more examples.

## Checks

Checks run when the order is submitted, so an order that breaks a rule is rejected straight away and never rests on the book:

1. The builder exists and is `ACTIVE`.
2. The user has approved the builder.
3. `builder_fee_rate` ≤ the user's approved `max_fee_rate`.
4. `builder_fee_rate` ≤ the protocol cap: `max_fee_rate_perps` (**5 bps**) for perpetuals, `max_fee_rate_options` (**3 bps**) for options.

The same rules are checked again on every fill. If one no longer holds (for example the user revoked), the fill still executes with a builder fee of `0` and keeps your `builder_id`.

## Maker and taker

The builder fee applies whether your order is the maker or the taker. A taker order that fills against several makers is charged on each fill.

## Where the fee appears

Each fill in the user's trade history, trade CSV and the websocket `fills` channels carries `builder_id`, `builder_fee_rate` and `builder_fee` (USDC). The builder fee is separate from `fee`, which is Aevo's trading fee.

## Errors

| Code                             | Meaning                                                                |
| -------------------------------- | ---------------------------------------------------------------------- |
| `BUILDER_NOT_APPROVED`           | The user hasn't approved this builder, or revoked.                     |
| `BUILDER_FEE_EXCEEDS_USER_LIMIT` | `builder_fee_rate` is above the user's approved maximum.               |
| `BUILDER_FEE_EXCEEDS_AEVO_LIMIT` | `builder_fee_rate` is above the protocol cap for this instrument type. |
| `BUILDER_NOT_ACTIVE`             | The builder is suspended or disabled.                                  |
| `BUILDER_NOT_SUPPORTED`          | Builder fields on an unsupported order type or instrument.             |
| `BUILDER_INVALID_FEE_RATE`       | `builder_fee_rate` isn't a decimal with at most 6 decimals.            |
| `BUILDER_INVALID_ID`             | `builder_id` is malformed.                                             |
| `BUILDER_NOT_FOUND`              | Unknown `builder_id`.                                                  |


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://www.aevo.xyz/docs/api-reference/builder-codes/placing-orders.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
