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

# Split and Merge

<div className="venue-tags" aria-label="Supported venues">
  <span className="venue-tag">Polymarket</span>
</div>

Splits pUSD into equal Yes and No outcome shares, or merges equal Yes and No shares back into pUSD.
These are version 2 `userOutcome` actions, signed by the user or an approved API wallet.

## Endpoint

```text theme={null}
POST /exchange
```

Check [Split/Merge Support](/api-reference/info-endpoints/outcome-operation-capabilities)
for the selected operation before submitting. Both actions execute asynchronously.

## Request Body

| Parameter | Type | Description |
| - | - | - |
| `action`\* | object | A `userOutcome` action with exactly one split or merge payload |
| `nonce`\* | number | Nonnegative safe integer replay-protection nonce in Unix milliseconds |
| `signature`\* | object | Notional EIP-712 signature with `r`, `s`, and `v` |

The request, action, payload, market, and signature objects reject extra fields. In particular,
version 2 requests do not accept `expiresAfter`, `amount`, `outcome`, or `amount: null` in place of
the fields below.

### action

`type` must be `"userOutcome"`. Include exactly one of:

* `splitOutcome`: reserve pUSD and receive the same amount of each outcome side on completion.
* `mergeOutcome`: reserve the same amount of each outcome side and receive pUSD on completion.

Both nested payloads have this shape:

| Field | Type | Description |
| - | - | - |
| `schemaVersion`\* | number | Must be `2` |
| `market`\* | object | Exact Polymarket condition and Yes/No asset identities |
| `amountBaseUnits`\* | string | Canonical positive uint256 decimal integer in base units |

One pUSD and one share each use 1,000,000 base units. `"1000000"` therefore splits 1 pUSD into
1 Yes share and 1 No share, or merges 1 share of each side into 1 pUSD. Fractional quantities are
represented as integer base units: `"500000"` means 0.5. Zero, negative values, decimals, exponent
notation, leading zeroes, and `null` are rejected. Specify an exact amount; there is no mutable
“maximum available” request.

### market

| Field | Type | Description |
| - | - | - |
| `adapter`\* | string | Must be `"polymarket"` |
| `conditionId`\* | string | Nonzero lowercase, `0x`-prefixed 32-byte condition ID |
| `yesAssetId`\* | string | Canonical lowercase, `0x`-prefixed `PM_Outcome` AssetId for Yes |
| `noAssetId`\* | string | Canonical lowercase, `0x`-prefixed `PM_Outcome` AssetId for No |
| `negRisk`\* | boolean | Negative-risk classification matching the condition |

The two AssetIds must be distinct and match the condition's actual sides. Version 2 uses
**`0x`-prefixed** AssetIds: `0x1001` followed by the token ID encoded as 64 lowercase hex characters.
See [Products and Asset IDs](/api-reference/products-and-asset-ids) for token-ID encoding.

The examples below illustrate the wire shape with placeholder condition and token IDs. Replace
the complete `market` object with a real matching condition/side pair, then sign the request.

## Examples

<Tabs sync={false}>
  <Tab title="Split">
    ```json theme={null}
    {
      "action": {
        "type": "userOutcome",
        "splitOutcome": {
          "schemaVersion": 2,
          "market": {
            "adapter": "polymarket",
            "conditionId": "0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
            "yesAssetId": "0x10010000000000000000000000000000000000000000000000000000000000000001",
            "noAssetId": "0x10010000000000000000000000000000000000000000000000000000000000000002",
            "negRisk": false
          },
          "amountBaseUnits": "1000000"
        }
      },
      "nonce": 1785254400000,
      "signature": {
        "r": "0x1234...",
        "s": "0x5678...",
        "v": 27
      }
    }
    ```
  </Tab>

  <Tab title="Merge">
    ```json theme={null}
    {
      "action": {
        "type": "userOutcome",
        "mergeOutcome": {
          "schemaVersion": 2,
          "market": {
            "adapter": "polymarket",
            "conditionId": "0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
            "yesAssetId": "0x10010000000000000000000000000000000000000000000000000000000000000001",
            "noAssetId": "0x10010000000000000000000000000000000000000000000000000000000000000002",
            "negRisk": false
          },
          "amountBaseUnits": "1000000"
        }
      },
      "nonce": 1785254400000,
      "signature": {
        "r": "0x1234...",
        "s": "0x5678...",
        "v": 27
      }
    }
    ```
  </Tab>
</Tabs>

## Signing

Sign the complete action and nonce with `signNotionalOrder` from `@notional/common`, using the
`NotionalExchange` domain:

```typescript theme={null}
import { signNotionalOrder } from "@notional/common";

const nonce = Date.now();
const { r, s, v } = await signNotionalOrder(
  apiWalletPrivateKey,
  action,
  nonce,
  undefined,
  true, // false for testnet
);
const request = { action, nonce, signature: { r, s, v } };
```

Send only `r`, `s`, and `v` in the signature object; the helper also returns a serialized
`signature` field that this strict request schema does not accept. Use the API wallet's private key
or the user's signing flow, and keep the action, amount, and market unchanged after signing. See
[Signing, Nonces, and API Wallets](/api-reference/signing-nonces-api-wallets).

## Response

```json theme={null}
{
  "status": "ok",
  "response": {
    "type": "outcomeOperation",
    "data": {
      "actionId": "0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
      "operation": "split",
      "adapter": "polymarket",
      "status": "pending"
    }
  }
}
```

A merge returns the same shape with `operation: "merge"`. Keep `actionId` and poll
[Split/Merge Status](/api-reference/info-endpoints/outcome-operation-status) until it returns
`completed` or `failed`. A request can also return an already-advanced status, particularly on an
exact retry.

## Balance Effects and Retries

An accepted split holds pUSD; an accepted merge holds equal quantities of both outcome sides.
Successful completion consumes those holds and credits the resulting shares or pUSD. A terminal
failure releases the holds. A nonterminal or uncertain operation can retain its reservation.

After completion or failure, refresh [`assets`](/api-reference/info-endpoints/assets) and
[`polymarketPositions`](/api-reference/info-endpoints/polymarket-positions). Do not treat an accepted
request as completed execution.

For an uncertain HTTP response, preserve and retry the identical signed body and nonce. A recorded
operation returns its current status without creating another operation. A previously rejected
request can return `{ "status": "error", "error": "..." }` on an exact retry; inspect the body
as well as the HTTP status. A new nonce creates a different intent.

## Admission and Errors

* The account must have protocol access and enough unheld pUSD or outcome shares. Splits also
  check account margin after reserving the source pUSD.
* The condition must be supported, open, and match the signed side identities and `negRisk` value.
* Deployment policy and runtime readiness can disable admission or execution. Check capabilities
  again if an operation becomes unavailable.
* Malformed or ineligible requests return `400`; invalid signatures return `401`; unavailable
  policy, market binding, or split readiness can return `503`.

The [legacy Hyperliquid merge](/api-reference/exchange-endpoints/merge-outcome) uses a different
payload and response. Version 2 Hyperliquid split and merge are currently disabled.


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