> ## 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.

# Place combo

> Place a combo from a quote

Place a combo you priced with [Get combo quote](https://docs.bayse.markets/api-reference/pm/get-combo-quote.md). The stake is debited from your wallet when the combo is placed. See [Combos](https://docs.bayse.markets/concepts/combos.md) for settlement rules.

## Authentication

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

## Request body

**quoteId** `string` *required*

The `quoteId` returned by [Get combo quote](https://docs.bayse.markets/api-reference/pm/get-combo-quote.md). It is the idempotency key: a retry with the same `quoteId` cannot place a second combo.

**selections** `array` *required*

The same 2 to 10 selections you quoted.

**selection fields**

**marketId** `string` *required*

UUID of the market.

**outcomeId** `string` *required*

UUID of the outcome on that market.

**amount** `number` *required*

Stake, in the specified currency. Must be greater than 0 and at least the minimum order amount (\$1.00 USD / ₦100.00 NGN). Cannot exceed the quote's `maxStake`.

**currency** `string`

`USD` (default) or `NGN`.

**maxPrice** `number`

Highest combo `price` you accept, greater than 0 and up to 1. Placement re-prices the combo. If the new price is above `maxPrice`, the placement is refused with `409` and nothing is debited. Set it to the quoted `price` to refuse any upward move.

## Example request

```bash cURL theme={null}
PUBLIC_KEY="pk_live_abcdef123456"
SECRET_KEY="sk_live_secret789xyz"
TIMESTAMP=$(date +%s)
METHOD="POST"
URL_PATH="/v1/pm/combos"
BODY='{"quoteId":"7c1e9a52-4b3d-4f8e-9a61-2d5b8c0e3f47","selections":[{"marketId":"f6a7b8c9-d0e1-2345-fabc-678901234567","outcomeId":"01234567-89ab-cdef-0123-456789abcdef"},{"marketId":"c9d0e1f2-a3b4-5678-cdef-901234567890","outcomeId":"34567890-bcde-f012-3456-789abcdef012"},{"marketId":"d0e1f2a3-b4c5-6789-defa-012345678901","outcomeId":"45678901-cdef-0123-4567-89abcdef0123"}],"amount":10,"currency":"USD","maxPrice":0.18}'

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 "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/combos';
const body = JSON.stringify({
  quoteId: '7c1e9a52-4b3d-4f8e-9a61-2d5b8c0e3f47',
  selections: [
    { marketId: 'f6a7b8c9-d0e1-2345-fabc-678901234567', outcomeId: '01234567-89ab-cdef-0123-456789abcdef' },
    { marketId: 'c9d0e1f2-a3b4-5678-cdef-901234567890', outcomeId: '34567890-bcde-f012-3456-789abcdef012' },
    { marketId: 'd0e1f2a3-b4c5-6789-defa-012345678901', outcomeId: '45678901-cdef-0123-4567-89abcdef0123' },
  ],
  amount: 10,
  currency: 'USD',
  maxPrice: 0.18,
});

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,
    'Content-Type': 'application/json',
  },
  body,
});
if (!response.ok) {
  const { message = '' } = await response.json().catch(() => ({}));
  // 409 "already been placed": an earlier request with this quoteId went
  // through. Find that combo with List combos instead of placing another.
  // Any other 409: the price moved past maxPrice and nothing was placed.
  throw new Error(`Place combo failed: ${response.status} ${message}`);
}
const combo = await response.json();
```

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

public_key = 'pk_live_abcdef123456'
secret_key = 'sk_live_secret789xyz'
timestamp = int(time.time())
method = 'POST'
path = '/v1/pm/combos'
body = json.dumps({
    'quoteId': '7c1e9a52-4b3d-4f8e-9a61-2d5b8c0e3f47',
    'selections': [
        {'marketId': 'f6a7b8c9-d0e1-2345-fabc-678901234567', 'outcomeId': '01234567-89ab-cdef-0123-456789abcdef'},
        {'marketId': 'c9d0e1f2-a3b4-5678-cdef-901234567890', 'outcomeId': '34567890-bcde-f012-3456-789abcdef012'},
        {'marketId': 'd0e1f2a3-b4c5-6789-defa-012345678901', 'outcomeId': '45678901-cdef-0123-4567-89abcdef0123'},
    ],
    'amount': 10,
    'currency': 'USD',
    'maxPrice': 0.18,
})

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,
        'Content-Type': 'application/json',
    },
    data=body,
)
if not resp.ok:
    message = resp.json().get('message', '') if resp.content else ''
    # 409 "already been placed": an earlier request with this quoteId went
    # through. Find that combo with List combos instead of placing another.
    # Any other 409: the price moved past maxPrice and nothing was placed.
    raise RuntimeError(f'Place combo failed: {resp.status_code} {message}')
