> ## 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.

# Start a Pix payment

> Starts a Pix to one Pix key and returns it with a `start_url`. Open `start_url` in the browser: the first Pix from a bank opens the bank page to authorize Visor, then every Pix opens the page where the user confirms with biometrics. Nothing is paid until the user confirms there. Requires the `pix:payments:write` scope (Visor CLI login), the Pro or Premium plan, and an `Idempotency-Key` header. A retry with the same key and the same Pix returns the Pix already started, with `idempotent-replayed: true`; the same key with another key, amount, or description returns `409 IDEMPOTENCY_CONFLICT`. Read `GET /v1/pix-payments/{pix_payment_id}` until `status` is final.



## OpenAPI

````yaml /openapi.json post /v1/pix-payments
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/pix-payments:
    post:
      tags:
        - Pix payments
      summary: Start a Pix payment
      description: >-
        Starts a Pix to one Pix key and returns it with a `start_url`. Open
        `start_url` in the browser: the first Pix from a bank opens the bank
        page to authorize Visor, then every Pix opens the page where the user
        confirms with biometrics. Nothing is paid until the user confirms there.
        Requires the `pix:payments:write` scope (Visor CLI login), the Pro or
        Premium plan, and an `Idempotency-Key` header. A retry with the same key
        and the same Pix returns the Pix already started, with
        `idempotent-replayed: true`; the same key with another key, amount, or
        description returns `409 IDEMPOTENCY_CONFLICT`. Read `GET
        /v1/pix-payments/{pix_payment_id}` until `status` is final.
      operationId: VisorWeb.Api.V1.PixPaymentController.create
      parameters:
        - description: >-
            A value you choose for this Pix, 1 to 128 letters, digits, or `-`
            `_` `.` `:`. Send the same value when you retry. A UUID per Pix
            works well.
          in: header
          name: Idempotency-Key
          required: true
          schema:
            maxLength: 128
            minLength: 1
            pattern: ^[A-Za-z0-9_\-.:]+$
            type: string
      requestBody:
        content:
          application/json:
            example:
              amount: '20.00'
              bank: Nubank
              description: Almoço
              key_type: cpf
              pix_key: 123.456.789-09
            schema:
              $ref: '#/components/schemas/PixPaymentCreateRequest'
        description: The Pix to start
        required: true
      responses:
        '201':
          content:
            application/json:
              example:
                data:
                  amount: '20.00'
                  bank:
                    linked: true
                    name: Nubank
                  created_at: '2026-10-22T15:31:02Z'
                  currency: BRL
                  description: Almoço
                  end_to_end_id: null
                  failure: null
                  id: 7b2d5e91-3c4a-4f68-9a0b-1c2d3e4f5a6b
                  paid_at: null
                  pix_key_masked: '***.456.789-**'
                  recipient: null
                  start_url: >-
                    https://dashboard.visorfinance.app/pix/payments/continue?ref=SFMyNTY.g2gDdAAAAAJ
                  status: pending
                  waiting_for: payment_confirmation
              schema:
                $ref: '#/components/schemas/PixPaymentResponse'
          description: The started Pix, or the one already started with the same key
          headers:
            idempotent-replayed:
              description: >-
                `true` when the response returns the record already created with
                the same Idempotency-Key
              schema:
                enum:
                  - 'true'
                  - 'false'
                type: string
              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
        '400':
          content:
            application/json:
              example:
                errors:
                  - code: BAD_REQUEST
                    details:
                      field: currency_code
                    message: The request is malformed.
                    request_id: F8x2kQ9vXc1AAAAB
              schema:
                $ref: '#/components/schemas/ErrorResponse'
          description: >-
            The body has a field the operation does not accept, or (on create)
            the Idempotency-Key header is missing or malformed
          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: pix:payments: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, insufficient scope, or Pix not
            available for the account
          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
        '409':
          content:
            application/json:
              example:
                errors:
                  - code: IDEMPOTENCY_CONFLICT
                    details: {}
                    message: >-
                      This Idempotency-Key was already used with a different
                      request.
                    request_id: F8x2kQ9vXc1AAAAB
              schema:
                $ref: '#/components/schemas/ErrorResponse'
          description: >-
            The Idempotency-Key was used with a different Pix, or the Pix cannot
            start again with it
          headers:
            x-request-id:
              description: Request identifier, also returned as `request_id` in errors
              schema:
                type: string
              style: simple
        '422':
          content:
            application/json:
              example:
                errors:
                  - code: BANK_REQUIRED
                    details:
                      banks:
                        - Nubank
                        - Itaú
                    message: >-
                      Send the bank the Pix comes from in the bank field. See
                      details.banks for suggestions.
                    request_id: F8x2kQ9vXc1AAAAB
              schema:
                $ref: '#/components/schemas/ErrorResponse'
          description: >-
            The body has invalid values, or the Pix cannot start. `code` is
            `VALIDATION_FAILED`, `AMBIGUOUS_PIX_KEY`,
            `PIX_MONTHLY_LIMIT_REACHED`, `CPF_REQUIRED`, `BANK_REQUIRED`, or
            `BANK_NOT_FOUND`
          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: {}
      security:
        - visor_cli_oauth:
            - pix:payments:write
