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

# Validate a credit

> Confirm the recipient account can receive the credit before any money moves.



## OpenAPI

````yaml products/bank-transfers/credit-api-example/credit-api-example.yaml POST /credits/validate
openapi: 3.1.0
info:
  title: Meridian Credit API — Reference Specification
  version: 1.0.0
  summary: >-
    Recommended API surface for bank partners receiving credit (payout)
    instructions from Meridian.
  description: >
    This is Meridian's **reference specification** for a bank partner Credit
    API. It is the API the

    **bank partner hosts** and **Meridian calls** whenever a product event
    requires funds to be pushed

    from Meridian's sponsored account to a customer's account at the home bank
    (for example, a customer

    withdrawal from a Retail Virtual Account).


    Partners are not required to implement this exact contract — Meridian adapts
    to existing partner

    APIs during onboarding. However, partners building a Credit API from scratch
    should start here:

    an API matching this specification plugs directly into Meridian's
    integration layer with minimal

    custom mapping, which shortens the integration timeline considerably.


    ## Lifecycle


    Meridian drives every credit through the same sequence:


    1. **`POST /credits`** (optional) — register the credit instruction ahead of
    any processing.
       The bank persists the data structure and returns `RECEIVED`. No checks against the recipient
       account, no money movement.
    2. **`POST /credits/validate`** (optional but recommended) — confirm the
    recipient account can
       receive the credit before any money movement. No funds move. Safe to call repeatedly.
    3. **`POST /credits/commit`** — execute the transfer. Idempotent on
    `transactionId`.

    4. **`GET /credits/{transactionId}`** — retrieve the current status.
    Meridian's workflow engine
       polls this until the credit reports `COMPLETED` or `FAILED`; it may also call it **before**
       commit as a pre-check, so an unknown `transactionId` must return `404` (not an error status),
       which Meridian treats as "not yet committed" rather than a failure.
    5. **Status webhook** (optional) — proactively notify Meridian of a final
    status instead of
       waiting for polling. See the `webhooks` section.

    Steps 1 and 2 are independent: Meridian may call validate without a prior
    create, and commit

    without either. Every request carries the full instruction payload, so no
    step depends on

    bank-side state from an earlier one.


    ## Response model


    If your core system can settle synchronously, returning a final result
    (`COMPLETED` or `FAILED`)

    straight from `commit` lets Meridian update the customer sooner. Meridian
    does not depend on it,

    though: it polls the status endpoint until the credit is terminal either
    way, so a synchronous

    final result is an optimization rather than a requirement.


    Most partners settle asynchronously. That is the expected case: return
    `PROCESSING` from commit

    and expose the final state via `GET /credits/{transactionId}` and, ideally,
    the status webhook.

    Align the polling and retry strategy with Meridian during onboarding.


    ## Idempotency


    `transactionId` is Meridian's unique identifier for the credit and is the
    idempotency key.

    If a `commit` is received for a `transactionId` that was already processed,
    return the original

    outcome (do not credit twice). If the payload differs from the original
    request for the same

    `transactionId`, return `409`.


    ## Business failures vs transport failures


    A credit that is *received and rejected by business rules* (account closed,
    limit exceeded,

    compliance block) is a **`200` response** with `status: FAILED` plus a
    machine-readable

    `errorCode`. Reserve `4xx`/`5xx` for malformed requests, authentication
    failures, and genuine

    server faults. This distinction is load-bearing: Meridian retries transport
    failures but treats

    business failures as final.


    ## Conventions


    These are the conventions used throughout this specification. They are
    recommendations, not

    requirements — Meridian can adapt to the bank's preferred formats during
    onboarding.


    - Amounts are strings with up to 2 decimal places (never floats), with an
    ISO 4217 currency code.

    - Country codes are ISO 3166-1 alpha-2 (`PH`, `US`).

    - Timestamps are RFC 3339 / ISO 8601 with timezone offset.

    - All requests and responses are `application/json` over HTTPS (TLS 1.2+).
  contact:
    name: Meridian Implementation Team
    url: https://docs.mnai.com/products/bank-transfers/credit-api
servers:
  - url: https://api.examplebank.com/meridian/v1
    description: Production (partner-hosted)
  - url: https://sandbox.examplebank.com/meridian/v1
    description: Sandbox (required before go-live)
security:
  - bearerAuth: []
tags:
  - name: Credits
    description: Validate, execute, and track credit (payout) instructions.
