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

# Send Outbound Payments

> Create and send SEPA Credit Transfer and Instant payments through CSM.

# Send Your First Payment

Inventi routes your SEPA payments through CSM, giving you direct access to European clearing networks.

<Info>
  **What happens when you send a payment:**

  1. You submit the payment via API
  2. Inventi validates and forwards to CSM
  3. The clearing system routes to the beneficiary bank
  4. You receive status updates via webhooks
</Info>

## Supported Payment Types

<CardGroup cols={2}>
  <Card title="SEPA Credit Transfer" icon="euro-sign">
    Standard transfers with next business day settlement
  </Card>

  <Card title="SEPA Instant" icon="bolt">
    Real-time payments settled in under 10 seconds
  </Card>
</CardGroup>

## API Reference

<CardGroup cols={2}>
  <Card title="Create SEPA Payment" icon="paper-plane" href="/payments/api/sepa/sepa-payment-create">
    Initiate SCT or Instant payment
  </Card>

  <Card title="Sign Transactions" icon="signature" href="/payments/api/sepa/transactions-sign">
    Approve payments requiring signature
  </Card>

  <Card title="Approve Transaction" icon="check" href="/payments/api/sepa/transaction-approve">
    Single transaction approval
  </Card>

  <Card title="Decline Transaction" icon="xmark" href="/payments/api/sepa/transaction-decline">
    Reject a pending transaction
  </Card>

  <Card title="Transaction Status Webhook" icon="bell" href="/payments/webhooks/payment-status-change">
    Track payment lifecycle
  </Card>

  <Card title="Get Transaction" icon="magnifying-glass" href="/payments/api/accounts/get-transaction">
    Retrieve payment details
  </Card>
</CardGroup>

## Business Requirements

<AccordionGroup>
  <Accordion title="Use idempotency for payment creation" icon="key">
    Always send an `Idempotency-Key` header when creating payments. If your request times out, retry with the same key to prevent duplicate payments.

    <Warning>
      Without idempotency, network retries can result in duplicate transactions.
    </Warning>
  </Accordion>

  <Accordion title="Treat trx_id as the primary key" icon="fingerprint">
    The create response returns `result.id` (transaction ID). Persist it immediately and use it for all subsequent operations.

    <Info>
      Store both `trx_id` and `end_to_end_id` for complete tracking and reconciliation.
    </Info>
  </Accordion>

  <Accordion title="Webhooks are the source of truth" icon="bell">
    Use the **Payment Status Change** webhook to update transaction state in real-time. Implement API polling only as a fallback for reconciliation.
  </Accordion>

  <Accordion title="TO_SIGN requires approval" icon="signature">
    Depending on your tenant configuration, transactions may require approval before processing. When status is `To sign`, use one of these methods:

    * **Single approval**: `PATCH /v1/transactions/{id}:approve`
    * **Bulk signing**: `POST /v1/transactions/signatures`

    <Tip>
      Choose based on your UX: single-button approve for simple flows, bulk signing for queue-based approval workflows.
    </Tip>
  </Accordion>
</AccordionGroup>

## Transaction Lifecycle

```mermaid actions={true} theme={null}
stateDiagram-v2
  [*] --> Created: create payment
  Created --> To_sign: requires approval
  Created --> Sent_to_clear: auto-accepted
  To_sign --> Signed: approve/sign
  Signed --> Sent_to_clear: sent to clearing
  Sent_to_clear --> Accepted: accepted by CSM
  Sent_to_clear --> Rejected: rejected by CSM
  Accepted --> Completed: settled
  Accepted --> Cancelled: camt.056 accepted
  Created --> Cancelled: cancelled
  To_sign --> Cancelled: cancelled
  Created --> Rejected: validation failed
  To_sign --> Rejected: rejected
  Signed --> Rejected: rejected
  Completed --> [*]
  Cancelled --> [*]
  Rejected --> [*]
```

## Transaction Statuses

<Tabs>
  <Tab title="SEPA Credit Transfer">
    | Status          | Description                       | Timing            |
    | --------------- | --------------------------------- | ----------------- |
    | `Created`       | Payment initiated                 | Immediate         |
    | `To sign`       | Awaiting approval (if configured) | Until signed      |
    | `Signed`        | Approved, queued for clearing     | Until cut-off     |
    | `Sent to clear` | Delivered to CSM for processing   | After cut-off     |
    | `Accepted`      | Accepted by CSM                   | Next business day |
    | `Completed`     | Settled at beneficiary bank       | D+1               |
  </Tab>

  <Tab title="SEPA Instant">
    | Status          | Description                       | Timing        |
    | --------------- | --------------------------------- | ------------- |
    | `Created`       | Payment initiated                 | Immediate     |
    | `To sign`       | Awaiting approval (if configured) | Until signed  |
    | `Signed`        | Approved, sent to clearing        | Immediate     |
    | `Sent to clear` | Delivered to CSM for processing   | Immediate     |
    | `Accepted`      | Accepted by CSM                   | Seconds       |
    | `Completed`     | Settled at beneficiary bank       | \< 10 seconds |
  </Tab>

  <Tab title="Error States">
    | Status      | Description                              |
    | ----------- | ---------------------------------------- |
    | `Cancelled` | Cancelled before clearing submission     |
    | `Rejected`  | Rejected by clearing or beneficiary bank |
  </Tab>
