Skip to content

Payments

Payments are initiated against active mandates and progress through submission, collection, and settlement states. This guide outlines the lifecycle, constraints, and best practices for integrating with the VRP Billing payments API.

Creating a Payment

POST /payments

Required Fields

Field Type Description
mandate_id string Identifier of the mandate authorising the collection.
amount string (decimal) Amount to collect, formatted with two decimal places.
currency string Must match the mandate currency.

Optional Fields

  • description: Displayed on customer statements where supported.
  • metadata: JSON object for internal tracking (20 key limit).
  • capture_at: ISO 8601 timestamp requesting a delayed submission (max 7 days ahead).

Validation Rules

  • Amount cannot exceed mandate limit or fall below 1.00.
  • Payments scheduled via capture_at must be at least 10 minutes in the future.
  • metadata keys must be unique per request.

Example

{
  "mandate_id": "mandate_f9d3",
  "amount": "42.50",
  "currency": "GBP",
  "description": "April membership",
  "metadata": {
    "invoice_number": "INV-10045"
  }
}

Payment Lifecycle

Status Description
pending_submission Payment accepted but waiting for capture window.
submitted Sent to the customer's bank for processing.
settled Funds have cleared and will appear in the merchant payout.
failed Bank declined the request. Inspect failure_code.
cancelled Merchant cancelled before submission or mandate was revoked.
refunded Payment has an associated refund totalling the original amount.

Failure Codes

Code Meaning Recovery
insufficient_funds Customer account balance was too low. Retry using POST /payments/{id}/retry.
mandate_revoked Mandate was cancelled prior to collection. Notify customer to re-authorise.
bank_offline Bank could not process at the time. Automatic retry occurs within 30 minutes.
limit_exceeded Amount breached bank- or mandate-level limits. Reduce amount and retry within limit.

Retrying Payments

POST /payments/{payment_id}/retry

  • Retries are permitted for failed payments only.
  • Retries inherit the original amount and metadata.
  • A payment can be retried up to three times with a minimum interval of one hour.

Listing Payments

GET /payments?mandate_id=mandate_f9d3&page_size=50

Use the cursor parameter for pagination. Sort order defaults to reverse chronological by created_at and can be changed with the order parameter described in Pagination. Responses return results, next_cursor, previous_cursor, and page_size.

Payment Notifications

Subscribe to these webhooks to track status changes:

  • payment.submitted
  • payment.settled
  • payment.failed
  • payment.refunded

Webhook payloads include mandate_id, amount, and failure_code when applicable.

Reporting

GET /payments/summary?from=2024-01-01&to=2024-01-31

The summary endpoint aggregates payments by status and currency. It is subject to rate limits documented in Rate Limits.

Reconciliation Tips

  • Use the metadata.invoice_number field to map payments to internal invoices.
  • Store the settlement_date returned on GET /payments/{id} to align with payouts.
  • When reconciling refunds, combine payment and refund CSV exports to track net amounts.