paths:
  /credits/validate:
    post:
      tags:
        - Credits
      summary: Validate a credit before execution
      description: >
        Confirms the recipient account is eligible to receive the credit
        (account exists, is active,

        can accept the amount, name matches where applicable). **No funds
        move.** May be called zero,

        one, or multiple times per transaction, including for standalone account
        lookups with no

        subsequent commit.


        Return `status: VALIDATED` when the credit would be accepted, or
        `status: FAILED` with an

        `errorCode` explaining why it would be rejected.
      operationId: validateCredit
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreditInstruction'
            examples:
              instruction:
                $ref: '#/components/examples/CreditInstructionExample'
      responses:
        '200':
          description: >-
            Validation outcome (both eligible and ineligible accounts return
            200).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CreditResult'
              examples:
                valid:
                  value:
                    transactionId: mrdn-9f2c1e4a-71bd-4c5e-a2f3-8d6b0c9e1a27
                    status: VALIDATED
                invalid:
                  value:
                    transactionId: mrdn-9f2c1e4a-71bd-4c5e-a2f3-8d6b0c9e1a27
                    status: FAILED
                    errorCode: ACCOUNT_INACTIVE
                    errorMessage: Recipient account is closed or dormant.
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '500':
          $ref: '#/components/responses/ServerError'
