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

# Record External Payment

> Record money already collected and settled in a lender/LMS. Requires the exact company-owned loan/account identifier. This creates no Finosu processor charge. The company-scoped transactionId is the atomic idempotency identity: exact retries return 200 and the original transaction; changed payloads return 409. Only settled USD payments are supported; pending, returns, reversals, refunds, negative adjustments, and corrections are rejected.

Use this endpoint when your lender or loan management system (LMS) collected a
payment outside Finosu and the money has already settled. Finosu records and
applies the payment; it does not create an ACH/card processor charge.

This is different from [Confirm ACH Settlement](/api-reference/endpoint/ach-confirms/create),
which updates a payment that Finosu already originated.

## Authentication and account identity

Send the company API key in `X-API-Key`. The key determines the company scope;
company or customer IDs in the request cannot widen it.

`loanId` is required and must be the exact company-owned external loan/account
identifier. A customer identifier is not accepted because one customer can have
multiple loans. Unknown or other-company identifiers return `404`. If legacy data
makes an identifier ambiguous within the authenticated company, Finosu returns
`409` and records nothing.

## Request

```json theme={null}
{
  "loanId": "ACCOUNT-1001",
  "transactionId": "lms-payment-001",
  "sourceSystem": "example-lms",
  "amount": "125.25",
  "currency": "USD",
  "paymentDate": "2026-10-16",
  "status": "settled",
  "settlesLoan": false
}
```

* `transactionId` is the lender's stable transaction identity. It must be
  unique across every feed used by the authenticated company, not merely within
  one loan.
* `sourceSystem` is a stable lowercase LMS identifier using letters, digits,
  `.`, `_`, or `-`. Finosu stores it as payment provenance.
* `amount` is a positive USD decimal no greater than `21474836.47`, with at
  most two fractional digits. JSON strings are recommended to preserve decimal
  precision.
* `paymentDate` is the settlement date in ISO `YYYY-MM-DD` format.
* `status` must be `settled`. Pending, submitted, failed, returned, reversed,
  or refunded events are not accepted by this contract.
* Set `settlesLoan` to `true` only after the lender has finalized this payment
  as full payoff or negotiated settlement. It invokes the existing external
  settlement flow, including stopping servicing and pending communications.

CamelCase is preferred. Matching snake\_case field names remain accepted. Extra
fields are rejected.

## Idempotency and conflicts

No separate idempotency header is needed. Finosu atomically claims
`(authenticated company, transactionId)` in the payment transaction itself.

* The first accepted request returns `201` and `status: "recorded"`.
* An exact retry returns `200`, the original `paymentTransactionId`, and
  `status: "duplicate"`. It does not apply money or settlement effects again.
* Reusing the same `transactionId` with a changed loan, source, amount, date,
  currency, status, or `settlesLoan` value returns `409`. The original payment
  remains unchanged.

The database uniqueness claim is race-safe, so simultaneous exact retries
produce one payment.

## Accounting and integration behavior

The payment is stored as a successful `EXTERNAL_IMPORT` transaction and uses
the same scheduled-payment allocation and external-settlement services as the
canonical CSV flow. Rollover rows may be created when one payment covers
multiple installments, but their total equals the request amount. Finosu does
not create an `AchPayment`, payment method, gateway transaction, or processor
charge.

Imports dated before boarding remain pre-boarding history and are not allocated
to a later Finosu payment plan. Existing balance calculations exclude that
history where the transferred balance already includes it, preventing double
counting. Post-boarding imports participate in normal balance, reporting, and
payoff calculations.

`EXTERNAL_IMPORT` payments are ineligible for LMS payment writeback. The stored
source provenance also identifies the originating LMS, preventing the import
from being echoed back as a new Finosu-originated payment.

## Response

```json theme={null}
{
  "paymentTransactionId": "17f82780-3c2d-4e71-bbad-03ca7f713e4f",
  "transactionId": "lms-payment-001",
  "loanId": "ACCOUNT-1001",
  "amount": "125.25",
  "currency": "USD",
  "paymentDate": "2026-10-16",
  "status": "recorded",
  "replayed": false,
  "overpayment": false,
  "settledLoan": false
}
```

## Returns, reversals, and corrections

Do not represent a return, reversal, or correction by sending a negative amount
or by reusing `transactionId` with changed data; both are rejected. The existing
`/ach-returns` API is only for ACH payments Finosu originated and is not a
general reversal API.

Until a separate immutable external-adjustment contract is published, contact
Finosu support for a reviewed correction. This endpoint never deletes or edits
an existing financial record.

## Errors

* `401` — missing, invalid, or inactive `X-API-Key`
* `404` — `loanId` is not owned by the authenticated company
* `409` — ambiguous `loanId`, or conflicting reuse of `transactionId`
* `422` — invalid identifier, amount, currency, date, status, or request shape
* `500` — the atomic payment/accounting operation failed and was rolled back


