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

# Create transactions in a batch

> Records 1 to 100 manual transactions independently. Requires the `pfm:transactions:write` scope. Each row has the single-create fields and an `idempotency_key` with the same rules as the single-create header. The response preserves input order and uses zero-based indexes. A failed row does not undo successful rows. Retrying a successful row returns `replayed`; a changed body for its key returns `IDEMPOTENCY_CONFLICT`. The batch counts as one request.



## OpenAPI

````yaml /openapi.json post /v1/spaces/{space_id}/transactions/batch
openapi: 3.0.3
info:
  description: >-
    Personal REST API for Visor Pro and Premium users. Authenticate with a
    personal API token created in Visor Settings, sent as `Authorization: Bearer
    visor_pat_...`, or with an OAuth access token from the Visor CLI browser
    login.
  title: Visor Personal API
  version: 1.0.0
servers:
  - url: https://api.visorfinance.app
    variables: {}
security:
  - personal_api_token: []
  - visor_cli_oauth:
      - pfm:read
tags: []
paths:
  /v1/spaces/{space_id}/transactions/batch:
    post:
      tags:
        - Transactions
      summary: Create transactions in a batch
      description: >-
        Records 1 to 100 manual transactions independently. Requires the
        `pfm:transactions:write` scope. Each row has the single-create fields
        and an `idempotency_key` with the same rules as the single-create
        header. The response preserves input order and uses zero-based indexes.
        A failed row does not undo successful rows. Retrying a successful row
        returns `replayed`; a changed body for its key returns
        `IDEMPOTENCY_CONFLICT`. The batch counts as one request.
      operationId: VisorWeb.Api.V1.TransactionController.batch
      parameters:
        - description: A space `id` from `GET /v1/spaces`
          in: path
          name: space_id
          required: true
          schema:
            format: uuid
            type: string
      requestBody:
        content:
          application/json:
            example:
              transactions:
                - account_id: 5d3a9c1e-2b4f-4e6a-8c7d-1f0e9b2a3c45
                  amount: '42.90'
                  category_id: 3e9a1b7c-4d2f-4a8e-9b6c-0d1e2f3a4b5c
                  description: Padaria
                  idempotency_key: import-row-1
                  transacted_at: '2026-10-01T15:30:00-03:00'
                  type: debit
            schema:
              $ref: '#/components/schemas/TransactionBatchCreateRequest'
        description: The transactions to record
        required: true
      responses:
        '200':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TransactionBatchResponse'
          description: The ordered result of each row
          headers:
            x-ratelimit-limit:
              description: Requests allowed for this token per minute
              schema:
                example: 60
                type: integer
              style: simple
            x-ratelimit-remaining:
              description: Requests left for this token in the current minute
              schema:
                example: 59
                type: integer
              style: simple
            x-request-id:
              description: Request identifier, also returned as `request_id` in errors
              schema:
                type: string
              style: simple
        '400':
          content:
            application/json:
              example:
                errors:
                  - code: BAD_REQUEST
                    details:
                      parameter: include_hidden
                    message: The request is malformed.
                    request_id: F8x2kQ9vXc1AAAAB
              schema:
                $ref: '#/components/schemas/ErrorResponse'
          description: A query parameter has an invalid value
          headers:
            x-request-id:
              description: Request identifier, also returned as `request_id` in errors
              schema:
                type: string
              style: simple
        '401':
          content:
            application/json:
              example:
                errors:
                  - code: INVALID_TOKEN
                    details: {}
                    message: The personal API token is not valid.
                    request_id: F8x2kQ9vXc1AAAAB
              schema:
                $ref: '#/components/schemas/ErrorResponse'
          description: Missing, invalid, expired, or revoked token
          headers:
            x-request-id:
              description: Request identifier, also returned as `request_id` in errors
              schema:
                type: string
              style: simple
        '403':
          content:
            application/json:
              example:
                errors:
                  - code: INSUFFICIENT_SCOPE
                    details:
                      required_scope: pfm:transactions:write
                    message: The personal API token does not grant this operation.
                    request_id: F8x2kQ9vXc1AAAAB
              schema:
                $ref: '#/components/schemas/ErrorResponse'
          description: Pro or Premium plan required, or insufficient scope
          headers:
            x-request-id:
              description: Request identifier, also returned as `request_id` in errors
              schema:
                type: string
              style: simple
        '404':
          content:
            application/json:
              example:
                errors:
                  - code: NOT_FOUND
                    details: {}
                    message: The resource does not exist.
                    request_id: F8x2kQ9vXc1AAAAB
              schema:
                $ref: '#/components/schemas/ErrorResponse'
          description: The space does not exist or the token's user cannot access it
          headers:
            x-request-id:
              description: Request identifier, also returned as `request_id` in errors
              schema:
                type: string
              style: simple
        '406':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
          description: The client does not accept JSON
          headers:
            x-request-id:
              description: Request identifier, also returned as `request_id` in errors
              schema:
                type: string
              style: simple
        '429':
          content:
            application/json:
              example:
                errors:
                  - code: RATE_LIMITED
                    details:
                      retry_after_seconds: 42
                    message: >-
                      Too many requests. Retry after the number of seconds in
                      Retry-After.
                    request_id: F8x2kQ9vXc1AAAAB
              schema:
                $ref: '#/components/schemas/ErrorResponse'
          description: Rate limit exceeded
          headers:
            retry-after:
              description: Seconds until the current window ends
              schema:
                example: 42
                type: integer
              style: simple
            x-ratelimit-limit:
              description: Requests allowed for this token per minute
              schema:
                example: 60
                type: integer
              style: simple
            x-ratelimit-remaining:
              description: Requests left for this token in the current minute
              schema:
                example: 59
                type: integer
              style: simple
            x-request-id:
              description: Request identifier, also returned as `request_id` in errors
              schema:
                type: string
              style: simple
      callbacks: {}
