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

# Approve a transaction

> Posts the transaction's journal entry to the ledger. Requires the transactions:approve scope. Safe to retry; approving an approved transaction returns it unchanged. Fails when required dimensions are missing or the period is locked.



## OpenAPI

````yaml /openapi.json post /api/v1/transactions/{id}/approve
openapi: 3.0.3
info:
  title: Grain API
  description: >-
    Church accounting and donor management API. Use an organization API key for
    server automation or OAuth 2.1 (Sign in with Grain) for applications acting
    on behalf of users. Unmanaged OAuth requests require X-Organization-Id;
    Grain-managed OAuth apps may list authorized organizations first. API keys
    infer the organization.
  version: 1.3.0
servers:
  - url: https://api.grainledger.com
    description: API Server
security:
  - ApiKeyAuth: []
  - GrainOAuth2: []
  - BearerAuth: []
tags:
  - name: Funds
    description: Active funds available for integration mapping
  - name: Coding Reference Data
    description: Accounts, dimensions, and vendors used to code transactions
  - name: Transactions
    description: Bank transactions, coding, approval, and receipts
  - name: Bills
    description: Vendor bills from creation through payment
  - name: Donors
    description: Donor records and household relationships
  - name: Contributions
    description: Giving records with fund assignment and settlement
  - name: Giving Batches
    description: Contribution groups with derived totals and lifecycle state
  - name: Settlements
    description: Provider deposits with recorded and linked-contribution totals
  - name: Pledges
    description: Pledge campaigns and fulfillment tracking
  - name: Pledge Card Imports
    description: Submit structured pledge card data for review
  - name: Households
    description: Household groupings and primary contacts
  - name: Organizations
    description: Organizations the current Grain OAuth app is authorized to access
paths:
  /api/v1/transactions/{id}/approve:
    post:
      tags:
        - Transactions
      summary: Approve a transaction
      description: >-
        Posts the transaction's journal entry to the ledger. Requires the
        transactions:approve scope. Safe to retry; approving an approved
        transaction returns it unchanged. Fails when required dimensions are
        missing or the period is locked.
      operationId: approveTransaction
      parameters:
        - $ref: '#/components/parameters/OrganizationId'
        - $ref: '#/components/parameters/PathId'
      responses:
        '200':
          headers:
            X-Request-Id:
              description: >-
                Server-generated ID linking this request to API activity and
                audit records.
              schema:
                type: string
                format: uuid
          description: Approved transaction
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Transaction'
        '400':
          headers:
            X-Request-Id:
              description: >-
                Server-generated ID linking this request to API activity and
                audit records.
              schema:
                type: string
                format: uuid
          description: Bad request (missing header or invalid input)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          headers:
            X-Request-Id:
              description: >-
                Server-generated ID linking this request to API activity and
                audit records.
              schema:
                type: string
                format: uuid
          description: Unauthorized (missing or invalid Bearer token)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          headers:
            X-Request-Id:
              description: >-
                Server-generated ID linking this request to API activity and
                audit records.
              schema:
                type: string
                format: uuid
          description: Forbidden (no access to organization or action)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: Resource not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
          headers:
            X-Request-Id:
              description: >-
                Server-generated ID linking this request to API activity and
                audit records.
              schema:
                type: string
                format: uuid
        '409':
          headers:
            X-Request-Id:
              description: >-
                Server-generated ID linking this request to API activity and
                audit records.
              schema:
                type: string
                format: uuid
          description: >-
            Conflict (duplicate, cross-resource ownership conflict, concurrent
            change, or accounting-frozen resource)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: Validation error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
          headers:
            X-Request-Id:
              description: >-
                Server-generated ID linking this request to API activity and
                audit records.
              schema:
                type: string
                format: uuid
        '429':
          description: Rate limit exceeded
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
          headers:
            X-Request-Id:
              description: >-
                Server-generated ID linking this request to API activity and
                audit records.
              schema:
                type: string
                format: uuid
        '500':
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
          headers:
            X-Request-Id:
              description: >-
                Server-generated ID linking this request to API activity and
                audit records.
              schema:
                type: string
                format: uuid
