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

# Create multiple transactions in a single atomic operation.

> Criação em lote é **atômica**: ou todos os N itens são criados, ou nenhum.
Cada item segue as validações da rota POST /transactions unitária e valida a própria origem (conta ou cartão).
Os lançamentos nascem não pagos; o status é derivado do vencimento como no POST unitário (a vencer, vence hoje ou vencido).
Limite: 1..100 itens. Cota consumida apenas pelo que foi criado.
`idempotency_key` (1..64 caracteres) permite replay: mesma chave e mesmo conteúdo devolve 201 com `replayed: true` e o resultado original, sem efeito novo.
Mesma chave com conteúdo diferente devolve 409 `idempotency_payload_mismatch`.
Segunda request com a mesma chave ainda em voo devolve 409 `concurrent_operation`.
Item com `payment_date` é rejeitado (`payment_date_not_allowed`). Item com `installments > 1` é rejeitado (`installments_not_allowed`).
422 com item inválido (`invalid_items`): devolve `BatchResponseDTO` com `results` completo, na ordem enviada; o item inválido traz `code`/`http_status`/`message` do erro da rota unitária e cada item válido traz `status = error`, `code = not_created`, `http_status = 422` (série atômica, nada foi criado).
422 com envelope inválido (lista vazia, acima de 100 itens, `idempotency_key` fora de 1..64) devolve `ErrorResponseDTO` com `error = invalid_envelope`.
402 `limit_exceeded` quando a cota mensal não comporta os N itens (o campo `error` traz a métrica `transactions_per_month`). Nada é criado.



## OpenAPI

````yaml /openapi/extat-openapi.json post /companies/transactions/batch
openapi: 3.0.0
info:
  contact:
    email: contato@cernedigital.io
    name: Cerne Digital
    url: https://cernedigital.io
  description: >-
    API REST da Extat Plataforma usada pelo painel web. Artefato OpenAPI 3.0
    para a documentação Mintlify (tags em PT-BR).
  license:
    name: Apache 2.0
    url: http://www.apache.org/licenses/LICENSE-2.0.html
  termsOfService: http://swagger.io/terms/
  title: Extat Plataforma - API REST
  version: '1.0'
servers:
  - url: https://golang-api-vgnqx.ondigitalocean.app/v1
security: []
tags:
  - name: Autenticação
  - name: Bancos
  - name: Contas Bancárias
  - name: Plano e Assinaturas
  - name: Empresa
  - name: Centros de Custo
  - name: Painel
  - name: Demonstrativos
  - name: Saúde
  - name: Convites
  - name: Membros
  - name: Onboarding
  - name: Fornecedores
  - name: Usuário
  - name: DangerZone
paths:
  /companies/transactions/batch:
    post:
      tags:
        - Empresa
      summary: Create multiple transactions in a single atomic operation.
      description: >-
        Criação em lote é **atômica**: ou todos os N itens são criados, ou
        nenhum.

        Cada item segue as validações da rota POST /transactions unitária e
        valida a própria origem (conta ou cartão).

        Os lançamentos nascem não pagos; o status é derivado do vencimento como
        no POST unitário (a vencer, vence hoje ou vencido).

        Limite: 1..100 itens. Cota consumida apenas pelo que foi criado.

        `idempotency_key` (1..64 caracteres) permite replay: mesma chave e mesmo
        conteúdo devolve 201 com `replayed: true` e o resultado original, sem
        efeito novo.

        Mesma chave com conteúdo diferente devolve 409
        `idempotency_payload_mismatch`.

        Segunda request com a mesma chave ainda em voo devolve 409
        `concurrent_operation`.

        Item com `payment_date` é rejeitado (`payment_date_not_allowed`). Item
        com `installments > 1` é rejeitado (`installments_not_allowed`).

        422 com item inválido (`invalid_items`): devolve `BatchResponseDTO` com
        `results` completo, na ordem enviada; o item inválido traz
        `code`/`http_status`/`message` do erro da rota unitária e cada item
        válido traz `status = error`, `code = not_created`, `http_status = 422`
        (série atômica, nada foi criado).

        422 com envelope inválido (lista vazia, acima de 100 itens,
        `idempotency_key` fora de 1..64) devolve `ErrorResponseDTO` com `error =
        invalid_envelope`.

        402 `limit_exceeded` quando a cota mensal não comporta os N itens (o
        campo `error` traz a métrica `transactions_per_month`). Nada é criado.
      parameters:
        - description: Company ID (UUID)
          in: header
          name: x-company-id
          required: true
          schema:
            type: string
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/transaction.BatchCreateRequestDTO'
        description: Batch creation request
        required: true
      responses:
        '201':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/transaction.BatchResponseDTO'
          description: >-
            Série criada, ou replay (`replayed = true`). `results` traz o `id`
            de cada lançamento, na ordem enviada.
        '400':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/handler.ErrorResponseDTO'
          description: >-
            JSON malformado, `x-company-id` ausente ou inválido, ou outro erro
            no nível da request.
        '401':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/handler.ErrorResponseDTO'
          description: JWT ausente ou inválido.
        '402':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/handler.ErrorResponseDTO'
          description: >-
            Cota mensal não comporta N novos itens (`limit_exceeded`). Nada é
            criado.
        '403':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/handler.ErrorResponseDTO'
          description: Usuário não é membro ativo da empresa do header.
        '409':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/handler.ErrorResponseDTO'
          description: >-
            `idempotency_key` já usada com conteúdo diferente
            (`idempotency_payload_mismatch`) ou disputa de lock
            (`concurrent_operation`). Nada é criado.
        '422':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/transaction.BatchResponseDTO'
          description: >-
            Item inválido (`invalid_items`): `results` completo, itens válidos
            com `not_created`. Envelope inválido devolve `ErrorResponseDTO`
            (`invalid_envelope`).
        '500':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/handler.ErrorResponseDTO'
          description: Erro interno do servidor.
      security:
        - ApiKeyAuth: []