components:
  schemas:
    CreditInstruction:
      type: object
      description: A credit (payout) instruction from Meridian to the bank.
      required:
        - transactionId
        - amount
        - recipient
      properties:
        transactionId:
          type: string
          maxLength: 64
          description: >
            Meridian's unique identifier for this credit and the idempotency
            key. Stable across

            retries and across the validate/commit/status lifecycle of one
            transaction.
          example: mrdn-9f2c1e4a-71bd-4c5e-a2f3-8d6b0c9e1a27
        amount:
          $ref: '#/components/schemas/MonetaryAmount'
        recipient:
          $ref: '#/components/schemas/Recipient'
        sender:
          $ref: '#/components/schemas/Party'
          description: >
            Originator of the funds (KYC data). Included on commit for
            compliance screening.

            Field-level availability is confirmed during onboarding, and some
            corridors add further

            compliance fields (for example the sender's relationship to the
            recipient, or source of

            income) that Meridian agrees with the bank at that time.
        purpose:
          type: string
          maxLength: 140
          description: Human-readable purpose / remittance information for the transfer.
          example: Wallet withdrawal payout
        metadata:
          type: object
          additionalProperties:
            type: string
          description: >
            Additional key/value context supplied by Meridian (e.g. a
            customer-facing reference to

            print on statements). Banks should persist and echo these where
            their core allows, but

            must not require fields beyond those agreed at onboarding.
    CreditResult:
      type: object
      description: Outcome of a validate, commit, or status call. One shape for all three.
      required:
        - transactionId
        - status
      properties:
        transactionId:
          type: string
          description: Echo of Meridian's transaction identifier.
        status:
          $ref: '#/components/schemas/CreditStatus'
        bankReference:
          type: string
          maxLength: 64
          description: >
            The bank's own reference for the transfer, if one exists. Meridian
            stores this for

            reconciliation and support. Include it on every response after
            commit.
        errorCode:
          type: string
          description: >
            Machine-readable failure code. **Required whenever `status` is
            `FAILED`.** Use a stable,

            documented set; Meridian maps these to customer-facing outcomes.
            Recommended baseline:


            - `ACCOUNT_NOT_FOUND`

            - `ACCOUNT_INACTIVE`

            - `NAME_MISMATCH`

            - `LIMIT_EXCEEDED`

            - `INVALID_AMOUNT`

            - `COMPLIANCE_REJECTED`

            - `INSUFFICIENT_FUNDS` (sponsored account)

            - `DUPLICATE_TRANSACTION`

            - `BANK_SYSTEM_ERROR`
        errorMessage:
          type: string
          maxLength: 500
          description: >-
            Human-readable detail for the failure. Not shown to customers
            verbatim.
        completedAt:
          type: string
          format: date-time
          description: RFC 3339 timestamp when the credit reached a final status.
    MonetaryAmount:
      type: object
      required:
        - value
        - currency
      properties:
        value:
          type: string
          pattern: ^\d+(\.\d{1,2})?$
          description: Decimal amount as a string, up to 2 decimal places. Never a float.
          example: '1500.00'
        currency:
          type: string
          pattern: ^[A-Z]{3}$
          description: ISO 4217 currency code.
          example: PHP
    Recipient:
      type: object
      description: The customer being credited at the home bank.
      required:
        - account
        - firstName
        - lastName
      properties:
        account:
          $ref: '#/components/schemas/BankAccount'
        firstName:
          type: string
          maxLength: 70
          example: Maria
        middleName:
          type: string
          maxLength: 70
        lastName:
          type: string
          maxLength: 70
          example: Santos
    Party:
      type: object
      description: A person involved in the transaction (KYC subject).
      required:
        - firstName
        - lastName
      properties:
        firstName:
          type: string
          maxLength: 70
        middleName:
          type: string
          maxLength: 70
        lastName:
          type: string
          maxLength: 70
        dateOfBirth:
          type: string
          format: date
          description: >
            ISO 8601 date (YYYY-MM-DD). Some destinations require the sender's
            date of birth for

            compliance screening and reject the credit without it, so support
            this field even though

            it is not marked required here.
          example: '1990-01-15'
        countryOfResidence:
          type: string
          pattern: ^[A-Z]{2}$
          description: ISO 3166-1 alpha-2.
          example: PH
        address:
          $ref: '#/components/schemas/PostalAddress'
    CreditStatus:
      type: string
      description: >
        Transaction state machine:


        - `RECEIVED` — registered; nothing checked and nothing moved

        - `VALIDATED` — the recipient account passed eligibility checks

        - `PROCESSING` — money movement is underway

        - `COMPLETED` — terminal; the funds reached the recipient

        - `FAILED` — terminal; the credit will not be delivered

        - `UNKNOWN` — outcome not yet determinable, for example a timeout in
        your core system or an
          unreachable downstream rail; not terminal

        Status moves only forward through that order, though skipping steps is
        fine, and terminal

        statuses must never change once reported. `UNKNOWN` is exempt from the
        ordering and may be

        followed by any status. Prefer it over guessing `FAILED`, since a
        terminal status can never

        be walked back.
      enum:
        - RECEIVED
        - VALIDATED
        - PROCESSING
        - COMPLETED
        - FAILED
        - UNKNOWN
    ApiError:
      type: object
      description: Transport-level error payload for 4xx/5xx responses.
      required:
        - errorCode
        - errorMessage
      properties:
        errorCode:
          type: string
        errorMessage:
          type: string
    BankAccount:
      type: object
      description: Account identification at the home bank (intra-bank transfer target).
      required:
        - accountNumber
      properties:
        accountNumber:
          type: string
          maxLength: 34
          description: >-
            Account number in the bank's canonical format (or IBAN where
            applicable).
          example: '001234567890'
    PostalAddress:
      type: object
      properties:
        addressLines:
          type: array
          items:
            type: string
            maxLength: 70
          maxItems: 3
        city:
          type: string
          maxLength: 35
        stateProvince:
          type: string
          maxLength: 35
        postalCode:
          type: string
          maxLength: 16
        country:
          type: string
          pattern: ^[A-Z]{2}$
          description: ISO 3166-1 alpha-2.
          example: PH
  examples:
    CreditInstructionExample:
      summary: PHP 1,500.00 payout to a bank account
      description: >
        The same instruction is sent to create, validate, and commit. Only the
        endpoint changes.
      value:
        transactionId: mrdn-9f2c1e4a-71bd-4c5e-a2f3-8d6b0c9e1a27
        amount:
          value: '1500.00'
          currency: PHP
        recipient:
          account:
            accountNumber: '001234567890'
          firstName: Maria
          lastName: Santos
        sender:
          firstName: Juan
          lastName: Cruz
          dateOfBirth: '1990-01-15'
          address:
            addressLines:
              - 123 Test Street
            city: Taguig
            stateProvince: Metro Manila
            postalCode: '1634'
            country: PH
        metadata:
          reference: R9x8k2m4p6w1c3v5b7n9q0z2
  responses:
    BadRequest:
      description: >-
        Malformed request (missing/invalid fields). Not retryable without
        correction.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ApiError'
          example:
            errorCode: VALIDATION_ERROR
            errorMessage: >-
              amount.value must be a decimal string with at most 2 decimal
              places.
    Unauthorized:
      description: Missing or invalid credentials.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ApiError'
    ServerError:
      description: Unexpected bank-side failure. Meridian treats this as retryable.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ApiError'
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      description: >
        Assume OAuth 2.0 client credentials issued by the bank, presented as a
        bearer token.

        Meridian can adapt to the bank's preferred authentication scheme during
        onboarding.

````