# Deep Dive — Request Validation

For state-changing operations, the SDK validates request bodies against the documented shape **before** signing or sending them. A malformed request fails fast with a typed `ValidationError` and never hits the network.

## Why validate client-side

Authenticated mutations are signed with your nonce and secret. Sending a request the server will reject wastes a nonce and a round trip, and the resulting server error is often less specific than a local check. Validating first means:

- Bad requests fail before authentication — no wasted nonce.
- The error names the exact field and rule that failed.
- You catch mistakes in development, not from a production 400.

## ValidationError

```ts
import { ValidationError } from "gemini-markets/server";

try {
  await client.trading.createNewOrder({
    symbol: "BTCUSD",
    amount: "not-a-number", // invalid decimal
    price: "50000",
    side: "buy",
    type: "exchange limit",
  });
} catch (err) {
  if (err instanceof ValidationError) {
    console.log(err.operation); // "trading.createNewOrder"
    console.log(err.field);     // "amount"
    console.log(err.rule);      // "format"
    console.log(err.message);   // "amount must be a quoted decimal string"
  }
}
```

`ValidationError` extends `SdkError` and carries three fields for programmatic handling:

| Field | Meaning |
| --- | --- |
| `operation` | The operation that failed (e.g. `"trading.createNewOrder"`) |
| `field` | The offending field name |
| `rule` | The rule that failed (`"required"`, `"type"`, etc.) |

## Validated operations

Validation covers state-changing operations across trading, prediction markets, clearing, and account services:

**Trading** — `createNewOrder`, `cancelOrder`, `cancelAllActiveOrders`, `cancelAllSessionOrders`, `getOrderStatus`, `wrapOrder`

**Prediction Markets** — `placeOrder`, `placeOrderBatch`, `cancelOrder`, `cancelOrderBatch`, `createCombo`

**Clearing & Instant** — `createNewClearingOrder`, `createNewBrokerOrder`, `confirmClearingOrder`, `cancelClearingOrder`, `executeInstantOrder`
**Account Services** — `withdrawCryptoFunds`, `transferBetweenAccounts`, `stakeCryptoFunds`, `unstakeCryptoFunds`, `createNewApprovedAddress`, `removeApprovedAddress`, `createNewDepositAddress`, `createNewAccount`, `renameAccount`, `addBank`, `addBankCAD`, `revokeOAuthToken`

Validation is operation-specific. Most read-only operations pass inputs directly to the server, but some (like `trading.getOrderStatus`) validate that required identifiers are present and well-formed before sending.

## What gets checked

Validators enforce the documented shape of each body: required fields are present, and fields have the correct type and format. Common formats:

| Rule | Checks |
| --- | --- |
| Decimal | Numeric string like `"50000.25"` (prices, quantities, amounts) |
| Integer ID | Digit string like `"12345"` |
| UUID | RFC 4122 UUID (`clientTransferId` on transfers and withdrawals) |
| Boolean | Actual `boolean`, not `"true"` |
| Required | Field is present and non-null |

Validation runs on the caller-supplied body before the SDK adds transport fields (`nonce`, `request`) and signs. The check is purely structural — it does not contact the server, so it cannot catch business-rule failures (insufficient funds, unknown symbol); those still surface as [`ApiError`](/tools/typescript-sdk/errors) subclasses from the server.

## Ordering with terms acceptance

For prediction market order placement, validation runs first, then the SDK checks terms acceptance, then it sends. The sequence:

1. `ValidationError` if the body shape is wrong.
2. `AcceptTermsRequired` if terms are not accepted ([see Patterns](/tools/typescript-sdk/patterns#prediction-markets-terms-acceptance)).
3. The signed request is sent.

## What's next

- [Error Handling](/tools/typescript-sdk/errors) — the full error hierarchy
- [REST Reference](/tools/typescript-sdk/reference/overview) — every operation and its access level