components:
  schemas:
    transaction.BatchCreateRequestDTO:
      properties:
        idempotency_key:
          description: |-
            Chave de idempotência da série (1..64 caracteres).
            Escopo: por empresa. Permite detecção de divergência e replay.
            swagger:example "batch-invoices-2026-10-01"
          maxLength: 64
          minLength: 1
          type: string
        items:
          description: |-
            Lista de itens a criar. Limite: 1..100.
            Cada item segue as validações do POST /transactions unitário.
          items:
            $ref: '#/components/schemas/transaction.CreateTransactionRequestDTO'
          maxItems: 100
          minItems: 1
          type: array
      required:
        - idempotency_key
        - items
      type: object
    transaction.BatchResponseDTO:
      properties:
        replayed:
          description: >-
            Indica se a resposta é um replay de uma request anterior
            (idempotência).

            True: mesma chave de idempotência foi processada antes, nenhum
            efeito novo.

            False: request foi processada normalmente.

            Omitido em PATCH e DELETE.
          type: boolean
        results:
          description: Resultados por item, na ordem da request original.
          items:
            $ref: '#/components/schemas/transaction.BatchResultDTO'
          type: array
        series_id:
          description: >-
            Identificador da série criada (somente em POST /batch com status
            201).

            Omitido em caso de erro no nível da request.
          type: string
        summary:
          allOf:
            - $ref: '#/components/schemas/transaction.BatchSummaryDTO'
          description: Resumo agregado dos resultados.
      type: object
    handler.ErrorResponseDTO:
      properties:
        error:
          type: string
        message:
          type: string
      type: object
    transaction.CreateTransactionRequestDTO:
      properties:
        amount:
          type: number
        bank_account_id:
          type: string
        coa_id:
          type: integer
        competence:
          format: date
          type: string
        contact:
          type: string
        cost_center_id:
          description: >-
            CostCenterID e BankAccountID seguem string (e não ponteiro): o corpo

            atual continua válido byte a byte, e ausência de conta deixou de ser
            erro

            por si só — passou a depender de haver, ou não, cartão no lugar
            dela.
          type: string
        credit_card_account_id:
          description: >-
            CreditCardAccountID é a SEGUNDA origem possível (Decisão B).
            Aditivo:

            ausente, tudo se comporta exatamente como antes desta feature.
          type: string
        due_date:
          description: >-
            DueDate, Competence e PaymentDate são DateOnly (não time.Time):
            aceitam

            "AAAA-MM-DD" (Swagger) e RFC3339 (frontend web) — ver date_only.go.
          format: date
          type: string
        installments:
          description: >-
            Installments é PONTEIRO para distinguir "ausente" de "1". Os dois

            significam à vista, mas só o ponteiro permite recusar `installments`

            enviado junto com conta bancária — silenciar levaria o usuário a
            crer que

            parcelou algo que não foi parcelado (mesma regra que a coluna
            `Parcelas`

            do CSV tem na spec).


            O TETO (24, decisão Q2) NÃO é validado aqui: quem o decide é

            creditcardrepo.validatePurchaseRequest, via
            ErrInstallmentsOutOfRange, e

            duplicar o número neste arquivo criaria duas fontes para o mesmo
            limite.
          type: integer
        more_infos:
          type: string
        payment_date:
          format: date
          type: string
        reason:
          description: |-
            Reason é lido SÓ pelo PUT de lançamento de conta bancária
            (paid-transaction-reversal / T7): obrigatório quando a edição move
            dinheiro (valor, conta ou tipo de lançamento pago — RN7), ignorado
            quando não move. O POST de criação o ignora.
          type: string
        reference:
          type: string
        supplier_id:
          type: string
        tags:
          items:
            type: string
          type: array
        type:
          type: string
        url:
          type: string
      type: object
    transaction.BatchResultDTO:
      properties:
        code:
          description: >-
            Código do erro (ex.: "invalid_request", "not_found",
            "reason_required").

            Omitido quando status é "ok".
          type: string
        http_status:
          description: >-
            Status HTTP que seria retornado isoladamente (ex.: 400, 404, 422,
            409).

            Omitido quando status é "ok".
          type: integer
        id:
          description: >-
            Identificador da transação criada, alterada ou excluída (ou a
            solicitada).

            Omitido em caso de erro de validação antes da criação.
          type: string
        index:
          description: Posição do item na request original (base zero).
          type: integer
        message:
          description: |-
            Mensagem de erro em português.
            Omitida quando status é "ok".
          type: string
        status:
          description: |-
            Status do processamento: "ok" ou "error".
            swagger:enum "ok","error"
          type: string
      type: object
    transaction.BatchSummaryDTO:
      properties:
        failed:
          description: Itens que falharam.
          type: integer
        succeeded:
          description: Itens processados com sucesso.
          type: integer
        total:
          description: Total de itens processados.
          type: integer
      type: object
  securitySchemes:
    ApiKeyAuth:
      description: >-
        Token da sessão no cabeçalho Authorization, no formato Bearer (mesmo
        esquema ApiKeyAuth do contrato).
      in: header
      name: Authorization
      type: apiKey

````

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