Incoming payment webhook and approval mechanism
Webhook that is called when an incoming payment is received by a customer — over UMA to the customer's UMA address, or over a bank rail (e.g. a SWIFT wire to the customer's funding coordinates from fundingPaymentInstructions). 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:
- Get the Grid public key provided to you during integration
- Decode the base64 signature from the header
- Create a SHA-256 hash of the request body
- 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:
- The client should check the counterpartyInformation against their requirements
- To APPROVE the payment synchronously, return a 200 OK response
- To REJECT the payment, return a 403 Forbidden response with an Error object
- To request more information, return a 422 Unprocessable Entity with specific missing fields
- 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.
Bank-rail incoming payments (e.g. SWIFT) are informational at every status, including PENDING: the funds have already moved interbank, so the approval mechanism and the 5-second response window do not apply.
Payload
Example payload
{
"id": "Webhook:019542f5-b3e7-1d02-0000-000000000007",
"timestamp": "2025-08-15T14:32:00Z",
"data": {
"id": "Transaction:019542f5-b3e7-1d02-0000-000000000004",
"destination": {
"destinationType": "ACCOUNT",
"currency": "EUR",
"accountId": "ExternalAccount:a12dcbd6-dced-4ec4-b756-3c3a9ea3d123",
"onChainTransaction": {
"transactionHash": "h82pJGF9p7kpzb6eU326EFZf2cDnimbTFVeJtx1qtBmUNJAEqN76R7PwPfHt3oWb8R6cKvhgyxQdDn53jFrK6wFx",
"network": "SOLANA"
}
},
"customerId": "Customer:019542f5-b3e7-1d02-0000-000000000001",
"platformCustomerId": "18d3e5f7b4a9c2",
"settledAt": "2025-08-15T14:30:00Z",
"createdAt": "2025-08-15T14:25:18Z",
"updatedAt": "2025-08-15T14:30:00Z",
"receiptDeliveryConfirmedAt": "2025-08-15T14:31:00Z",
"agentId": "Agent:019542f5-b3e7-1d02-0000-000000000042",
"description": "Payment for invoice #1234",
"sentAmount": {
"amount": 12550,
"currency": {
"code": "USD",
"name": "United States Dollar",
"symbol": "$",
"decimals": 2
}
},
"exchangeRate": 1.08,
"quoteId": "Quote:019542f5-b3e7-1d02-0000-000000000006",
"refund": {
"reference": "UMA-Q12345-REFUND",
"initiatedAt": "2025-08-15T14:30:00Z",
"settledAt": "2025-08-15T14:35:00Z",
"status": "COMPLETED",
"reason": "TRANSACTION_FAILED"
},
"counterpartyInformation": {
"FULL_NAME": "John Sender",
"BIRTH_DATE": "1985-06-15",
"NATIONALITY": "DE"
},
"source": {
"sourceType": "ACCOUNT",
"currency": "USD",
"accountId": "InternalAccount:e85dcbd6-dced-4ec4-b756-3c3a9ea3d965",
"onChainTransaction": {
"transactionHash": "h82pJGF9p7kpzb6eU326EFZf2cDnimbTFVeJtx1qtBmUNJAEqN76R7PwPfHt3oWb8R6cKvhgyxQdDn53jFrK6wFx",
"network": "SOLANA"
}
},
"receivedAmount": {
"amount": 12550,
"currency": {
"code": "USD",
"name": "United States Dollar",
"symbol": "$",
"decimals": 2
}
},
"fees": 10,
"reconciliationInstructions": {
"reference": "UMA-Q12345-REF",
"transactionHash": "0x9f2c6b6f4b6c8f2a8d9e0b1c2d3e4f5061728394a5b6c7d8e9f00112233445566"
},
"requestedReceiverCustomerInfoFields": [
{
"name": "FULL_NAME",
"mandatory": true
}
]
}
}Response
Webhook received successfully. For PENDING transactions on approval-mechanism rails, this indicates approval to proceed with the payment. For bank-rail incoming payments (e.g. SWIFT) a 200 only acknowledges receipt: there is nothing to approve. If requestedReceiverCustomerInfoFields were present in the webhook request, the corresponding fields for the recipient must be included in this response in the receiverCustomerInfo object.