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

# Copy PnL Batch

> Calculate copying-slippage cash flow for up to 100 wallets in one request.

Uses the same [Copy PnL calculation, coverage, and response fields](/data/wallets/copy-pnl) for each wallet. This replaces the deprecated [V2 on-demand batch](/api-reference/backtesting/batch).

## Request

```bash theme={null}
curl -X POST "https://api.polynode.dev/v3/copy-pnl/batch" \
  -H "x-api-key: pn_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  --data '{"wallets":["0xab03f377164c3726d498e56f7a9398cd8eb74494","0x3708cef9f92678df15a0473e36c45d68a16cdaf9"],"max_trades":50000}'
```

| Body field   | Required | Description                                                                                                            |
| ------------ | -------- | ---------------------------------------------------------------------------------------------------------------------- |
| `wallets`    | Yes      | Array of 1–100 wallet addresses.                                                                                       |
| `max_trades` | No       | Integer from 1 to 50,000, applied **per wallet**. Default 50,000. Recent/fallback cap; initial scan size in full mode. |
| `history`    | No       | `recent` (default), `auto`, or `full`, applied independently to each wallet.                                           |
| `period`     | No       | `7d`, `14d`, `30d`, `60d`, `90d`, or `180d`. No default date window.                                                   |
| `from`, `to` | No       | Inclusive start and exclusive end. Unix seconds or UTC `YYYY-MM-DD` dates. `from` overrides `period`.                  |

Send parameters in a JSON object, with a body no larger than 16 KiB. Unknown fields, invalid options, and invalid batch sizes return `400`. An invalid wallet within an otherwise valid batch produces an error for that row.

Results preserve input order and duplicate entries. Duplicate normalized wallets with the same options share calculation work. Wallets use different snapshots; relative periods are anchored to each calculation, so use explicit `from` and `to` to fix the same dates across the batch. The whole HTTP batch counts as one API request under normal V3 account limits; the old V2 five-second throttle does not apply.

