---
title: "Incoming payment webhook and approval mechanism"
method: POST
path: "incoming-payment"
tags: ["Webhooks"]
---

# Incoming payment webhook and approval mechanism

`POST incoming-payment` (webhook)

Webhook that is called when an incoming payment is received by a customer's UMA address.
This endpoint should be implemented by clients of the Grid API.

### Authentication
The webhook includes a signature in the `X-Grid-Signature` header that allows you to verify that the webhook was sent by Grid.
To verify the signature:
1. Get the Grid public key provided to you during integration
2. Decode the base64 signature from the header
3. Create a SHA-256 hash of the request body
4. Verify the signature using the public key and the hash

If the signature verification succeeds, the webhook is authentic. If not, it should be rejected.

### Payment Approval Flow
When a transaction has `status: "PENDING"`, this webhook serves as an approval mechanism:

1. The client should check the `counterpartyInformation` against their requirements
2. To APPROVE the payment synchronously, return a 200 OK response
3. To REJECT the payment, return a 403 Forbidden response with an Error object
4. To request more information, return a 422 Unprocessable Entity with specific missing fields
5. To process the payment asynchronously, return a 202 Accepted response and then call the `/transactions/{transactionId}/approve` or `/transactions/{transactionId}/reject` endpoint within 5 seconds. Note that synchronous approval/rejection is preferred where possible.

The Grid system will proceed or cancel the payment based on your response.

For transactions with other statuses (COMPLETED, FAILED, REFUNDED), this webhook is purely informational.

## Payload