## OpenAPI

````yaml POST /external-payments
openapi: 3.1.0
info:
  title: Finosu API
  description: Finosu API
  license:
    name: MIT
  version: 1.0.0
servers:
  - url: https://api.finosu.com
security:
  - apiKeyAuth: []
paths:
  /external-payments:
    post:
      summary: Record a settled external payment
      description: >-
        Record money already collected and settled in a lender/LMS. Requires the
        exact company-owned loan/account identifier. This creates no Finosu
        processor charge. The company-scoped transactionId is the atomic
        idempotency identity: exact retries return 200 and the original
        transaction; changed payloads return 409. Only settled USD payments are
        supported; pending, returns, reversals, refunds, negative adjustments,
        and corrections are rejected.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PublicExternalPaymentRequest'
            example:
              loanId: ACCOUNT-1001
              transactionId: lms-payment-001
              sourceSystem: example-lms
              amount: '125.25'
              currency: USD
              paymentDate: '2026-10-16'
              status: settled
              settlesLoan: false
      responses:
        '200':
          description: >-
            Exact idempotent replay; no accounting or settlement effects were
            repeated.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PublicExternalPaymentResponse'
        '201':
          description: External payment recorded and applied.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PublicExternalPaymentResponse'
        '401':
          description: Missing, empty, invalid, or inactive X-API-Key.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: >-
            The exact loan/account identifier is not owned by the authenticated
            company.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '409':
          description: >-
            Ambiguous loan identifier or transactionId reused with a different
            payload.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: >-
            Invalid identifier, decimal amount, currency, date, status, or
            request shape.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ValidationErrorResponse'
        '500':
          description: The atomic payment/accounting operation failed and was rolled back.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      security:
        - apiKeyAuth: []
components:
  schemas:
    PublicExternalPaymentRequest:
      description: >-
        A successful payment already settled outside Finosu. CamelCase is
        preferred; matching snake_case aliases are accepted. Extra fields are
        rejected.
      type: object
      additionalProperties: false
      properties:
        loanId:
          type: string
          minLength: 1
          maxLength: 255
          description: Exact company-owned external loan/account identifier.
        transactionId:
          type: string
          minLength: 1
          maxLength: 200
          description: >-
            Stable lender transaction identity, unique across the authenticated
            company.
        sourceSystem:
          type: string
          minLength: 1
          maxLength: 50
          pattern: ^[a-z0-9][a-z0-9._-]*$
          description: Stable lowercase identifier of the originating LMS.
        amount:
          type: string
          format: decimal
          pattern: ^(?!0+(?:\.0{1,2})?$)\d{1,8}(?:\.\d{1,2})?$
          description: >-
            Positive USD amount no greater than 21474836.47, with at most two
            decimal places.
        currency:
          type: string
          enum:
            - USD
        paymentDate:
          type: string
          format: date
          description: Settlement date in YYYY-MM-DD format.
        status:
          type: string
          enum:
            - settled
        settlesLoan:
          type: boolean
          default: false
          description: >-
            True only for a lender-finalized full payoff or negotiated
            settlement.
      required:
        - loanId
        - transactionId
        - sourceSystem
        - amount
        - currency
        - paymentDate
        - status
    PublicExternalPaymentResponse:
      type: object
      properties:
        paymentTransactionId:
          type: string
          format: uuid
        transactionId:
          type: string
        loanId:
          type: string
        amount:
          type: string
          format: decimal
        currency:
          type: string
          enum:
            - USD
        paymentDate:
          type: string
          format: date
        status:
          type: string
          enum:
            - recorded
            - duplicate
        replayed:
          type: boolean
        overpayment:
          type: boolean
        settledLoan:
          type: boolean
      required:
        - paymentTransactionId
        - transactionId
        - loanId
        - amount
        - currency
        - paymentDate
        - status
        - replayed
        - overpayment
        - settledLoan
    Error:
      type: object
      required:
        - detail
      description: >-
        HTTP error envelope. Most errors contain a message; structured
        application errors may contain an object or array.
      properties:
        detail:
          oneOf:
            - type: string
            - additionalProperties: true
              type: object
            - type: array
              items: {}
    ValidationErrorResponse:
      type: object
      required:
        - detail
      properties:
        detail:
          description: >-
            Application validation returns a message; framework validation
            returns an array of field errors.
          anyOf:
            - type: string
            - type: array
              items:
                $ref: '#/components/schemas/ValidationError'
    ValidationError:
      type: object
      required:
        - loc
        - msg
        - type
      properties:
        loc:
          type: array
          items:
            anyOf:
              - type: string
              - type: integer
        msg:
          type: string
        type:
          type: string
  securitySchemes:
    apiKeyAuth:
      type: apiKey
      in: header
      name: X-API-Key

````

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