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

# Batch amend orders

> Modify the price and/or size of up to 20 open CLOB orders in a single round-trip

Modify up to **20 CLOB orders** in a single request. Each item names an existing `orderId` you own and supplies the new `price`, the new total `size`, or both. Orders may belong to different markets and events. CLOB-only: any AMM order is rejected per-item with `UNSUPPORTED_ENGINE`.

Amend is the natural complement to place/cancel for market makers running cancel-and-replace ladders. It mutates an order in place — preserving time priority when possible — instead of cancelling and re-placing.

See the [Batch orders](/concepts/batch-orders) concept page for limits, semantics, and rate-limit behavior.

## Authentication

Write authentication required — `X-Public-Key`, `X-Timestamp`, and `X-Signature` headers. See the [Authentication guide](/authentication).

## Headers

<ParamField header="Idempotency-Key" type="string">
  Optional. 1–255 characters of `[A-Za-z0-9_-]`. Retries within 24 hours that share the same key, body, and route replay the original response with `Idempotent-Replayed: true`. A retry with the same key but a different body is rejected with `422`. A concurrent retry (sent while the first is still in flight) is rejected with `409` — back off briefly and retry once the first call has finished. Transient responses (`5xx`, `429`, `408`) are not cached, so you can recover by retrying.
</ParamField>

## Request body

<ParamField body="items" type="array" required>
  1–20 amend items. Each item is processed independently — one bad item does not abort the others.

  <Expandable title="Amend item fields">
    <ParamField body="orderId" type="string" required>
      UUID of the order to amend. Must be owned by the caller. Status must be `open` or `partial_filled`; terminal orders return `NOT_FOUND`.
    </ParamField>

    <ParamField body="newPrice" type="number">
      New limit price per share (0.01–0.99). Absolute, not a delta. Optional — omit to keep the order's current price. **At least one of `newPrice` or `newSize` must be supplied per item**; items with neither are rejected with `BAD_REQUEST`.
    </ParamField>

    <ParamField body="newSize" type="number">
      New TOTAL size of the order in the order's original currency. Must be greater than the order's `filledSize`, and the resulting remaining (`newSize − filledSize`) must be at least the minimum order size. Optional — omit to keep the order's current size.
    </ParamField>
  </Expandable>
</ParamField>

## Self-trade prevention

Self-trade prevention on amend is a fixed server policy: **always `CANCEL_OLDEST`**. If the amend would put the order in a position that crosses a same-user resting order, the resting crosser is cancelled and the amend proceeds.

* The order's resting `stpMode` (set at placement) is **not** consulted for amend — it governs matching-time self-cross behavior on incoming orders, which is a different event from the amend itself.
* Orders being amended in the same batch are automatically excluded from the cancel set, so simultaneous amends that transiently cross don't kill each other.
* If you want an amend to fail rather than cancel a crosser, cancel + re-place instead of amending.

## Example request