- IncomingPaymentWebhook
  - `id` string, required — Unique identifier for this webhook delivery (can be used for idempotency)
  - `type` 'INCOMING_PAYMENT.PENDING' | 'INCOMING_PAYMENT.COMPLETED' | 'INCOMING_PAYMENT.FAILED' | 'INCOMING_PAYMENT.REFUND_PENDING' | 'INCOMING_PAYMENT.REFUND_COMPLETED' | 'INCOMING_PAYMENT.REFUND_FAILED', required — Type of webhook event in OBJECT.EVENT dot-notation. The part before the dot identifies the resource, the part after identifies the event. This lets consumers route purely on type without inspecting data.status.
  - `timestamp` string, date-time, required — ISO 8601 timestamp of when the webhook was sent
  - `data` IncomingPaymentWebhookData, required
    - `id` string, required — Unique identifier for the transaction
    - `status` 'CREATED' | 'PENDING' | 'PENDING_AUTHORIZATION' | 'PROCESSING' | 'COMPLETED' | 'REJECTED' | 'FAILED' | 'REFUNDED' | 'EXPIRED', required — Status of a payment transaction. | Status | Description | |--------|-------------| | `CREATED` | Initial lookup has been created | | `PENDING` | Quote has been created | | `PENDING_AUTHORIZATION` | Awaiting Strong Customer Authentication. Only occurs for customers in a region where SCA is required (e.g. EU); authorize the transaction's `scaChallenge` to proceed. | | `PROCESSING` | Funding has been received and payment initiated | | `COMPLETED` | Cross border payment has been received, converted and payment has been sent to the offramp network | | `REJECTED` | Receiving institution or wallet rejected payment, payment has been refunded | | `FAILED` | An error occurred during payment | | `REFUNDED` | Payment was unable to complete and refunded | | `EXPIRED` | Quote has expired |
    - `type` 'INCOMING', required — Type of transaction (incoming payment or outgoing payment)
    - `direction` 'CREDIT' | 'DEBIT', required — Whether the transaction credits (funds in) or debits (funds out) the customer's account. Independent of `type`: an incoming transaction is normally a `CREDIT`, but an inbound ACH pull, for example, is an `INCOMING` transaction with a `DEBIT` direction.
    - `destination` union, required
      - AccountTransactionDestination — Destination account details
        - `destinationType` 'ACCOUNT', required — Type of transaction destination
        - `currency` string — Currency code for the destination
        - `accountId` string, required — Destination account identifier
        - `onChainTransaction` OnChainTransaction
          - `transactionHash` string, required — On-chain transaction hash of the crypto transfer for this leg of the transaction.
          - `network` 'BITCOIN' | 'ETHEREUM' | 'SOLANA' | 'BASE' | 'POLYGON' | 'TRON' | 'PLASMA' | 'SPARK', required — The blockchain network an on-chain transaction settled on. Whether this is the mainnet or a test network (e.g. Solana devnet) is determined by your platform's environment — sandbox platforms operate on test networks, production platforms on mainnet — mirroring how `cryptoNetwork` is interpreted elsewhere in the API.
      - UmaAddressTransactionDestination — UMA address destination details
        - `destinationType` 'UMA_ADDRESS', required — Type of transaction destination
        - `currency` string — Currency code for the destination
        - `umaAddress` string, required — UMA address of the recipient
    - `customerId` string, required — System ID of the customer this transaction belongs to
    - `platformCustomerId` string, required — Platform-specific ID of the customer this transaction belongs to
    - `settledAt` string, date-time — When the payment was or will be settled
    - `createdAt` string, date-time — When the transaction was created
    - `updatedAt` string, date-time — When the transaction was last updated
    - `receiptDeliveryConfirmedAt` string, date-time — The time at which the platform confirmed delivery of the receipt to their customer.
    - `agentId` string — If this transaction was initiated by an agent, the system-generated ID of that agent. Absent for platform-initiated transactions.
    - `description` string — Optional memo or description for the payment
    - `sentAmount` CurrencyAmount
      - `amount` integer, required — Amount in the smallest unit of the currency (e.g., cents for USD/EUR, satoshis for BTC)
      - `currency` Currency, required
        - `code` string — Three-letter currency code (ISO 4217) for fiat currencies. Some cryptocurrencies may use their own ticker symbols (e.g. "BTC" for Bitcoin, "USDC" for USDC, etc.)
        - `name` string — Full name of the currency
        - `symbol` string — Symbol of the currency
        - `decimals` integer — Number of decimal places for the currency
    - `exchangeRate` number — Number of sending currency units per receiving currency unit.
    - `quoteId` string — The ID of the quote that was used to trigger this payment
    - `refund` Refund
      - `reference` string, required — The unique reference ID of the refund
      - `initiatedAt` string, date-time, required — When the refund was initiated
      - `settledAt` string, date-time — When the refund was settled
      - `status` 'PENDING' | 'COMPLETED' | 'FAILED', required — Current status of the refund
      - `reason` 'TRANSACTION_FAILED' | 'USER_CANCELLATION' | 'TIMEOUT' — Reason for the refund
    - `counterpartyInformation` CounterpartyInformation — Additional information about the counterparty, if available and relevant to the transaction and platform.
    - `source` union
      - AccountTransactionSource — Source account details
        - `sourceType` 'ACCOUNT', required — Type of transaction source
        - `currency` string — Currency code for the source
        - `accountId` string, required — Source account identifier
        - `onChainTransaction` OnChainTransaction
          - `transactionHash` string, required — On-chain transaction hash of the crypto transfer for this leg of the transaction.
          - `network` 'BITCOIN' | 'ETHEREUM' | 'SOLANA' | 'BASE' | 'POLYGON' | 'TRON' | 'PLASMA' | 'SPARK', required — The blockchain network an on-chain transaction settled on. Whether this is the mainnet or a test network (e.g. Solana devnet) is determined by your platform's environment — sandbox platforms operate on test networks, production platforms on mainnet — mirroring how `cryptoNetwork` is interpreted elsewhere in the API.
      - UmaAddressTransactionSource — UMA address source details
        - `sourceType` 'UMA_ADDRESS', required — Type of transaction source
        - `currency` string — Currency code for the source
        - `umaAddress` string, required — UMA address of the sender
      - RealtimeFundingTransactionSource — Transaction was funded using an external funding source. All originator fields are optional and populated on a best-effort basis depending on what the funding source provides.
        - `sourceType` 'REALTIME_FUNDING', required — Type of transaction source
        - `currency` string, required — Currency code for the funding source
        - `customerId` string — The customer on whose behalf the transaction was initiated.
        - `accountHolderName` string — The name of the originator (sender) of the payment.
        - `accountIdentifier` string — The originator's account number or IBAN. May be masked or partial depending on the rail.
        - `bankName` string — The name of the originating bank.
        - `bankIdentifier` string — The identifier of the originating bank, such as a routing number, BIC, or SWIFT code.
        - `paymentRail` 'ACH' | 'ACH_COLOMBIA' | 'BANK_TRANSFER' | 'BRE_B' | 'CIPS' | 'FAST' | 'FASTER_PAYMENTS' | 'FEDNOW' | 'INSTAPAY' | 'MOBILE_MONEY' | 'NEFT' | 'PAYNOW' | 'PESONET' | 'PIX' | 'RTGS' | 'RTP' | 'SEPA' | 'SEPA_INSTANT' | 'SPEI' | 'SWIFT' | 'UNIONPAY' | 'UPI' | 'WIRE' — The payment rail used for the transfer. Payment rails represent the underlying payment network or system used to move funds between accounts.
        - `remittanceInformation` string — Free-form information about the payment provided by the originator. The source field depends on the payment rail: the Addenda record for ACH, the OBI / beneficiary information for wires, and the remittanceInformation field for RTP and FedNow.
        - `endToEndId` string — The originator's own end-to-end reference for the payment.
        - `traceNumber` string — Rail-level tracking identifier for the payment, such as an ACH trace number or a wire IMAD/OMAD, useful for reconciliation.
        - `onChainTransaction` OnChainTransaction
          - `transactionHash` string, required — On-chain transaction hash of the crypto transfer for this leg of the transaction.
          - `network` 'BITCOIN' | 'ETHEREUM' | 'SOLANA' | 'BASE' | 'POLYGON' | 'TRON' | 'PLASMA' | 'SPARK', required — The blockchain network an on-chain transaction settled on. Whether this is the mainnet or a test network (e.g. Solana devnet) is determined by your platform's environment — sandbox platforms operate on test networks, production platforms on mainnet — mirroring how `cryptoNetwork` is interpreted elsewhere in the API.
    - `receivedAmount` CurrencyAmount, required
      - `amount` integer, required — Amount in the smallest unit of the currency (e.g., cents for USD/EUR, satoshis for BTC)
      - `currency` Currency, required
        - `code` string — Three-letter currency code (ISO 4217) for fiat currencies. Some cryptocurrencies may use their own ticker symbols (e.g. "BTC" for Bitcoin, "USDC" for USDC, etc.)
        - `name` string — Full name of the currency
        - `symbol` string — Symbol of the currency
        - `decimals` integer — Number of decimal places for the currency
    - `fees` integer — The total fees available from the receive quote in the smallest unit of the sending currency (eg. cents).
    - `reconciliationInstructions` ReconciliationInstructions — Instructions for reconciling a payment with this transaction. For the on-chain transaction to or from an external crypto wallet that is the transaction's own source or destination, use the `onChainTransaction` on the relevant source or destination instead.
      - `reference` string — Unique reference code to include with the payment to match it with the correct incoming transaction, when available.
      - `transactionHash` string — Transaction hash of the internal settlement transfer used to deliver a UMA payment — the inter-VASP settlement leg (e.g. USDC on Solana to the receiving partner), when available. This is not a transfer to a customer's own wallet; for that, see the `onChainTransaction` on the transaction's source or destination.
    - `failureReason` 'LNURLP_FAILED' | 'PAY_REQUEST_FAILED' | 'PAYMENT_APPROVAL_WEBHOOK_ERROR' | 'PAYMENT_APPROVAL_TIMED_OUT' | 'OFFRAMP_FAILED' | 'MISSING_MANDATORY_PAYEE_DATA' | 'QUOTE_EXPIRED' | 'QUOTE_EXECUTION_FAILED' — Reason for failure of an incoming transaction. This is used to provide more context on why a transaction failed. If the transaction is not in a failed state, this field is omitted.
    - `requestedReceiverCustomerInfoFields` CounterpartyFieldDefinition[] — Information required by the sender's VASP about the recipient. Platform must provide these in the 200 OK response if approving. Note that this only includes fields which Grid does not already have from initial customer registration.
      - `name` 'FULL_NAME' | 'BIRTH_DATE' | 'NATIONALITY' | 'PHONE_NUMBER' | 'EMAIL' | 'POSTAL_ADDRESS' | 'TAX_ID' | 'REGISTRATION_NUMBER' | 'USER_TYPE' | 'COUNTRY_OF_RESIDENCE' | 'ACCOUNT_IDENTIFIER' | 'FI_LEGAL_ENTITY_NAME' | 'FI_ADDRESS' | 'PURPOSE_OF_PAYMENT' | 'ULTIMATE_INSTITUTION_COUNTRY' | 'IDENTIFIER' | 'BUSINESS_TYPE' | 'COMPANY_LEGAL_NAME' | 'ID_TYPE' | 'ID_NUMBER', required — Name of a type of field containing info about a platform's customer or counterparty customer.
      - `mandatory` boolean, required — Whether the field is mandatory