components:
  parameters:
    OrganizationId:
      name: X-Organization-Id
      in: header
      required: false
      schema:
        type: string
      description: >-
        Required with OAuth access tokens for resource requests. Omit only for
        GET /api/v1/organizations. Optional with organization API keys; if
        supplied with an API key, it must match the key's organization.
      example: cm123abc456def
    PathId:
      name: id
      in: path
      required: true
      schema:
        type: string
      description: Resource ID
      example: cm456def789ghi
  schemas:
    Transaction:
      type: object
      additionalProperties: false
      required:
        - id
        - externalId
        - description
        - amount
        - direction
        - transactionType
        - date
        - referenceNumber
        - source
        - reviewStatus
        - isReconciled
        - is1099Excluded
        - bankAccount
        - sourceAccount
        - fund
        - vendor
        - dimensions
        - coding
        - suggestion
        - attachmentCount
        - canManage
        - createdAt
        - updatedAt
      properties:
        id:
          type: string
        externalId:
          type: string
          nullable: true
          description: Integrator-supplied ID, unique within the organization.
        description:
          type: string
        amount:
          type: number
          minimum: 0
          description: Always positive. Use direction for the sign.
        direction:
          type: string
          enum:
            - INFLOW
            - OUTFLOW
        transactionType:
          type: string
          enum:
            - DEPOSIT
            - WITHDRAWAL
            - TRANSFER
            - ADJUSTMENT
        date:
          type: string
          format: date-time
          description: Calendar day represented as a UTC-midnight ISO timestamp.
        referenceNumber:
          type: string
          nullable: true
        source:
          type: string
          enum:
            - MANUAL
            - PLAID
            - IMPORT
            - PLANNING_CENTER
            - PUSHPAY
            - TITHELY
            - SUBSPLASH
            - ROCK_RMS
            - RAMP
            - DIVVY
            - OVERFLOW
        reviewStatus:
          type: string
          enum:
            - DRAFT
            - PENDING_REVIEW
            - PENDING_TRANSFER_MATCH
            - PENDING_TRANSFER_CONFIRM
            - AUTO_CATEGORIZED
            - APPROVED
            - POSTED
            - REJECTED
        isReconciled:
          type: boolean
        is1099Excluded:
          type: boolean
        bankAccount:
          $ref: '#/components/schemas/TransactionBankAccountSummary'
          nullable: true
          description: Connected bank or card feed, when the transaction came from one.
        sourceAccount:
          $ref: '#/components/schemas/AccountRelationshipSummary'
          nullable: true
          description: Ledger cash, bank, or card account the transaction clears through.
        fund:
          $ref: '#/components/schemas/FundRelationshipSummary'
          nullable: true
        vendor:
          $ref: '#/components/schemas/NamedResourceSummary'
          nullable: true
        dimensions:
          type: array
          description: Header dimensions for the transaction.
          items:
            $ref: '#/components/schemas/DimensionAssignment'
        coding:
          $ref: '#/components/schemas/TransactionCoding'
        suggestion:
          $ref: '#/components/schemas/TransactionSuggestion'
          nullable: true
        attachmentCount:
          type: integer
          minimum: 0
        canManage:
          type: boolean
          description: Whether this credential can edit the transaction.
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
    Error:
      type: object
      description: >-
        Every error response is valid JSON with this shape. The HTTP status code
        carries the outcome; `code` is a stable machine-readable form of it.
      required:
        - code
        - message
      properties:
        code:
          type: string
          enum:
            - bad_request
            - unauthorized
            - forbidden
            - not_found
            - conflict
            - unprocessable_entity
            - payload_too_large
            - rate_limited
            - internal_server_error
          example: forbidden
        message:
          type: string
          example: You do not have access to this organization.
        error:
          type: string
          deprecated: true
          description: Deprecated alias for `message`. Read `message` instead.
          example: You do not have access to this organization.
        details:
          type: object
          description: >-
            Present for schema validation failures. Contains safe top-level
            field names and validation codes, never submitted values.
          properties:
            fields:
              type: array
              maxItems: 20
              items:
                type: object
                required:
                  - field
                  - code
                properties:
                  field:
                    type: string
                    example: amount
                  code:
                    type: string
                    example: invalid_type
    TransactionBankAccountSummary:
      type: object
      additionalProperties: false
      required:
        - id
        - name
        - mask
        - accountType
      properties:
        id:
          type: string
        name:
          type: string
        mask:
          type: string
          nullable: true
        accountType:
          type: string
          nullable: true
    AccountRelationshipSummary:
      type: object
      additionalProperties: false
      required:
        - id
        - accountNumber
        - name
        - accountType
      properties:
        id:
          type: string
        accountNumber:
          type: string
          nullable: true
        name:
          type: string
        accountType:
          type: string
          nullable: true
    FundRelationshipSummary:
      type: object
      additionalProperties: false
      required:
        - id
        - name
        - fundType
      properties:
        id:
          type: string
        name:
          type: string
        fundType:
          type: string
          nullable: true
    NamedResourceSummary:
      type: object
      additionalProperties: false
      required:
        - id
        - name
      properties:
        id:
          type: string
        name:
          type: string
    DimensionAssignment:
      type: object
      additionalProperties: false
      required:
        - dimensionId
        - dimensionValueId
      properties:
        dimensionId:
          type: string
        dimensionName:
          type: string
          nullable: true
          readOnly: true
        dimensionValueId:
          type: string
        dimensionValueName:
          type: string
          nullable: true
          readOnly: true
    TransactionCoding:
      type: object
      additionalProperties: false
      required:
        - status
        - journalEntryId
        - entryNumber
        - isSplit
        - lines
        - missingRequiredDimensions
      properties:
        status:
          type: string
          enum:
            - UNCATEGORIZED
            - CATEGORIZED
            - APPROVED
          description: >-
            UNCATEGORIZED has no journal entry. CATEGORIZED has a draft entry.
            APPROVED has a posted entry.
        journalEntryId:
          type: string
          nullable: true
        entryNumber:
          type: string
          nullable: true
        isSplit:
          type: boolean
        lines:
          type: array
          description: Category-side journal lines. The bank or card line is omitted.
          items:
            $ref: '#/components/schemas/TransactionCodingLine'
        missingRequiredDimensions:
          type: array
          description: >-
            Required dimensions that must be assigned before the transaction can
            be approved.
          items:
            type: object
            additionalProperties: false
            required:
              - dimensionId
              - dimensionName
            properties:
              dimensionId:
                type: string
              dimensionName:
                type: string
    TransactionSuggestion:
      type: object
      additionalProperties: false
      required:
        - account
        - fund
        - confidence
      description: Rule or AI coding suggestion awaiting review.
      properties:
        account:
          $ref: '#/components/schemas/AccountRelationshipSummary'
          nullable: true
        fund:
          $ref: '#/components/schemas/FundRelationshipSummary'
          nullable: true
        confidence:
          type: integer
          minimum: 0
          maximum: 100
          nullable: true
    TransactionCodingLine:
      type: object
      additionalProperties: false
      required:
        - id
        - account
        - fund
        - amount
        - memo
        - dimensions
      properties:
        id:
          type: string
          description: Journal entry line ID.
        account:
          $ref: '#/components/schemas/AccountRelationshipSummary'
          nullable: true
        fund:
          $ref: '#/components/schemas/FundRelationshipSummary'
          nullable: true
        amount:
          type: number
          description: >-
            Allocated amount. Positive values allocate the transaction; negative
            values offset another line.
        memo:
          type: string
          nullable: true
        dimensions:
          type: array
          items:
            $ref: '#/components/schemas/DimensionAssignment'
  securitySchemes:
    ApiKeyAuth:
      type: http
      scheme: bearer
      bearerFormat: grain_live_… or grain_test_…
      description: >-
        Organization API key created in Grain Settings → API. The key determines
        the organization and is limited to its assigned resource scopes. Write
        scopes imply the corresponding read scope.
    GrainOAuth2:
      type: oauth2
      flows:
        authorizationCode:
          authorizationUrl: https://auth.grainledger.com/auth/v1/oauth/authorize
          tokenUrl: https://auth.grainledger.com/auth/v1/oauth/token
          scopes:
            openid: OpenID Connect
            email: Email address
            profile: Profile information
    BearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: OAuth access token (JWT)

````

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