components:
  schemas:
    TransactionBatchCreateRequest:
      additionalProperties: false
      properties:
        transactions:
          items:
            $ref: '#/components/schemas/TransactionBatchCreateItem'
          maxItems: 100
          minItems: 1
          type: array
      required:
        - transactions
      title: TransactionBatchCreateRequest
      type: object
    TransactionBatchResponse:
      additionalProperties: false
      properties:
        data:
          items:
            $ref: '#/components/schemas/TransactionBatchResult'
          maxItems: 100
          minItems: 1
          type: array
      required:
        - data
      title: TransactionBatchResponse
      type: object
    ErrorResponse:
      additionalProperties: false
      properties:
        errors:
          items:
            $ref: '#/components/schemas/Error'
          minItems: 1
          type: array
      required:
        - errors
      title: ErrorResponse
      type: object
    TransactionBatchCreateItem:
      additionalProperties: false
      properties:
        account_id:
          description: An account of the space. Its currency is the transaction's.
          format: uuid
          type: string
        amount:
          description: >-
            Positive decimal string with up to 2 decimal places. `type` gives
            the direction.
          example: '42.90'
          format: decimal
          pattern: ^\d{1,13}(\.\d{1,2})?$
          type: string
        category_id:
          description: A category of the space
          format: uuid
          type: string
        description:
          maxLength: 255
          minLength: 1
          type: string
        idempotency_key:
          description: >-
            The same key format and account-scoped replay rules as the
            single-create Idempotency-Key header
          maxLength: 128
          minLength: 1
          pattern: ^[A-Za-z0-9_\-.:]+$
          type: string
        ignored:
          default: false
          type: boolean
        merchant_name:
          maxLength: 255
          type: string
        notes:
          maxLength: 500
          type: string
        tag_ids:
          items:
            format: uuid
            type: string
          maxItems: 20
          type: array
        transacted_at:
          description: >-
            RFC 3339 date and time, with an offset such as `-03:00` or `Z`. A
            future time records a pending transaction.
          format: date-time
          type: string
        type:
          enum:
            - debit
            - credit
          type: string
      required:
        - account_id
        - transacted_at
        - description
        - amount
        - type
        - category_id
        - idempotency_key
      title: TransactionBatchCreateItem
      type: object
    TransactionBatchResult:
      additionalProperties: false
      properties:
        error:
          additionalProperties: false
          nullable: true
          properties:
            code:
              type: string
            details:
              additionalProperties: true
              type: object
            message:
              type: string
          required:
            - code
            - message
            - details
          type: object
        index:
          maximum: 99
          minimum: 0
          type: integer
        status:
          enum:
            - created
            - replayed
            - failed
          type: string
        transaction:
          additionalProperties: false
          nullable: true
          properties:
            account_id:
              format: uuid
              type: string
            amount:
              description: >-
                Absolute amount as a decimal string, in `currency_code`. `type`
                gives the direction.
              example: '42.90'
              format: decimal
              type: string
            category_id:
              format: uuid
              nullable: true
              type: string
            created_at:
              format: date-time
              type: string
            currency_code:
              description: ISO 4217 code
              example: BRL
              type: string
            description:
              type: string
            id:
              format: uuid
              type: string
            ignored:
              description: True when the transaction does not count in totals
              type: boolean
            merchant_name:
              nullable: true
              type: string
            notes:
              nullable: true
              type: string
            source:
              description: >-
                `manual` for a transaction you recorded, `connected` for one
                that a bank sent, `apple_pay` for one that the Apple Pay
                shortcut imported, and `pix` for a Pix you paid through Visor
                while the bank has not sent it yet. Only `manual` accepts edits
                to every field.
              enum:
                - manual
                - connected
                - apple_pay
                - pix
              type: string
            status:
              enum:
                - pending
                - posted
              type: string
            tag_ids:
              items:
                format: uuid
                type: string
              type: array
            transacted_at:
              format: date-time
              type: string
            type:
              description: '`debit` for money out, `credit` for money in'
              enum:
                - debit
                - credit
              type: string
            updated_at:
              format: date-time
              type: string
          required:
            - id
            - account_id
            - category_id
            - tag_ids
            - amount
            - type
            - currency_code
            - source
            - status
            - ignored
            - description
            - merchant_name
            - notes
            - transacted_at
            - created_at
            - updated_at
          title: Transaction
          type: object
      required:
        - index
        - status
        - transaction
        - error
      title: TransactionBatchResult
      type: object
    Error:
      additionalProperties: false
      properties:
        code:
          description: Stable machine-readable code
          example: INVALID_TOKEN
          type: string
        details:
          additionalProperties: true
          description: Code-specific context
          type: object
        message:
          description: English text for developers
          type: string
        request_id:
          description: The x-request-id response header of the request
          nullable: true
          type: string
      required:
        - code
        - message
        - details
        - request_id
      title: Error
      type: object
  securitySchemes:
    personal_api_token:
      bearerFormat: visor_pat_<public_id>_<secret>
      description: Personal API token created in Visor Settings
      scheme: bearer
      type: http
    visor_cli_oauth:
      description: >-
        OAuth 2.0 access token of the Visor CLI browser login (authorization
        code with PKCE). Only the first-party Visor CLI client can use it on
        this API.
      flows:
        authorizationCode:
          authorizationUrl: https://dashboard.visorfinance.app/oauth/authorize
          refreshUrl: https://dashboard.visorfinance.app/oauth/token
          scopes:
            pfm:read: Read financial data
            pfm:transactions:write: Create, edit, and delete transactions
            pix:payments:write: Start Pix payments that you confirm with biometrics at your bank
          tokenUrl: https://dashboard.visorfinance.app/oauth/token
      type: oauth2

````

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