## Acknowledgement `200`

Webhook received successfully.
For PENDING transactions, this indicates approval to proceed with the payment.
If `requestedReceiverCustomerInfoFields` were present in the webhook request, the corresponding fields for the recipient must be included in this response in the `receiverCustomerInfo` object.

- IncomingPaymentWebhookResponse
  - `receiverCustomerInfo` object — Information about the recipient, provided by the platform if requested in the webhook via `requestedReceiverCustomerInfoFields` and the payment is approved.

## Other responses

- `202` — Webhook received and will be processed asynchronously. The synchronous 200 response should be preferred where possible. This asycnhronous path should only be used in cases where the platform's architecture requires async (but still very quick) processing before approving or rejecting the payment. The platform must call the `/transactions/{transactionId}/approve` or `/transactions/{transactionId}/reject` endpoint to approve or reject the payment within 5 seconds or the payment will be automatically rejected.
- `400` — Bad request
- `401` — Unauthorized - Signature validation failed
- `403` — Forbidden - Payment rejected by the client. Only applicable for PENDING transactions.
- `409` — Conflict - Webhook has already been processed (duplicate id)
- `422` — Unprocessable Entity - Additional counterparty information required. Only applicable for PENDING transactions.

---

[API](https://skmtc.net/stainless-api/apis/grid-api.md) · [All operations](https://skmtc.net/stainless-api/apis/grid-api/llms.txt) · [OpenAPI document](https://skmtc-service-staging.skmtc.workers.dev/v1/apis/stainless-api/grid-api/revisions/d5fa4e7d8c26/schema)
