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

# Serialize a v1 transaction

> Your own instructions, serialized exactly as given into an unsigned v1 (SIMD-0385)
transaction: nothing is inspected, reordered, added, signed, routed or sent. Use it to
assemble a swap you composed from `/swap-instructions` (plus your own instructions) without
writing a v1 encoder. The instruction JSON is the one `/swap-instructions` emits.

`config.computeUnitLimit` and `config.loadedAccountsDataSizeLimit` are **required and
nonzero**: in a v1 message an absent limit reads as zero at runtime, and the transaction
could not execute. Copy them from `transactionConfig` of the build, adding what your extra
instructions need. The router does not check the blockhash. Works on a router that is not ready.

Limits: 4,096 bytes, 64 instructions, 64 distinct account keys (`413 wire_limit`; nothing is truncated).


Guide: [Transactions](/router/transactions).


## OpenAPI

````yaml router.openapi.yaml POST /tx/v1
openapi: 3.1.0
info:
  title: Raze Swap Router API
  version: 1.0.0
  description: >
    Quotes and **unsigned** transactions for swaps on Solana, routed over ~20
    venues through a

    deploy of the `swap` program. The router **never signs and never sends**:
    you get a

    quote, then the instructions (or a serialized, unsigned transaction), and
    you sign and

    broadcast from your backend.


    **Public router.** `https://router.raze.bot` is Raze's router: it takes no
    key and builds for

    Raze's deploy of the `swap` program,
    `DADMMjfNnY6z8H9h9RfHZ9tfarBySsj4Yb65qLyKJDAD`.


    **One router, one `swap` deploy.** A router builds for the program address
    in its

    `ROUTER_SWAP_PROGRAM_ID` (the `programId` of every `swapInstruction` is that
    address) and

    reads that deploy's on-chain config: a venue the config has no live row for
    is never served,

    and while the config is paused every build answers `503`.


    **No authentication.** A router you run yourself has no keys, no accounts
    and no rate limit. It

    listens on loopback by default (`ROUTER_LISTEN=127.0.0.1:4700`); keep it
    behind your firewall or

    your own gateway.


    **Conventions:**

    - Amounts are integers in the token's base units (lamports, atoms). In
    quotes and builds the
      u64 amounts are decimal **strings** (`inAmount`, `outAmount`, `otherAmountThreshold`,
      `platformFee.amount`, every `costs.*`). `minReturn`, `maxAmountIn`, `computeUnits` and
      `contextSlot` are JSON numbers.
    - Mints and wallets are base58 addresses; wrapped SOL is
    `So11111111111111111111111111111111111111112`.

    - Venue labels (`label`, `dexes`, `excludeDexes`) are the `dex` names of
    `GET /venues`; input
      labels match case- and punctuation-insensitively, aliases included.
    - Request bodies are read as JSON whatever the `Content-Type`; at most 256
    KiB (larger is `413`).

    - Unknown fields and query parameters are ignored, not rejected.


    **Transactions are v1** (SIMD-0385, prefix `0x81`, up to 4,096 bytes and 64
    account keys, no

    address lookup tables). The compute-unit limit, loaded-accounts limit and
    priority fee travel in

    the message header (`transactionConfig`), not as ComputeBudget instructions.
    Signing a v1

    transaction needs an SDK that supports it. `txVersion: 0` and
    `asLegacyTransaction: true` are

    refused.


    **Errors** are `{"error", "reason", "quoteId"}`: `error` is a closed code,
    `reason` a label or a

    sentence, `quoteId` present once the request was parsed. The status says
    whose move it is:

    `400` fix the request, `404` no route exists, `409` re-quote or retry later,
    `413` too large,

    `422` a named decline that waiting will not change, `500` a router bug,
    `503` not ready: retry

    with backoff. Two bodies differ: `not_ready` carries `reasons` (a list)
    instead of `reason`, and

    a `low_liquidity` decline adds `liquidity`.


    The quote and swap fields mirror Jupiter's Swap API (Metis), so most clients
    change only the

    host; differences are listed on each operation.
servers:
  - url: https://router.raze.bot
    description: Raze's public router
  - url: http://127.0.0.1:4700
    description: Your own router (default ROUTER_LISTEN)
security: []
tags:
  - name: ops
    description: Liveness and readiness
  - name: venues
    description: The venues this router knows, and the price oracle's verdict on each
  - name: swap
    description: Quote, then build the instructions or the unsigned transaction
  - name: transactions
    description: Serialize your own instructions as an unsigned v1 transaction