<CodeGroup>
  ```bash cURL theme={null}
  PUBLIC_KEY="pk_live_abcdef123456"
  SECRET_KEY="sk_live_secret789xyz"
  TIMESTAMP=$(date +%s)
  METHOD="POST"
  URL_PATH="/v1/pm/orders/batch/amend"
  BODY='{"items":[{"orderId":"f6a7b8c9-d0e1-2345-fabc-678901234567","newPrice":0.50,"newSize":15},{"orderId":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","newPrice":0.40,"newSize":8}]}'

  BODY_HASH=$(printf '%s' "$BODY" | openssl dgst -sha256 -hex 2>/dev/null | sed 's/.*= //')
  PAYLOAD="${TIMESTAMP}.${METHOD}.${URL_PATH}.${BODY_HASH}"
  SIGNATURE=$(printf '%s' "$PAYLOAD" | openssl dgst -sha256 -hmac "$SECRET_KEY" -binary | base64)

  curl -X POST "https://relay.bayse.markets${URL_PATH}" \
    -H "X-Public-Key: ${PUBLIC_KEY}" \
    -H "X-Timestamp: ${TIMESTAMP}" \
    -H "X-Signature: ${SIGNATURE}" \
    -H "Idempotency-Key: 9d3f2c0e-7b1a-4e5d-9f80-3a8b1c2d4e5f" \
    -H "Content-Type: application/json" \
    -d "$BODY"
  ```

  ```javascript Node.js theme={null}
  import crypto from 'crypto';

  const publicKey = 'pk_live_abcdef123456';
  const secretKey = 'sk_live_secret789xyz';
  const timestamp = Math.floor(Date.now() / 1000);
  const method = 'POST';
  const path = '/v1/pm/orders/batch/amend';
  const body = JSON.stringify({
    items: [
      {
        orderId: 'f6a7b8c9-d0e1-2345-fabc-678901234567',
        newPrice: 0.50,
        newSize: 15,
      },
      {
        orderId: 'a1b2c3d4-e5f6-7890-abcd-ef1234567890',
        newPrice: 0.40,
        newSize: 8,
      },
    ],
  });

  const bodyHash = crypto.createHash('sha256').update(body).digest('hex');
  const payload = `${timestamp}.${method}.${path}.${bodyHash}`;
  const signature = crypto
    .createHmac('sha256', secretKey)
    .update(payload)
    .digest('base64');

  const response = await fetch(`https://relay.bayse.markets${path}`, {
    method,
    headers: {
      'X-Public-Key': publicKey,
      'X-Timestamp': timestamp.toString(),
      'X-Signature': signature,
      'Idempotency-Key': crypto.randomUUID(),
      'Content-Type': 'application/json',
    },
    body,
  });
  const result = await response.json();
  ```

  ```python Python theme={null}
  import hmac, hashlib, base64, json, time, uuid, requests

  public_key = 'pk_live_abcdef123456'
  secret_key = 'sk_live_secret789xyz'
  timestamp = int(time.time())
  method = 'POST'
  path = '/v1/pm/orders/batch/amend'
  body = json.dumps({
      'items': [
          {
              'orderId': 'f6a7b8c9-d0e1-2345-fabc-678901234567',
              'newPrice': 0.50,
              'newSize': 15,
          },
          {
              'orderId': 'a1b2c3d4-e5f6-7890-abcd-ef1234567890',
              'newPrice': 0.40,
              'newSize': 8,
          },
      ],
  })

  body_hash = hashlib.sha256(body.encode()).hexdigest()
  payload = f'{timestamp}.{method}.{path}.{body_hash}'
  signature = base64.b64encode(
      hmac.new(secret_key.encode(), payload.encode(), hashlib.sha256).digest()
  ).decode()

  resp = requests.post(
      f'https://relay.bayse.markets{path}',
      headers={
          'X-Public-Key': public_key,
          'X-Timestamp': str(timestamp),
          'X-Signature': signature,
          'Idempotency-Key': str(uuid.uuid4()),
          'Content-Type': 'application/json',
      },
      data=body,
  )
  result = resp.json()
  ```

  ```go Go theme={null}
  import (
      "crypto/hmac"
      "crypto/sha256"
      "encoding/base64"
      "encoding/hex"
      "fmt"
      "net/http"
      "strconv"
      "strings"
      "time"
  )

  timestamp := time.Now().Unix()
  method := "POST"
  urlPath := "/v1/pm/orders/batch/amend"
  body := []byte(`{"items":[{"orderId":"f6a7b8c9-d0e1-2345-fabc-678901234567","newPrice":0.50,"newSize":15},{"orderId":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","newPrice":0.40,"newSize":8}]}`)

  bodySum := sha256.Sum256(body)
  bodyHash := hex.EncodeToString(bodySum[:])
  payload := fmt.Sprintf("%d.%s.%s.%s", timestamp, method, urlPath, bodyHash)
  mac := hmac.New(sha256.New, []byte("sk_live_secret789xyz"))
  mac.Write([]byte(payload))
  signature := base64.StdEncoding.EncodeToString(mac.Sum(nil))

  req, _ := http.NewRequest("POST", "https://relay.bayse.markets"+urlPath, strings.NewReader(string(body)))
  req.Header.Set("X-Public-Key", "pk_live_abcdef123456")
  req.Header.Set("X-Timestamp", strconv.FormatInt(timestamp, 10))
  req.Header.Set("X-Signature", signature)
  req.Header.Set("Idempotency-Key", "9d3f2c0e-7b1a-4e5d-9f80-3a8b1c2d4e5f")
  req.Header.Set("Content-Type", "application/json")
  resp, _ := http.DefaultClient.Do(req)
  ```
</CodeGroup>

## Response

<ResponseField name="engine" type="string">
  Always `CLOB` for batch endpoints today.
</ResponseField>

<ResponseField name="results" type="array">
  Per-item outcomes, in the same order as the request.

  <Expandable title="Result fields">
    <ResponseField name="index" type="integer">
      Position of this item in the request `items` array (zero-based).
    </ResponseField>

    <ResponseField name="orderId" type="string">
      The order UUID submitted in the request.
    </ResponseField>

    <ResponseField name="success" type="boolean">
      `true` if the amend transitioned the order to the new `(price, size)`, `false` if it failed.
    </ResponseField>

    <ResponseField name="order" type="object">
      The amended CLOB order. Present when `success` is `true`. Includes the new `price`, `size`, `remainingSize`, `amount`, and updated timestamps. See the CLOB order fields on [Place order](/api-reference/pm/place-order) for the full schema.
    </ResponseField>

    <ResponseField name="error" type="object">
      Present when `success` is `false`.

      <Expandable title="Error fields">
        <ResponseField name="code" type="string">
          Machine-readable code (e.g. `INSUFFICIENT_BALANCE`, `INSUFFICIENT_SHARES`, `NOT_FOUND`, `MARKET_CLOSED`, `UNSUPPORTED_ENGINE`).
        </ResponseField>

        <ResponseField name="message" type="string">
          Human-readable description.
        </ResponseField>
      </Expandable>
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="summary" type="object">
  <Expandable title="Summary fields">
    <ResponseField name="total" type="integer">Total items submitted.</ResponseField>
    <ResponseField name="succeeded" type="integer">Items that transitioned to the new `(price, size)`.</ResponseField>
    <ResponseField name="failed" type="integer">Items that failed; see each result's `error`.</ResponseField>
  </Expandable>
</ResponseField>

<ResponseExample>
  ```json 200 OK theme={null}
  {
    "engine": "CLOB",
    "results": [
      {
        "index": 0,
        "orderId": "f6a7b8c9-d0e1-2345-fabc-678901234567",
        "success": true,
        "order": {
          "id": "f6a7b8c9-d0e1-2345-fabc-678901234567",
          "marketId": "b2c3d4e5-f6a7-8901-bcde-f12345678901",
          "userId": "9a8b7c6d-5e4f-3210-abcd-ef1234567890",
          "outcome": "YES",
          "side": "BUY",
          "orderType": "LIMIT",
          "type": "BUY",
          "status": "open",
          "amount": 7.50,
          "price": 0.50,
          "size": 15,
          "filledSize": 0,
          "remainingSize": 15,
          "avgFillPrice": 0,
          "fee": 0,
          "postOnly": false,
          "stpMode": "SKIP",
          "quantity": 0,
          "createdAt": "2026-05-12T17:33:21Z",
          "updatedAt": "2026-05-12T17:38:52Z"
        }
      },
      {
        "index": 1,
        "orderId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
        "success": false,
        "error": {
          "code": "INSUFFICIENT_BALANCE",
          "message": "Insufficient balance"
        }
      }
    ],
    "summary": { "total": 2, "succeeded": 1, "failed": 1 }
  }
  ```

  ```json 400 Bad Request — body shape theme={null}
  {
    "error": "bad_request",
    "message": "invalid request body: items[] required (1..20 entries with orderId and at least one of newPrice / newSize)",
    "statusCode": 400
  }
  ```

  ```json 200 OK — per-item bad request (neither newPrice nor newSize) theme={null}
  {
    "engine": "CLOB",
    "results": [
      {
        "index": 0,
        "orderId": "f6a7b8c9-d0e1-2345-fabc-678901234567",
        "success": false,
        "error": {
          "code": "BAD_REQUEST",
          "message": "at least one of newPrice or newSize must be specified"
        }
      }
    ],
    "summary": { "total": 1, "succeeded": 0, "failed": 1 }
  }
  ```

  ```json 409 Conflict theme={null}
  {
    "error": "conflict",
    "message": "A request with this Idempotency-Key is already in flight; retry shortly.",
    "statusCode": 409
  }
  ```

  ```json 422 Unprocessable Entity theme={null}
  {
    "error": "unprocessable_entity",
    "message": "Idempotency-Key reused with a different request body",
    "statusCode": 422
  }
  ```

  ```json 429 Too Many Requests theme={null}
  {
    "message": "Rate limit exceeded for batch payload size. Please reduce the batch or try again later.",
    "retryAfter": 2
  }
  ```
</ResponseExample>

## Per-item error codes

| Code                   | Meaning                                                                                              | Caller action                                                                                    |
| ---------------------- | ---------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------ |
| `INSUFFICIENT_BALANCE` | Wallet balance is too low for the BID amend's additional USD/NGN lock                                | Reduce `newSize` or `newPrice`, or top up the wallet, or fire a cancel batch first to free funds |
| `INSUFFICIENT_SHARES`  | Free share balance is too low for the ASK amend's additional shares lock                             | Reduce `newSize`, or cancel another ASK first to free shares                                     |
| `NOT_FOUND`            | Order not owned by the caller, or already terminal (`filled` / `cancelled` / `expired` / `rejected`) | Check the order's current status; amend works only while `open` or `partial_filled`              |
| `MARKET_CLOSED`        | Market is not `OPEN` (paused, closed, or resolved)                                                   | Wait for the market to reopen, or cancel the order instead                                       |
| `UNSUPPORTED_ENGINE`   | Order belongs to an LMSR / AMM market                                                                | Cancel and re-place to change price/size on AMM markets                                          |
| `DUPLICATE_ORDER_ID`   | The same `orderId` appears more than once in `items`                                                 | Deduplicate the request before retrying                                                          |
| `INTERNAL`             | Unexpected upstream error                                                                            | Retry; if persistent, contact support                                                            |

## Order ordering convention

A typical cancel-and-replace cycle uses three sibling calls in this order:

1. `DELETE /v1/pm/orders/batch` — cancel stale orders (frees locked capital and shares).
2. `POST /v1/pm/orders/batch/amend` — modify in-place orders (uses the freshly freed capacity).
3. `POST /v1/pm/orders/batch` — place new orders (uses what remains).

Funding rejections are evaluated per-item against the wallet's current state at the time the amend reaches the matching engine. By cancelling first you give your amend batch the best chance of clearing for size-up / price-up changes. The amend itself does not aggregate releases ahead of debits within the batch; you'll get an `INSUFFICIENT_BALANCE` per item that can't fit even though the batch's net delta might.

<Note>
  Batch amend charges **one rate-limit token per item** against your write rate-limit bucket — a 20-item amend costs 20 tokens. Over-budget batches are rejected with `429` before any amends reach the matching engine. See [Rate limits](/rate-limits).
</Note>

<Note>
  Amend preserves time priority when the new `(price, size)` is unchanged or shrunk at the same price level. Price changes (up or down) move the order to the new tail of the new level, same as a cancel-and-replace.
</Note>