Every successful row includes separately scoped lifetime `realized_pnl_context`. Date filters apply to the copying simulation, not to that stored lifetime context. In `auto`, some wallets may return full history and others the completed recent-window fallback. Inspect `data.coverage.served_history`, `history_truncated`, and `fallback_reason` for every row. In `full`, incomplete histories become individual errors. See [history modes and work limits](/data/wallets/copy-pnl#history-modes).

## Response and partial failures

The envelope contains `results`, `requested`, `succeeded`, `failed`, `max_trades`, and `elapsed_ms`.

| Result field  | Successful row             | Failed row                                                               |
| ------------- | -------------------------- | ------------------------------------------------------------------------ |
| `wallet`      | Normalized wallet address  | Original input                                                           |
| `status`      | `ok`                       | `error`                                                                  |
| `data`        | Full single-wallet summary | Absent                                                                   |
| `cache`       | `status` and `age_ms`      | Absent                                                                   |
| `error`       | Absent                     | Object with `code` and `message`                                         |
| `status_code` | Absent                     | Per-wallet HTTP-equivalent status, such as `400`, `422`, `503`, or `504` |

A valid batch returns HTTP `200` even if some or all wallets fail. Always inspect `status` on every result. For example, an invalid wallet row is:

```json theme={null}
{
  "wallet": "invalid-address",
  "status": "error",
  "error": {
    "code": "invalid_wallet",
    "message": "Wallet must be a 0x-prefixed, 40-digit hexadecimal address."
  },
  "status_code": 400
}
```

Work is scheduled with bounded concurrency. Each calculation has a ten-second database budget, and the batch has a 25-second queue/result deadline inside the public request timeout. A maximum-size batch is accepted, but 100 uncached heavy wallets are not guaranteed to finish in that deadline. Start with batches of 5–10 for interactive use. Keep successful results and retry only transient failures in smaller batches; changing `max_trades` changes the analysis window.

Automatic expansion has up to two additional seconds per wallet within the existing ten-second calculation budget. It never silently lowers the requested fallback cap or returns a partly calculated financial total. The endpoint does not create a background job or update V2 BYOB wallets.


## OpenAPI

````yaml POST /v3/copy-pnl/batch
openapi: 3.1.0
info:
  title: PolyNode API
  description: >-
    Real-time Polymarket data API with decoded mempool settlements, OHLCV
    candles, and full Polygon JSON-RPC proxy.
  contact:
    name: PolyNode
    url: https://polynode.dev
  license:
    name: ''
  version: 2.0.0
servers:
  - url: https://api.polynode.dev
    description: Production
security:
  - api_key: []
paths:
  /v3/copy-pnl/batch:
    post:
      tags:
        - V3 Copy PnL
      summary: Copy PnL Batch
      description: >-
        Up to 100 input wallets with shared history/date options, ordered
        per-wallet results, lifetime realized-PnL context, and explicit
        per-wallet full/recent coverage. HTTP 200 can contain failed rows.
        25-second batch deadline; 10-second calculation budget. Auto expansion
        has at most two additional seconds within that budget. Default recent
        cap 50000 fills; full-history work limit 500000. One metered HTTP
        request.
      operationId: postV3CopyPnlBatch
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              additionalProperties: false
              required:
                - wallets
              properties:
                wallets:
                  type: array
                  minItems: 1
                  maxItems: 100
                  items:
                    type: string
                  description: Invalid addresses produce per-row errors.
                max_trades:
                  type: integer
                  minimum: 1
                  maximum: 50000
                  default: 50000
                  description: >-
                    Recent/fallback fill cap per wallet; initial scan size in
                    full mode. Auto/full may return more fills, up to the
                    500000-fill work limit.
                history:
                  type: string
                  enum:
                    - recent
                    - auto
                    - full
                  default: recent
                  description: >-
                    recent keeps the cap; auto attempts full history with an
                    explicit recent fallback; full requires complete matching
                    history or returns an error.
                period:
                  type: string
                  enum:
                    - 7d
                    - 14d
                    - 30d
                    - 60d
                    - 90d
                    - 180d
                  description: >-
                    Optional window ending at to or the calculation snapshot. No
                    default period. Explicit from overrides period.
                from:
                  oneOf:
                    - type: integer
                      minimum: 0
                      maximum: 253402300799
                    - type: string
                      pattern: ^(\d+|\d{4}-\d{2}-\d{2})$
                  description: >-
                    Inclusive start: Unix seconds or YYYY-MM-DD at UTC midnight.
                    Applies to fills and settlement events, not lifetime
                    realized-PnL context.
                to:
                  oneOf:
                    - type: integer
                      minimum: 0
                      maximum: 253402300799
                    - type: string
                      pattern: ^(\d+|\d{4}-\d{2}-\d{2})$
                  description: >-
                    Exclusive end: Unix seconds or YYYY-MM-DD at UTC midnight.
                    Defaults to the calculation snapshot.
      responses:
        '200':
          description: Ordered results; inspect status on every row
          content:
            application/json:
              schema:
                type: object
                required:
                  - results
                  - requested
                  - succeeded
                  - failed
                  - max_trades
                  - elapsed_ms
                properties:
                  results:
                    type: array
                    items:
                      oneOf:
                        - type: object
                          required:
                            - wallet
                            - status
                            - data
                            - cache
                          properties:
                            wallet:
                              type: string
                            status:
                              const: ok
                            data:
                              $ref: '#/components/schemas/CopyPnlSummary'
                            cache:
                              $ref: '#/components/schemas/CopyPnlCache'
                        - type: object
                          required:
                            - wallet
                            - status
                            - error
                            - status_code
                          properties:
                            wallet: {}
                            status:
                              const: error
                            error:
                              $ref: '#/components/schemas/CopyPnlError'
                            status_code:
                              type: integer
                  requested:
                    type: integer
                  succeeded:
                    type: integer
                  failed:
                    type: integer
                  max_trades:
                    type: integer
                  elapsed_ms:
                    type: integer
        '400':
          description: Invalid input
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    $ref: '#/components/schemas/CopyPnlError'
                required:
                  - error
components:
  schemas:
    CopyPnlSummary:
      type: object
      properties:
        wallet:
          type: string
        actual_pnl_usdc:
          type: string
        backtest_copy_pnl_usdc:
          type: string
        slippage_amount_usdc:
          type: string
        slippage_cost_rate_pct:
          type:
            - string
            - 'null'
        toxic_for_copying:
          type:
            - boolean
            - 'null'
        trade_count:
          type: integer
          minimum: 0
          maximum: 500000
        pnl_definition:
          type: string
        fees_included:
          type: boolean
        opening_inventory_valued:
          type: boolean
        open_positions_marked_to_market:
          type: boolean
        slippage_bps:
          type: object
          properties:
            buy:
              type: integer
            sell:
              type: integer
            buy_price_capped_at:
              type: string
          required:
            - buy
            - sell
            - buy_price_capped_at
        cashflows:
          type: object
          properties:
            buy_cost_usdc:
              type: string
            sell_revenue_usdc:
              type: string
            settlement_in_usdc:
              type: string
            settlement_out_usdc:
              type: string
          required:
            - buy_cost_usdc
            - sell_revenue_usdc
            - settlement_in_usdc
            - settlement_out_usdc
        event_counts:
          type: object
          properties:
            buys:
              type: integer
            sells:
              type: integer
            splits:
              type: integer
            merges:
              type: integer
            redemptions:
              type: integer
            neg_risk_conversions:
              type: integer
          required:
            - buys
            - sells
            - splits
            - merges
            - redemptions
            - neg_risk_conversions
        coverage:
          type: object
          properties:
            selection:
              type: string
            max_trades:
              type: integer
              minimum: 1
              maximum: 50000
            history_truncated:
              type: boolean
            window_start:
              oneOf:
                - type: object
                  properties:
                    type:
                      const: beginning_of_indexed_history
                  required:
                    - type
                - type: object
                  properties:
                    type:
                      const: inclusive_trade_cursor
                    block_number:
                      type: string
                    log_index:
                      type: string
                    timestamp:
                      type: number
                  required:
                    - type
                    - block_number
                    - log_index
                    - timestamp
                - type: object
                  properties:
                    type:
                      const: inclusive_timestamp
                    timestamp:
                      type: integer
                  required:
                    - type
                    - timestamp
            first_included_event_timestamp:
              type:
                - number
                - 'null'
            last_included_event_timestamp:
              type:
                - number
                - 'null'
            snapshot_at:
              type: string
              format: date-time
            requested_history:
              type: string
              enum:
                - recent
                - auto
                - full
            served_history:
              type: string
              enum:
                - recent
                - full
              description: >-
                Full means all indexed events matching the requested dates, not
                necessarily lifetime history.
            fallback_reason:
              type:
                - string
                - 'null'
              enum:
                - null
                - query_timeout
                - query_work_limit
                - activity_limit_exceeded
                - history_limit_exceeded
            lifetime_history_included:
              type: boolean
            window_end:
              oneOf:
                - type: object
                  properties:
                    type:
                      const: exclusive_timestamp
                    timestamp:
                      type: integer
                  required:
                    - type
                    - timestamp
                - type: object
                  properties:
                    type:
                      const: database_snapshot
                    snapshot_at:
                      type: string
                      format: date-time
                  required:
                    - type
                    - snapshot_at
          required:
            - selection
            - max_trades
            - history_truncated
            - window_start
            - first_included_event_timestamp
            - last_included_event_timestamp
            - snapshot_at
            - requested_history
            - served_history
            - fallback_reason
            - lifetime_history_included
            - window_end
        query_ms:
          type: integer
        realized_pnl_context:
          type: object
          properties:
            available:
              type: boolean
            scope:
              const: lifetime_wallet
            date_filters_applied:
              const: false
            source:
              const: api.wallet_pnl_current
            pnl_definition:
              const: realized
            total_realized_pnl_usdc:
              type:
                - string
                - 'null'
              description: >-
                Actual lifetime realized profit as stored at the recorded
                update; not filtered by from/to and not used in the slippage
                score.
            position_count:
              type:
                - integer
                - 'null'
            open_positions:
              type:
                - integer
                - 'null'
            updated_block:
              type:
                - string
                - 'null'
            updated_at:
              type:
                - string
                - 'null'
              format: date-time
            refresh_age_seconds:
              type:
                - integer
                - 'null'
              minimum: 0
            latest_indexed_fill_block:
              type:
                - string
                - 'null'
            freshness:
              type: string
              enum:
                - behind_indexed_fills
                - no_newer_indexed_fills
                - unknown
                - unavailable
              description: >-
                Compares summary update block with latest indexed fill. Does not
                certify settlement/valuation freshness.
          required:
            - available
            - scope
            - date_filters_applied
            - source
            - pnl_definition
            - total_realized_pnl_usdc
            - position_count
            - open_positions
            - updated_block
            - updated_at
            - refresh_age_seconds
            - latest_indexed_fill_block
            - freshness
        applied_filters:
          type: object
          properties:
            period:
              type:
                - string
                - 'null'
            from:
              type:
                - integer
                - 'null'
            to:
              type: integer
          required:
            - period
            - from
            - to
      required:
        - wallet
        - actual_pnl_usdc
        - backtest_copy_pnl_usdc
        - slippage_amount_usdc
        - slippage_cost_rate_pct
        - toxic_for_copying
        - trade_count
        - pnl_definition
        - fees_included
        - opening_inventory_valued
        - open_positions_marked_to_market
        - slippage_bps
        - cashflows
        - event_counts
        - coverage
        - query_ms
        - realized_pnl_context
        - applied_filters
    CopyPnlCache:
      type: object
      required:
        - status
        - age_ms
      properties:
        status:
          type: string
          enum:
            - hit
            - miss
            - coalesced
        age_ms:
          type: integer
          minimum: 0
    CopyPnlError:
      type: object
      required:
        - code
        - message
      properties:
        code:
          type: string
        message:
          type: string
  securitySchemes:
    api_key:
      type: apiKey
      in: header
      name: x-api-key

````