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

# Create a credit

> Register a credit instruction with the bank ahead of validation and execution.



## OpenAPI

````yaml products/bank-transfers/credit-api-example/credit-api-example.yaml POST /credits
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:
    post:
      tags:
        - Credits
      summary: Register a credit instruction (no processing)
      description: >
        Accepts and persists the credit instruction ahead of validation and
        execution. The bank

        performs **schema-level checks only** (well-formed payload, supported
        currency, known

        `metadata` keys) and stores the data structure so later lifecycle calls
        can be reconciled

        against it. It must NOT check the recipient account (that is `validate`)
        and must NOT move

        funds (that is `commit`).


        Return `status: RECEIVED` on acceptance. Idempotent on `transactionId`:
        replaying the same

        instruction returns `RECEIVED` again; a replay with a different payload
        returns `409`. To read

        the current state of a transaction, use the status endpoint rather than
        this one.


        This endpoint is optional. Meridian may call `validate` or `commit`
        without a prior create,

        so banks must not require a `RECEIVED` record to exist before honoring
        the other endpoints.
      operationId: createCredit
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreditInstruction'
            examples:
              instruction:
                $ref: '#/components/examples/CreditInstructionExample'
      responses:
        '200':
          description: >-
            Instruction registered (or already registered with an identical
            payload).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CreditRegistrationResult'
              example:
                transactionId: mrdn-9f2c1e4a-71bd-4c5e-a2f3-8d6b0c9e1a27
                status: RECEIVED
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '409':
          description: The `transactionId` was already used with a different payload.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiError'
        '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.
    CreditRegistrationResult:
      type: object
      description: >
        Acknowledgement that the instruction was registered. No recipient checks
        have run and no

        funds have moved, so the only status this endpoint reports is
        `RECEIVED`.
      required:
        - transactionId
        - status
      properties:
        transactionId:
          type: string
          description: Echo of Meridian's transaction identifier.
        status:
          type: string
          enum:
            - RECEIVED
          description: >-
            Always `RECEIVED`. The instruction is stored and nothing else has
            happened yet.
    ApiError:
      type: object
      description: Transport-level error payload for 4xx/5xx responses.
      required:
        - errorCode
        - errorMessage
      properties:
        errorCode:
          type: string
        errorMessage:
          type: string
    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'
    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.

````