This guide helps you reconcile all payment types—hosted payment sessions, API-integrated payments, third-party payments, and non-third-party payments—with your internal systems by tracking webhook events and matching them to your records. This ensures complete visibility into payment status and enables accurate financial reporting.
Payment reconciliation is critical for maintaining accurate financial records and providing customers with real-time payment status updates. This guide applies to all payment integration approaches:
This guide assumes you have already integrated Redpin’s payment APIs and are receiving webhook notifications.
Learn about hosted vs API integration approaches
Complete API specification for payment sessions
Complete API specification for direct payment integration
Detailed webhook payload schemas
Comprehensive error handling patterns
Understanding the identifiers in the payment flow is essential for proper reconciliation. Each identifier serves a specific purpose in matching webhooks to your internal records.
Use client_reference_id as your primary reconciliation key when present. For third-party payments, it is required and must be unique per customer (per Redpin customer_id); duplicates for the same customer will be rejected. For non-third-party API payments, it is optional and uniqueness is not enforced.
Field availability differs by payment type:
session_id is always present; client_customer_ref and client_reference_id are presentsession_id is NOT present; client_customer_ref and client_reference_id are presentsession_id is NOT present; client_customer_ref and client_reference_id may be present if providedThe payment_id appears in the first webhook (AWAITING_FUNDS or PROCESSING) for all payment types and should be your primary tracking identifier.
When creating a payment (via hosted session or direct API), store the key identifiers that will enable reconciliation when webhooks arrive.
For hosted payment sessions, store identifiers immediately after session creation:
Store these fields when you create a payment (hosted session or API) to enable webhook matching:
For hosted sessions: Store session_id, client_customer_ref, client_reference_id, and all items immediately after session creation.
For API-integrated payments: Store client_reference_id (required for third-party, recommended for non-third-party), client_customer_ref (for third-party only), and payment details immediately after payment creation.
The payment_id will appear in the first webhook (AWAITING_FUNDS or PROCESSING) for all payment types. Use client_reference_id as your primary reconciliation key to match webhooks to your records.
The following diagram shows the complete reconciliation flow from the client system perspective. Each step shows the action your system must take to maintain accurate payment records.
The diagram above shows the FX (different-currency) flow: AWAITING_FUNDS → RECEIVED_FUNDS → FX_COMPLETED → PAYOUT_INITIATED → PAYOUT_CREDITED → PAYMENT_COMPLETED. For same-currency payments (no FX), the first webhook is PROCESSING (not AWAITING_FUNDS), then PROCESSING → PAYOUT_INITIATED → PAYOUT_CREDITED → PAYMENT_COMPLETED (or PROCESSING → CANCELLED).
The reconciliation flow consists of six main stages:
1. Session Creation
GET /v1/customers/{customer_id}/sessions?client_reference_id={ref} first to fetch an existing session and avoid duplicate creationsession_id, client_reference_id, client_customer_ref, and all items immediatelyitem_ref for granular reconciliation (invoice numbers, property IDs, booking references, etc.)session_url to complete payment2. First Webhook (AWAITING_FUNDS or PROCESSING)
payment_id for the first time, along with client_reference_id. Match to your session using client_reference_id, map payment_id to session_id, update status to AWAITING_FUNDS.payment_id, customer_id, and (when provided) client_reference_id and client_customer_ref. Map payment_id to your record and update status to PROCESSING.3. Status Updates
4. Multi-Recipient Logic
recipient_id status separately5. Completion
6. Error Handling
Process each webhook status systematically to maintain accurate payment records. All webhooks contain event_id, payment_id, status, customer_id, client_customer_ref, event_timestamp, and data.
When: Session created, waiting for customer to send funds
Webhook contains:
payment_id (first time this ID appears)client_reference_id (your unique payment reference - use this to match!)client_customer_ref (your customer identifier)data: (empty)Action:
client_reference_idpayment_id and link it to your session_idWhen: Same-currency payment accepted (no FX); sent immediately after payment creation
Webhook contains:
payment_id (first time this ID appears for same-currency payments)client_reference_id (when provided)client_customer_ref (when provided)data: (empty)Action:
client_reference_id or payment_idpayment_id to your recordWhen: Customer’s funds received in Redpin wallet
Webhook contains:
payment_iddata.amount.currency: Currency of funds receiveddata.amount.value: Amount receivedAction:
payment_id in your databaseWhen: Currency conversion completed
Webhook contains:
payment_iddata.sell_amount: Source currency and amountdata.buy_amount: Destination currency and amountdata.quote_rate: Exchange rate usedAction:
payment_idWhen: Transfer to recipient started
Webhook contains:
payment_iddata.amount: Amount being sent to recipientdata.recipient_id: Unique identifier for the recipientAction:
payment_idrecipient_id (especially important for multi-recipient payments)When: Recipient’s bank account credited
Webhook contains:
payment_iddata.amount: Amount credited to recipientdata.recipient_id: Unique identifier for the recipientAction:
payment_idrecipient_id as PAIDWhen: All recipients paid, payment fully complete
Webhook contains:
payment_iddata.recipient_details: Array of all recipients with amounts and IDsAction:
payment_idFor single-recipient payments, both PAYOUT_CREDITED and PAYMENT_COMPLETED will be delivered. For multi-recipient payments, PAYOUT_CREDITED fires once per recipient, and PAYMENT_COMPLETED fires only when all recipients have been paid.
Payments with multiple recipients require special handling to track each recipient’s status individually.
When a payment has multiple recipients:
recipient_id)recipient_id)Maintain a separate table to track individual recipient status:
Example reconciliation logic:
Track recipient_id payment status in a separate table for a complete audit trail. This enables you to show customers the status of each individual payout in multi-recipient scenarios.
Handle error states and edge cases gracefully to maintain system reliability.
When: Payment cancelled before or during processing
Webhook contains:
payment_iddata.reason_description: Reason for cancellationAction:
When: Funds refunded to customer after receipt
Webhook contains:
payment_iddata.refund_amount: Amount refundeddata.refund_reason: Reason for refundAction:
When: Payout failed and funds returned
Webhook contains:
payment_iddata.amount: Amount that bounceddata.recipient_id: Affected recipientdata.bounce_reason: Why the payout failedAction:
When: Webhook arrives but cannot match to any session
Possible causes:
client_customer_ref mismatchAction:
When: Webhooks arrive in unexpected sequence
Why it happens:
Action:
event_timestamp to determine actual event orderWhen: Same event_id received multiple times
Why it happens:
Action:
event_id before processing any webhookevent_id already exists in your webhook_events table, skip processingAlways store event_id in your webhook events table with a unique constraint to detect and skip duplicate deliveries. This prevents double-processing payments and ensures data integrity.
Webhooks use Svix for delivery. See the Webhooks overview for signature verification implementation.
Follow these best practices for reliable payment reconciliation:
Use client_reference_id as primary reconciliation key
This is your unique payment reference (max 36 chars, alphanumeric with hyphens and underscores). It ensures idempotency across session creation retries - duplicate references will be rejected with a 400 error. This makes matching internal records straightforward and prevents accidental duplicate payments.
For hosted sessions, use GET /v1/customers/{customer_id}/sessions?client_reference_id={ref} as your first recovery step when session creation is retried or the original create response is lost.
Use this decision flow immediately after calling GET /v1/customers/{customer_id}/sessions?client_reference_id={ref}:
sessions is empty, create a new session.sessions[0].has_payment is true and payment_id is present, do not create another session; continue reconciliation using payment_id and webhook events.sessions[0].latest_status is SESSION_CREATED and session_expires_at is still in the future, reuse that session.session_expires_at is in the past and has_payment is false, create a replacement session according to your idempotency/session retry policy.customer_id + client_reference_id; do not reconcile by client_reference_id alone.Store full webhook payload in audit table
Preserve the complete event history by storing the entire JSON payload. This enables debugging, forensic analysis, and compliance audits. Include event_id, payment_id, status, and the full payload field.
Implement webhook signature verification
Validate the authenticity of webhooks to prevent fraudulent requests. See the Webhooks overview for implementation details using Svix signatures.
Log unmatched webhooks for operations review
Create alerts for webhooks that do not match any session in your database. This may indicate data sync issues, timing problems, or system errors that require investigation.
Set up status-based monitoring alerts
Monitor payment progress and alert on anomalies:
SESSION_CREATED session near session_expires_at and has_payment remains falseReconcile against bank statements regularly
Match payment_id records against actual bank movements daily or weekly. Identify discrepancies early and resolve them with the Partner Integrations Team.
Maintain complete audit trail with timestamps
Log all status transitions with timestamps and track who initiated actions (system vs manual). This provides a complete audit trail for compliance and debugging.
Handle webhook processing idempotently
Use event_id to prevent duplicate processing. Ensure operations are safe to retry. Use database transactions to ensure atomic updates.
Test your reconciliation logic thoroughly in the sandbox environment before going to production.
Setup: Create session with 1 recipient
Expected webhooks:
Validation:
payment_id mapped to session_id on first webhookSetup: Create session with 3 recipients
Expected webhooks:
Validation:
recipient_id tracked separatelySetup: Create session but cancel before completion
Expected webhooks:
Validation:
Setup: Manually send webhook with unknown payment_id
Expected behavior:
Validation:
Setup: Process same webhook twice (same event_id)
Expected behavior:
Validation:
event_id deduplication worksIn sandbox, webhooks are delivered instantly for testing. In production, expect slight delays based on payment processing time (typically seconds to minutes for each stage).
Common reconciliation issues and their solutions.
Symptoms: Expected webhook never arrives
Likely causes:
Solutions:
Symptoms: AWAITING_FUNDS webhook arrives but cannot find matching session
Likely causes:
client_reference_id mismatch between session and webhookSolutions:
client_reference_id from webhook and compare to database recordsGET /v1/customers/{customer_id}/sessions?client_reference_id={ref} to retrieve the matching session record and recover session_idclient_reference_id format consistency (trimming, case sensitivity)Symptoms: Status has not updated in 24+ hours
Likely causes:
Solutions:
payment_id and session_idSymptoms: Received PAYOUT_CREDITED for all recipients but PAYMENT_COMPLETED never arrives
Likely causes:
Solutions:
Symptoms: Same status processed multiple times, duplicate database entries
Likely causes:
event_id for idempotencySolutions:
event_id deduplication check before processingevent_id in webhook_events tableIf payment stuck for more than 24 hours, contact the Partner Integrations Team immediately at apisupport@redpincompany.com with your payment_id and session_id. Include recent webhook history and customer status in your report.
Now that you understand reconciliation, explore these related resources:
Complete API specification for sessions
Detailed webhook payload schemas
Hosted vs API integration approaches
Comprehensive error handling patterns
For integration support or questions about reconciliation, contact the Partner Integrations Team at apisupport@redpincompany.com.