paths:
  /tx/v1:
    post:
      tags:
        - transactions
      summary: Serialize instructions as a v1 transaction
      description: >
        Your own instructions, serialized exactly as given into an unsigned v1
        (SIMD-0385)

        transaction: nothing is inspected, reordered, added, signed, routed or
        sent. Use it to

        assemble a swap you composed from `/swap-instructions` (plus your own
        instructions) without

        writing a v1 encoder. The instruction JSON is the one
        `/swap-instructions` emits.


        `config.computeUnitLimit` and `config.loadedAccountsDataSizeLimit` are
        **required and

        nonzero**: in a v1 message an absent limit reads as zero at runtime, and
        the transaction

        could not execute. Copy them from `transactionConfig` of the build,
        adding what your extra

        instructions need. The router does not check the blockhash. Works on a
        router that is not ready.


        Limits: 4,096 bytes, 64 instructions, 64 distinct account keys (`413
        wire_limit`; nothing is truncated).
      operationId: serializeTxV1
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/TxV1Request'
            example:
              payer: 9WzDXwBbmkg8ZTbNMqUxvQRAyrZzDsGYdLVL9zYtAWWM
              instructions:
                - programId: '11111111111111111111111111111111'
                  accounts:
                    - pubkey: 9WzDXwBbmkg8ZTbNMqUxvQRAyrZzDsGYdLVL9zYtAWWM
                      isSigner: true
                      isWritable: true
                    - pubkey: 5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9
                      isSigner: false
                      isWritable: true
                  data: AgAAAAEAAAAAAAAA
              blockhash: 6ULNNrJUtsDgRFcEP462ebbxRMXo1HwtzY45WjG6D5vD
              config:
                computeUnitLimit: 1000
                loadedAccountsDataSizeLimit: 65536
                priorityFeeLamports: 1000
      responses:
        '200':
          description: The unsigned v1 transaction
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TxV1Response'
              example:
                swapTransaction: gQEAAQ8AAABRSwQ+upVuTIeWwCCmtaVlhi4tMrqENO/XArof9oe9LgEDfowI…
                txVersion: v1
                bytes: 236
                instructions: 1
        '400':
          description: >
            The request cannot be serialized. `error` is one of `bad_request`
            (the body is not the

            expected JSON, e.g. a missing field), `bad_address`,
            `no_instructions`, `bad_data`

            (instruction data is not standard base64; URL-safe base64 is
            refused), `missing_budget`,

            `invalid_message` (the message does not compile, e.g. the payer is
            also a program it calls).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              examples:
                missingBudget:
                  summary: >-
                    computeUnitLimit or loadedAccountsDataSizeLimit missing or
                    zero
                  value:
                    error: missing_budget
                    reason: >-
                      config.computeUnitLimit and
                      config.loadedAccountsDataSizeLimit are required and
                      nonzero: in a v1 message an absent limit reads as 0 at
                      runtime, and the transaction could not execute
                badData:
                  summary: URL-safe base64 in data
                  value:
                    error: bad_data
                    reason: 'instructions[0].data: not standard base64'
                missingField:
                  summary: No blockhash
                  value:
                    error: bad_request
                    reason: missing field `blockhash` at line 1 column 346
        '413':
          description: >
            `wire_limit`: more than 64 instructions, more than 64 distinct keys,
            or more than 4,096

            bytes. Split the instructions over two transactions; nothing was
            truncated. (A body over

            256 KiB is also `413`, with a plain-text body.)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: wire_limit
                reason: >-
                  65 instructions naming 2 distinct keys: a v1 message carries
                  at most 64 instructions and 64 keys — split them; nothing was
                  truncated
components:
  schemas:
    TxV1Request:
      type: object
      required:
        - payer
        - instructions
        - blockhash
      properties:
        payer:
          type: string
          description: Fee payer and first signer; it need not appear in any instruction
        instructions:
          type: array
          minItems: 1
          maxItems: 64
          items:
            $ref: '#/components/schemas/Instruction'
        blockhash:
          type: string
          description: A recent blockhash, base58
        config:
          type: object
          required:
            - computeUnitLimit
            - loadedAccountsDataSizeLimit
          properties:
            computeUnitLimit:
              type: integer
              minimum: 1
            loadedAccountsDataSizeLimit:
              type: integer
              minimum: 1
            priorityFeeLamports:
              type: integer
              description: >-
                Total in lamports (not per compute unit), as
                `transactionConfig.priorityFeeLamports`
            heapSize:
              type: integer
    TxV1Response:
      type: object
      properties:
        swapTransaction:
          type: string
          description: The unsigned v1 transaction, base64
        txVersion:
          type: string
          const: v1
        bytes:
          type: integer
          description: Serialized size (at most 4096)
        instructions:
          type: integer
          description: Number of instructions
    Error:
      type: object
      required:
        - error
        - reason
      properties:
        error:
          type: string
          description: >-
            Closed error code: `bad_request`, `declined`, `not_found`,
            `internal`, `quote_mismatch`, `invalid_route_ticket`,
            `route_ticket_mismatch`, `route_expired`, `bad_recipient`,
            `venue_red`, `rpc`, or on `/tx/v1` `bad_address`, `no_instructions`,
            `bad_data`, `missing_budget`, `invalid_message`, `wire_limit`
        reason:
          type: string
          description: >-
            With `declined`, a stable label (`no_route`, `cold_unresolved`,
            `platform_fee`, …); otherwise a sentence for humans
        quoteId:
          type: string
          description: >-
            16 hex digits, also in the router's logs. Absent when the request
            could not be parsed, and on `/tx/v1`
    Instruction:
      type: object
      required:
        - programId
        - accounts
        - data
      properties:
        programId:
          type: string
        accounts:
          type: array
          items:
            $ref: '#/components/schemas/AccountMeta'
        data:
          type: string
          description: Instruction data, standard base64
    AccountMeta:
      type: object
      required:
        - pubkey
      properties:
        pubkey:
          type: string
        isSigner:
          type: boolean
          default: false
        isWritable:
          type: boolean
          default: false

````

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