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

# Polymarket Place Bet

Place a bet (order) on Polymarket prediction markets. Supports BUY/SELL orders with GTC, FOK, or FAK order types. Flexible pricing modes: market, limit, or copy from variables. Ideal for: automated trading strategies, event-based betting, portfolio diversification, prediction market arbitrage.

![Polymarket Place Bet logo](https://cdn.b3.fun/b3os-icons/polymarket-icon.png)
Catalog action EVM Onchain wallet send

Place a bet (order) on Polymarket prediction markets. Supports BUY/SELL orders with GTC, FOK, or FAK order types. Flexible pricing modes: market, limit, or copy from variables. Ideal for: automated trading strategies, event-based betting, portfolio diversification, prediction market arbitrage.

**Review wallet and value movement**

This action can require a wallet connector, gas, token movement, or an external side effect. Test with simulation or a controlled amount before using it in a live workflow.

## At a Glance

| Field | Value |
| --- | --- |
| Action ID | `polymarket-place-bet` |
| Category | EVM Onchain |
| Connector | `wallet` |
| Requires gas | No |
| Funds movement | `send` |
| Tags | `polymarket`, `trading`, `defi`, `write` |

## Payload Schema

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `mode` | `string` | No | Mode of operation. 'manual' for selecting a specific market/outcome, 'copy' for copying trades from a trigger with all fields from variables. |
| `marketUrl` | `string` | No | Polymarket event URL \(e.g., https://polymarket.com/event/bitcoin-up-or-down-january-14-2am-et\). When provided, the action will fetch market data and use the specified outcome to determine the token ID. |
| `outcome` | `string` | No | The outcome to bet on \(e.g., "Up", "Down", "Yes", "No"\). Required when using marketUrl. Must match one of the available outcomes in the market. |
| `tokenId` | `string` | No | The CLOB token ID \(numeric string\) representing the specific outcome to bet on. Alternative to marketUrl+outcome — provide either tokenId OR marketUrl+outcome. |
| `groupOutcome` | `string` | No | For multi-market events: the selected sub-market question text. Used during execution to disambiguate between sub-markets when resolving tokenId from marketUrl+outcome \(e.g., grouped binary events where all outcomes are Yes/No\). |
| `tokenIdVariable` | `string` | No | Variable reference for the token ID in copy mode \(e.g., &#123;&#123;root.result.trade.tokenId&#125;&#125;\). The value will be resolved at runtime. |
| `sideVariable` | `string` | No | Variable reference for the side \(BUY/SELL\) in copy mode \(e.g., &#123;&#123;root.result.trade.side&#125;&#125;\). The value will be resolved at runtime. |
| `side` | `string` | No | BUY to bet on an outcome, SELL to bet against or exit a position. |
| `amountMode` | `string` | No | How to determine the bet amount. 'fixed' uses a static value, 'proportional' uses a variable with multiplier. |
| `fixedAmount` | `string` | No | Fixed bet amount in pUSD smallest units \(6 decimals\). e.g. "10000000" = $10. Minimum: $1 for market orders, $5 for limit orders. |
| `dynamicAmount` | `string \| number` | No | Variable reference or resolved value for the amount when amountMode is 'proportional'. |
| `multiplier` | `number` | No | Multiplier applied to dynamicAmount amount \(e.g., 0.5 for half, 2 for double\). |
| `minAmount` | `number` | No | Minimum bet amount when using copy mode. Final amount will be clamped to this floor. |
| `maxAmount` | `number` | No | Maximum bet amount when using copy mode. Final amount will be clamped to this ceiling. |
| `priceMode` | `string` | No | How to determine the price. 'market' uses current market price, 'limit' uses a fixed price, 'copy' uses a variable. |
| `price` | `number` | No | Price per share between 0.01 and 0.99. Maps from limitPrice in limit mode. |
| `limitPrice` | `number` | No | Limit price per share \(used when priceMode is 'limit'\). Represents probability between 0.01 and 0.99. |
| `copyPriceVariable` | `string \| number` | No | Variable reference or resolved value for the price when priceMode is 'copy'. |
| `orderType` | `string` | No | Order type: GTC \(Good Till Cancelled\), GTD \(Good Till Date — requires expiration\), FOK \(Fill Or Kill\), FAK \(Fill And Kill\). Default is FAK for market orders. |
| `expiration` | `string` | No | Unix timestamp for order expiration. Required when orderType is 'GTD'. The order will be automatically cancelled after this time. |
| `postOnly` | `boolean` | No | If true, the limit order will only be placed as a maker order \(sits on the book\). If it would immediately match, the order is rejected instead of filling as a taker. Only valid for GTC/GTD order types. Maker orders have zero fees. |
| `metadata` | `string` | No | Optional bytes32 metadata tag for the order. Can be used for strategy tagging, workflow attribution, or downstream analytics. |
| `deferExec` | `boolean` | No | Defer execution — order is signed and stored but not immediately matched. Useful for atomic multi-leg strategies. |

## Result Schema

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `status` | `string` | Yes | Status of the bet placement operation. 'filled'/'matched' = order matched \(check filledSize/amountSpent for the amount\). 'no_fill' = order accepted but nothing matched \(FAK/FOK killed\) — filledSize and amountSpent are 0. 'pending' = market order accepted but the asynchronous on-chain fill could not be confirmed within the polling window — filledSize/amountSpent are 0 but the order may still settle; reconcile via orderId. 'success' = legacy generic success. |
| `orderId` | `string` | No | The unique identifier for the placed order |
| `tokenId` | `string` | No | The token ID that was bet on |
| `side` | `string` | No | The side of the order |
| `price` | `number` | No | The price per share |
| `size` | `number` | No | The size of the order in shares. Always present — use this instead of order-type-specific fields \(sizeMatched, takingAmount\) in downstream workflow nodes. |
| `filledSize` | `number` | No | Unified field: amount of the order that was filled \(shares\). Always present — works for both market and limit orders. Prefer over sizeMatched/takingAmount. |
| `orderType` | `string` | No | The type of order placed \(GTC, GTD, FAK, FOK\) |
| `createdAt` | `string` | No | Timestamp when the order was created |
| `transactionHash` | `string` | No | On-chain transaction hash for market orders that settled immediately |
| `tradeIds` | `array` | No | Array of trade IDs for matched/filled orders |
| `takingAmount` | `number` | No | Raw API field for market orders ONLY \(FAK/FOK\): number of shares received. NOT present for limit orders — use filledSize instead. |
| `makingAmount` | `number` | No | Raw API field for market orders ONLY \(FAK/FOK\): USDC amount spent. NOT present for limit orders — use size instead. |
| `sizeMatched` | `number` | No | Raw API field for limit orders ONLY \(GTC\): number of shares matched. NOT present for market orders — use filledSize instead. |
| `amountSpent` | `number` | No | Unified field: actual USDC amount spent on this order, EXCLUDING the Polymarket taker fee \(see feeUsd for the fee; total spent = amountSpent + feeUsd\). Always present — works for both market and limit orders. For BUY orders: equals makingAmount \(market\) or filledSize × price \(limit\). For SELL orders: 0 \(sells are exits, not outflow\). Use this for budget tracking instead of the trigger's trade.amount. |
| `question` | `string` | No | The market question \(e.g. 'Will Bitcoin reach $100K?'\). Populated when resolved from marketUrl. |
| `message` | `string` | No | Optional message with additional context about the order result |
| `requestedUsd` | `number` | No | The notional the user requested \(USDC\), before any fee-driven reduction. |
| `notionalUsd` | `number` | No | The notional the order was actually placed at \(USDC\). Equals requestedUsd unless the wallet couldn't cover requestedUsd + Polymarket's taker fee, in which case it was reduced to fit \(see wasReducedForFee\). |
| `wasReducedForFee` | `boolean` | No | True when notionalUsd was reduced below requestedUsd to fit the wallet balance after Polymarket's taker fee. |
| `feeUsd` | `number` | No | Estimated Polymarket taker fee \(USDC\) charged on the FILLED amount, computed at the actual fill price. This is ON TOP of amountSpent — total spent = amountSpent + feeUsd. |

## Examples

**Workflow node**

```json
{
  "type": "polymarket-place-bet",
  "payload": {
    "mode": "manual",
    "marketUrl": "https://example.com/webhook",
    "outcome": "example-outcome",
    "tokenId": "1",
    "groupOutcome": "example-groupOutcome"
  },
  "children": [],
  "connector": {
    "type": "wallet",
    "id": "conn_wallet"
  }
}
```
  **Test with API**

```bash
curl -X POST "https://api.b3os.org/v1/actions/polymarket-place-bet/test" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "inputs": {
    "mode": "manual",
    "marketUrl": "https://example.com/webhook",
    "outcome": "example-outcome",
    "tokenId": "1",
    "groupOutcome": "example-groupOutcome"
  }
}'
```

**Use expressions for dynamic values**

Payload fields can use workflow expressions such as `{{$trigger.body.amount}}`, `{{$nodes.fetch.result.price}}`, and `{{$props.asset}}` when the value should come from a trigger, prior node, or reusable workflow prop.