components:
  schemas:
    PixPaymentCreateRequest:
      additionalProperties: false
      properties:
        amount:
          description: >-
            The amount in BRL as a positive decimal string with up to 2 decimal
            places
          example: '20.00'
          format: decimal
          type: string
        bank:
          description: >-
            The bank the user pays from. Without it, Visor uses the one bank the
            user already linked, or answers `BANK_REQUIRED`.
          maxLength: 100
          type: string
        description:
          maxLength: 140
          type: string
        key_type:
          description: >-
            The key type. Send it when the key can be a CPF and a phone
            (`AMBIGUOUS_PIX_KEY`).
          enum:
            - phone
            - cpf
            - cnpj
            - email
            - evp
          type: string
        link_device:
          default: false
          description: >-
            Link the bank again before the payment, on the device that opens
            `start_url`. A bank link (its passkey) belongs to the device that
            created it, and a bank can be linked on several devices. Send `true`
            to confirm on a device that is not linked yet; `bank.linked` is then
            `false` and `start_url` opens the bank page first.
          type: boolean
        pix_key:
          description: >-
            The Pix key as the user typed it: an email, a CPF, a CNPJ, a phone
            (with or without +55), or a random key (EVP).
          type: string
      required:
        - pix_key
        - amount
      title: PixPaymentCreateRequest
      type: object
    PixPaymentResponse:
      additionalProperties: false
      properties:
        data:
          $ref: '#/components/schemas/PixPayment'
      required:
        - data
      title: PixPaymentResponse
      type: object
    ErrorResponse:
      additionalProperties: false
      properties:
        errors:
          items:
            $ref: '#/components/schemas/Error'
          minItems: 1
          type: array
      required:
        - errors
      title: ErrorResponse
      type: object
    PixPayment:
      additionalProperties: false
      properties:
        amount:
          description: The amount in BRL as a decimal string
          example: '20.00'
          format: decimal
          type: string
        bank:
          allOf:
            - $ref: '#/components/schemas/PixPaymentBank'
          description: The bank the Pix comes from; `null` before a bank is chosen
          nullable: true
        created_at:
          format: date-time
          type: string
        currency:
          example: BRL
          type: string
        description:
          nullable: true
          type: string
        end_to_end_id:
          description: The Pix end-to-end id of a completed Pix
          nullable: true
          type: string
        failure:
          allOf:
            - $ref: '#/components/schemas/PixPaymentFailure'
          description: Set when the status is `failed`
          nullable: true
        id:
          format: uuid
          type: string
        paid_at:
          format: date-time
          nullable: true
          type: string
        pix_key_masked:
          description: The Pix key with its middle hidden
          type: string
        recipient:
          description: The recipient name, once the bank returns it
          nullable: true
          type: string
        start_url:
          description: >-
            The page to open in the browser while the Pix is `pending`: the bank
            page on the first Pix from a bank, then the page where the user
            confirms with biometrics. Only the user who started the Pix gets it.
          format: uri
          nullable: true
          type: string
        status:
          description: >-
            `pending` while the user authorizes the bank or confirms the Pix.
            Only `completed` means the Pix was paid; `failed`, `canceled`, and
            `expired` are final.
          enum:
            - awaiting_confirmation
            - pending
            - completed
            - failed
            - canceled
            - expired
          type: string
        waiting_for:
          description: The step the user does next while the Pix is `pending`, else `null`
          enum:
            - bank_authorization
            - payment_confirmation
          nullable: true
          type: string
      required:
        - id
        - status
        - waiting_for
        - amount
        - currency
        - pix_key_masked
        - recipient
        - description
        - bank
        - start_url
        - end_to_end_id
        - failure
        - created_at
        - paid_at
      title: PixPayment
      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
    PixPaymentBank:
      additionalProperties: false
      properties:
        linked:
          description: >-
            `false` while the user still has to authorize Visor at the bank. The
            first Pix from a bank opens the bank page.
          type: boolean
        name:
          example: Nubank
          type: string
      required:
        - name
        - linked
      title: PixPaymentBank
      type: object
    PixPaymentFailure:
      additionalProperties: false
      properties:
        code:
          description: The provider or Visor code of the failure
          example: SALDO_INSUFICIENTE
          type: string
        message:
          description: Text for the user, in the language of their Visor account
          type: string
      required:
        - code
        - message
      title: PixPaymentFailure
      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.