</Tabs>

## Create a Payment

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://api.pgw-sandbox.finventi.com/gateway/createSepaPmt \
    -H "Authorization: Bearer {token}" \
    -H "Content-Type: application/json" \
    -H "Idempotency-Key: {uuid}" \
    -d '{
      "dr_acc": "LT543210010000000003",
      "dr_name": "Sender Name",
      "dr_amount": 10657,
      "dr_ccy_isocode": "EUR",
      "cr_acc": "LT123450010000000004",
      "cr_name": "Recipient Name",
      "cr_amount": 10657,
      "cr_ccy_isocode": "EUR",
      "inst": true,
      "trx_purpose": "Invoice 2026-001"
    }'
  ```

  ```json Response theme={null}
  {
    "result": {
      "id": 12345,
      "status": "Created"
    }
  }
  ```
</CodeGroup>

### Request Fields

<ResponseField name="dr_acc" type="string" required>
  Debtor IBAN (sender account)
</ResponseField>

<ResponseField name="dr_name" type="string" required>
  Debtor name
</ResponseField>

<ResponseField name="dr_amount" type="integer" required>
  Amount in cents
</ResponseField>

<ResponseField name="dr_ccy_isocode" type="string" required>
  Currency code (EUR)
</ResponseField>

<ResponseField name="cr_acc" type="string" required>
  Creditor IBAN (recipient account)
</ResponseField>

<ResponseField name="cr_name" type="string" required>
  Creditor name
</ResponseField>

<ResponseField name="cr_amount" type="integer" required>
  Amount in cents
</ResponseField>

<ResponseField name="cr_ccy_isocode" type="string" required>
  Currency code (EUR)
</ResponseField>

<ResponseField name="inst" type="boolean">
  `true` for SEPA Instant, `false` for SCT
</ResponseField>

<ResponseField name="trx_purpose" type="string">
  Payment reference / remittance info
</ResponseField>

## Payment Flows

<Tabs>
  <Tab title="Without Signing">
    Standard flow when approval is not required.

    ```mermaid actions={true} theme={null}
    sequenceDiagram
    autonumber
    participant App as Your System
    participant Platform as Payments Platform
    participant Webhook as Your Webhook

    App->>Platform: POST /gateway/createSepaPmt
    Platform-->>App: 200 {id}
    Note over App: Store trx_id

    Platform-->>Webhook: Status: Created
    Platform-->>Webhook: Status: Sent to clear
    Platform-->>Webhook: Status: Accepted
    Platform-->>Webhook: Status: Completed
    Webhook->>App: Update status (final)
    ```
  </Tab>

  <Tab title="With Signing">
    Flow when transactions require approval before processing.

    ```mermaid actions={true} theme={null}
    sequenceDiagram
    autonumber
    participant App as Your System
    participant Platform as Payments Platform
    participant Webhook as Your Webhook

    App->>Platform: POST /gateway/createSepaPmt
    Platform-->>App: 200 {id}

    Platform-->>Webhook: Status: To sign
    Webhook->>App: Show approval action

    App->>Platform: POST /v1/transactions/signatures
    Platform-->>App: 200 {count, failedIds}

    Platform-->>Webhook: Status: Signed
    Platform-->>Webhook: Status: Sent to clear
    Platform-->>Webhook: Status: Accepted
    Platform-->>Webhook: Status: Completed
    ```

    <Note>
      **Signing rules:**

      * Only for SCT and SEPA Instant
      * Transaction must be in `To sign` status
      * Signing client must be different from creating client (maker-checker)
    </Note>
  </Tab>

  <Tab title="Decline Flow">
    When you need to reject a transaction waiting for approval.

    ```mermaid actions={true} theme={null}
    sequenceDiagram
    autonumber
    participant App as Your System
    participant Platform as Payments Platform
    participant Webhook as Your Webhook

    Platform-->>Webhook: Status: To sign

    App->>Platform: PATCH /v1/transactions/{id}:decline
    Platform-->>App: 200 OK

    Platform-->>Webhook: Status: Cancelled
    Webhook->>App: Update status (final)
    ```
  </Tab>
</Tabs>

## Sign Transactions

<CodeGroup>
  ```bash Single Approval theme={null}
  curl -X PATCH https://api.pgw-sandbox.finventi.com/v1/transactions/{id}:approve \
    -H "Authorization: Bearer {token}"
  ```

  ```bash Bulk Signing theme={null}
  curl -X POST https://api.pgw-sandbox.finventi.com/v1/transactions/signatures \
    -H "Authorization: Bearer {token}" \
    -H "Content-Type: application/json" \
    -d '{
      "transactionIds": [12345, 67890]
    }'
  ```

  ```json Bulk Response theme={null}
  {
    "count": 2,
    "failedToSignTransactionIds": []
  }
  ```
</CodeGroup>

<Warning>
  If `failedToSignTransactionIds` is not empty, those transactions were not signed. Check their status and retry if needed.
</Warning>

## Webhook Integration

### Payment Status Change

Each status transition triggers a webhook notification with these fields:

<ResponseField name="trx_id" type="string" required>
  Transaction identifier
</ResponseField>

<ResponseField name="end_to_end_id" type="string">
  End-to-end reference
</ResponseField>

<ResponseField name="direction" type="string" required>
  `OUTBOUND` for sent payments
</ResponseField>

<ResponseField name="status" type="string" required>
  Current transaction status
</ResponseField>

<ResponseField name="amount" type="integer" required>
  Amount in cents
</ResponseField>

<ResponseField name="currency" type="string" required>
  Currency code
</ResponseField>

<ResponseField name="updated_at" type="datetime" required>
  Status change timestamp
</ResponseField>

### Signature Verification

Verify webhook authenticity using these headers:

| Header                         | Purpose                      |
| ------------------------------ | ---------------------------- |
| `finventi-signature-1`         | RSASSA-PKCS1-v1\_5 signature |
| `finventi-signature-timestamp` | Request timestamp            |
| `finventi-receiver-tenant-id`  | Your tenant ID               |

See [Signature Verification](/payments/webhooks/signature-verification) for implementation details.

<Warning>
  If your webhook endpoint fails, the platform retries and **holds all subsequent notifications** until the blocked one succeeds.
</Warning>

## Reconciliation

Use API polling as a fallback when webhooks may have gaps.

<CardGroup cols={2}>
  <Card title="Get Transaction" icon="magnifying-glass" href="/payments/api/accounts/get-transaction">
    Retrieve current transaction details
  </Card>

  <Card title="Status History" icon="clock-rotate-left" href="/payments/api/accounts/get-transaction-status-history">
    View complete status timeline
  </Card>
</CardGroup>

<Tip>
  Run a nightly job to fetch recent transactions and compare statuses. Store any missing transitions for audit completeness.
</Tip>

## Data Model

Store these fields for complete tracking:

<ResponseField name="trx_id" type="string" required>
  Platform transaction ID (primary key)
</ResponseField>

<ResponseField name="end_to_end_id" type="string">
  Customer reference for reconciliation
</ResponseField>

<ResponseField name="idempotency_key" type="string" required>
  Your generated key for retry safety
</ResponseField>

<ResponseField name="current_status" type="string" required>
  Latest transaction status
</ResponseField>

<ResponseField name="status_history" type="array" required>
  Append-only list of status transitions
</ResponseField>

## Integration Checklist

<Steps>
  <Step title="Implement idempotency">
    Generate and persist an `Idempotency-Key` for each payment intent before calling the API
  </Step>

  <Step title="Store transaction ID">
    Persist `trx_id` from the response immediately after creation
  </Step>

  <Step title="Implement webhook receiver">
    Create an idempotent endpoint that responds `2xx` quickly and processes asynchronously
  </Step>

  <Step title="Verify webhook signatures">
    Validate authenticity using the provided signature headers
  </Step>

  <Step title="Handle signing flow">
    If approval is required, implement signing/approval actions for `To sign` transactions
  </Step>

  <Step title="Build reconciliation">
    Implement status polling as a fallback for missed webhooks
  </Step>
</Steps>

## What's Next?

You can now send payments. Next, set up your system to receive payments and handle the full payment lifecycle:

<CardGroup cols={2}>
  <Card title="Receive Payments" icon="arrow-down" href="/payments/integration-guide/incoming-sepa">
    Handle incoming SEPA payments via webhooks
  </Card>

  <Card title="Track and Reconcile" icon="chart-line" href="/payments/integration-guide/payment-information">
    Monitor transactions and reconcile with Nostro statements
  </Card>

  <Card title="Cancel Payments" icon="ban" href="/payments/integration-guide/outbound-cancellation">
    Request cancellation when needed
  </Card>

  <Card title="SWIFT Payments" icon="globe" href="/payments/integration-guide/swift-payments">
    Send international transfers outside SEPA
  </Card>
</CardGroup>