combo = 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/combos"
body := []byte(`{"quoteId":"7c1e9a52-4b3d-4f8e-9a61-2d5b8c0e3f47","selections":[{"marketId":"f6a7b8c9-d0e1-2345-fabc-678901234567","outcomeId":"01234567-89ab-cdef-0123-456789abcdef"},{"marketId":"c9d0e1f2-a3b4-5678-cdef-901234567890","outcomeId":"34567890-bcde-f012-3456-789abcdef012"},{"marketId":"d0e1f2a3-b4c5-6789-defa-012345678901","outcomeId":"45678901-cdef-0123-4567-89abcdef0123"}],"amount":10,"currency":"USD","maxPrice":0.18}`)

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("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
```

## Response

Returns the placed combo. [List combos](https://docs.bayse.markets/api-reference/pm/list-combos.md), [Get combo](https://docs.bayse.markets/api-reference/pm/get-combo.md), and [Cash out combo](https://docs.bayse.markets/api-reference/pm/cashout-combo.md) return the same shape.

**id** `string`

Combo UUID.

**code** `string`

8-character share code. Anyone can open the combo by this code with [Get combo](https://docs.bayse.markets/api-reference/pm/get-combo.md).

**status** `string`

`PENDING`, `WON`, `LOST`, `VOIDED`, or `CASHED_OUT`.

**uiStatus** `string`

`PENDING` (no leg's game has started), `ACTIVE` (at least one leg's game has started), or `COMPLETED` (settled or cashed out).

**amount** `number`

Stake, in `currency`.

**currency** `string`

`USD` or `NGN`.

**price** `number`

Combo price per share (0.00–1.00) at placement.

**multiplier** `number`

Payout per unit staked. Recomputed when legs are voided.

**potentialPayout** `number`

What you receive if every remaining leg wins. Falls when legs are voided.

**shares** `number`

Combo shares held. In NGN a share costs `price × 100` and settles at ₦100.00, so `shares` and `potentialPayout` differ by a factor of 100.

**amountPaidOut** `number`

Amount credited to your wallet. Present once the payout, refund, or cashout has been paid.

**cashoutPrice** `number`

Price per share the combo was cashed out at. Present only when `status` is `CASHED_OUT`.

**cashoutAmount** `number`

Amount the cashout returned, in `currency`. Present only when `status` is `CASHED_OUT`.

**cashoutMultiplier** `number`

`cashoutAmount` per unit staked. Present only when `status` is `CASHED_OUT`.

**cashedOutAt** `string`

ISO 8601 timestamp of the cashout. Present only when `status` is `CASHED_OUT`.

**isOwner** `boolean`

`true` when you placed the combo. When `false`, every money field is zero.

**legCount** `integer`

Number of legs.

**cashoutAvailable** `boolean`

Whether cashout is currently offered. Confirm with [Get combo cashout quote](https://docs.bayse.markets/api-reference/pm/get-combo-cashout-quote.md).

**paidOut** `boolean`

Whether the settlement money has landed in your wallet. Settlement changes `status` first; the wallet credit follows shortly after.

**createdAt** `string`

ISO 8601 timestamp.

**selections** `array`

The combo legs, in `position` order.

**selection fields**

**id** `string`

Selection UUID.

**eventId** `string`

UUID of the leg's event.

**marketId** `string`

UUID of the leg's market.

**outcomeId** `string`

UUID of the selected outcome.

**eventTitle** `string`

Title of the event.

**marketTitle** `string`

Title of the market.

**outcomeLabel** `string`

Label of the selected outcome.

**outcomeIndex** `integer`

`1` or `2`.

**imageUrl** `string`

Event image URL. Omitted when the event has no image.

**quotedProbability** `number`

The leg's probability at placement (0.00–1.00). Surviving legs settle at these probabilities when another leg is voided.

**position** `integer`

Order of the leg in the combo.

**status** `string`

`PENDING`, `WON`, `LOST`, or `VOIDED`.

**displayStatus** `string`

`NOT_STARTED`, `IN_PLAY`, `WON`, `LOST`, or `VOIDED`.

**gameStartDate** `string`

ISO 8601 start time of the leg's game. Present on sports legs.

```json 200 OK theme={null}
{
  "id": "3f8a2c61-9d4e-4b7a-8c15-6e2f0a9b4d73",
  "code": "K7Q2M9XA",
  "status": "PENDING",
  "uiStatus": "PENDING",
  "amount": 10,
  "currency": "USD",
  "price": 0.18,
  "multiplier": 5.56,
  "potentialPayout": 55.56,
  "shares": 55.56,
  "isOwner": true,
  "legCount": 3,
  "cashoutAvailable": true,
  "paidOut": false,
  "createdAt": "2026-10-27T10:15:00Z",
  "selections": [
    {
      "id": "a1c2e3f4-5b6d-4e7f-8a9b-0c1d2e3f4a5b",
      "eventId": "e5f6a7b8-c9d0-1234-efab-cd567890abcd",
      "marketId": "f6a7b8c9-d0e1-2345-fabc-678901234567",
      "outcomeId": "01234567-89ab-cdef-0123-456789abcdef",
      "eventTitle": "Manchester City vs Aston Villa",
      "marketTitle": "Manchester City to Win",
      "outcomeLabel": "YES",
      "outcomeIndex": 1,
      "imageUrl": "https://cdn.bayse.markets/events/mci-avl.jpg",
      "quotedProbability": 0.62,
      "position": 1,
      "status": "PENDING",
      "displayStatus": "NOT_STARTED",
      "gameStartDate": "2026-10-31T15:00:00Z"
    },
    {
      "id": "b2d3f4a5-6c7e-4f8a-9b0c-1d2e3f4a5b6c",
      "eventId": "b9c0d1e2-f3a4-5678-9abc-def012345678",
      "marketId": "c9d0e1f2-a3b4-5678-cdef-901234567890",
      "outcomeId": "34567890-bcde-f012-3456-789abcdef012",
      "eventTitle": "Arsenal vs Chelsea",
      "marketTitle": "Over 2.5 total goals",
      "outcomeLabel": "YES",
      "outcomeIndex": 1,
      "imageUrl": "https://cdn.bayse.markets/events/ars-che.jpg",
      "quotedProbability": 0.55,
      "position": 2,
      "status": "PENDING",
      "displayStatus": "NOT_STARTED",
      "gameStartDate": "2026-10-31T17:30:00Z"
    },
    {
      "id": "c3e4a5b6-7d8f-4a9b-0c1d-2e3f4a5b6c7d",
      "eventId": "c0d1e2f3-a4b5-6789-abcd-ef0123456789",
      "marketId": "d0e1f2a3-b4c5-6789-defa-012345678901",
      "outcomeId": "45678901-cdef-0123-4567-89abcdef0123",
      "eventTitle": "Liverpool vs Tottenham",
      "marketTitle": "Liverpool to Win",
      "outcomeLabel": "YES",
      "outcomeIndex": 1,
      "imageUrl": "https://cdn.bayse.markets/events/liv-tot.jpg",
      "quotedProbability": 0.48,
      "position": 3,
      "status": "PENDING",
      "displayStatus": "NOT_STARTED",
      "gameStartDate": "2026-11-01T16:30:00Z"
    }
  ]
}
```

```json 409 Price moved theme={null}
{
  "error": "Conflict",
  "message": "The price moved while you were placing this combo. Review the new odds and try again.",
  "statusCode": 409
}
```

```json 409 Already placed theme={null}
{
  "error": "Conflict",
  "message": "This combo has already been placed. Request a new quote to place another.",
  "statusCode": 409
}
```

```json 400 Below minimum theme={null}
{
  "error": "Bad Request",
  "message": "Minimum combo amount is 1.00",
  "statusCode": 400
}
```

## Errors

| Status | When |
| - | - |
| `400` | `amount` is below the minimum stake. |
| `400` | The stake is above `maxStake` or the payout would exceed the cap. Trade a lower amount. |
| `400` | Trading is disabled for your account. |
| `400` | You have an open position or combo in the other currency. You trade in one currency at a time. |
| `400` | A leg's market is no longer open, or any other leg rule from [Get combo quote](https://docs.bayse.markets/api-reference/pm/get-combo-quote.md) fails. |
| `401` | Missing or invalid HMAC signature. |
| `403` | Combos are currently unavailable. |
| `409` | The re-priced combo is above `maxPrice`. Nothing was placed. Request a new quote. |
| `409` | This `quoteId` has already been placed. An earlier request went through: find it with [List combos](https://docs.bayse.markets/api-reference/pm/list-combos.md) rather than placing again. |
| `424` | Your wallet could not be debited — for example, insufficient balance. |


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