Skip to content

Ripple Collections (0.1.0)

The Ripple Collection APIs are used to manage collections, manage payment channels, manage partners and settlements.

API environments

The Ripple Collection APIs offers the following environments:

Environment
Base URLDescription
Sandboxhttps://docs.ripple.com/products/collections/_mock/api/collectionsSandbox environment with mock data which does not require auth.
UAThttps://api.test.ripple.comUAT environment with simulated transactions.
Productionhttps://api.ripple.comProduction environment

API authentication

All API operations in UAT and Production require a Bearer access token specific to the environment you're using. Ripple provides a secure model for authentication and authorization by providing access tokens scoped for a set of credentials.

Generate client ID and client secret

You will need your client ID and client secret to obtain an access token. If you do not already have your client ID and client secret, do the following:

  1. Log into the Ripple Collections UI. 2. In the left navigation menu, click Settings. 3. Under Administration, click API Credentials. 4. In the dropdown list next to the page title, select the access environment. For example, to provision credentials for the test environment, select Test from the dropdown list. 5. In the upper right corner of the page, click New Credential. 6. Click Save and Generate Key. Caution: The client secret is displayed only once when you are creating new credentials. You cannot retrieve the secret after exiting this page. Copy and store the client secret securely and share it with authorized individuals in accordance with your organization's security policy. You can now use the client ID and client secret to generate access tokens using the Request an access token operation.

Request an access token

To get an access token, use the Request an access token operation with your client_id and client_secret. The response contains a token in the access_token field. We recommend rotating your API credentials at regular intervals according to your organization's security policy. Note: Authentication tokens are not a fixed length and can vary, avoid validating tokens based on character length.

Idempotency

When a client supplies a unique key (X-Idempotency-Key, UUID). The header is optional: if it is omitted the request is processed normally (no deduplication, no replay). Supplying the header is strongly recommended for POST operations that create side effects. Provide optional X-Idempotency-Key on POST writes for safe retries:

  • Success → cached and replayable.
  • In-flight duplicate → 409 (retry later).
  • Mismatch → 422.
  • Failure → entry removed (safe retry).
  • Only successes are replayed.

With vs Without the Header

With X-Idempotency-Key:

  • First request claims and (if successful) caches response.
  • Concurrent duplicates while in flight receive 409 + Retry-After: 1.
  • Later identical retries get the cached 2xx response.
  • Different payload/path/method using same key → 422 mismatch.

Without the header:

  • Filter bypasses idempotency entirely.
  • Each call executes independently; duplicates may create repeated side effects.

Verifying Webhooks

When receiving webhooks, the signing operation has already been performed by the platform and you must validate the signature we provide to ensure the webhook originated from us. When creating a subscription (using the subscription API), you are provided a signature_verification_key. This value is a base64‑encoded symmetric secret used to compute an HMAC-SHA256 signature for each webhook payload. You must persist this secret securely at subscription creation time.

NOTE: The returned signature_verification_key is base64-encoded binary. In the code sample below we base64‑decode it to raw bytes (you do NOT re‑encode it). You may display it in hex for debugging, but hex is not required for verification. When a webhook is dispatched:

  • We include X-Webhook-Timestamp (epoch milliseconds).
  • We include X-Webhook-Signature in the form: t=<timestamp>,v1=<hex_hmac_sha256>.
  • You reconstruct the exact signing string and verify.

Verification is a 2 step process:

Step
ActionDescription
1ReconstructConcatenate the timestamp, a dot (.), and the SHA256 hex digest of the raw request body: <timestamp>.<sha256(body)>
2VerifyHMAC-SHA256 the signing string with the decoded secret; compare the resulting hex digest to v1 (constant-time).

Fields Used in the Signature

Field
Description
TimestampRaw value from X-Webhook-Timestamp (epoch millis as a string).
BodyThe exact raw HTTP request body bytes (no parsing / reformatting).
body_hashSHA256 hex digest of the raw body.
signing_string<timestamp>.<body_hash>
SecretBase64-decoded signature_verification_key.
SignatureHex digest of HMAC_SHA256(secret, signing_string) placed in v1.

If any of these values are transformed (e.g. JSON pretty-printed, numeric formatting changed, timestamp altered) the verification will fail.

Verification Example


def verify_webhook(raw_body: bytes, timestamp: str, signature_header: str, base64_secret: str, max_age_seconds: int = 300) -> bool:
"""
Verify an incoming webhook.

Parameters:
raw_body:        Exact raw request body bytes (no mutation).
timestamp:       X-Webhook-Timestamp header (epoch millis as string).
signature_header:X-Webhook-Signature header in form "t=<timestamp>,v1=<hex>".
base64_secret:   subscription signature_verification_key (base64).
max_age_seconds: Allowed clock skew / replay window (0 disables freshness check).

Returns: True if signature is valid, else False.

"""
if not (raw_body and timestamp and signature_header and base64_secret): return False

# Parse signature header
parts = {}
try:
for seg in signature_header.split(","):
k, v = seg.split("=", 1)
parts[k.strip()] = v.strip()
except Exception:
return False

if parts.get("t") != timestamp or "v1" not in parts:
return False

# Freshness (optional)
if max_age_seconds > 0 and timestamp.isdigit():
try:
ts_int = int(timestamp)
# Detect millis
if ts_int > 1_000_000_000_000:
ts_int //= 1000
if abs(int(time.time()) - ts_int) > max_age_seconds:
return False
except ValueError:
return False

# SHA256 hex of body
body_hash = hashlib.sha256(raw_body).hexdigest()
signing_string = f"{timestamp}.{body_hash}".encode("utf-8")

# Decode secret (single base64 decode only)
try:
secret = base64.b64decode(base64_secret, validate=True)
except Exception:
return False

expected = hmac.new(secret, signing_string, hashlib.sha256).hexdigest()
provided = parts["v1"]
# Constant-time compare
return hmac.compare_digest(expected, provided)

Flask Usage Example

from flask import Flask, request, Response
import os

from verifier import verify_webhook  # assuming the function above saved as verifier.py
app = Flask(__name__)
SECRET = os.environ.get("WEBHOOK_SECRET_VERIFICATION_KEY")  # set from secure config


@app.post("/webhook")
def webhook():
raw_body = request.get_data()  # exact bytes
ts = request.headers.get("X-Webhook-Timestamp", "")
sig = request.headers.get("X-Webhook-Signature", "")
if not verify_webhook(raw_body, ts, sig, SECRET, max_age_seconds=300):
return Response("invalid signature", status=400)
# Safe to parse AFTER verification
return Response("ok", status=200)

Key Points

  • Always read raw bytes first; only parse JSON after verification.
  • Do not pretty-print or modify the JSON before hashing.
  • Reject if age window exceeded or headers malformed.
  • Use hmac.compare_digest for constant-time comparison.

Common Pitfalls

IssueCauseResolution
signature_mismatchSecret double-base64 encodedUse original subscription value directly
signature_mismatchBody re-serialized / pretty-printedHash exact raw bytes
signature_mismatchTimestamp mismatch between t and headerEnsure they match verbatim
Stale timestampClock skew or delayed processingCheck system clock; adjust max age
Invalid header formatMissing t= or v1= segmentEnsure exact format t=...,v1=...

Checklist

  • Captured raw body (not parsed then re-stringified)
  • Extracted X-Webhook-Timestamp
  • Parsed X-Webhook-Signature → t & v1
  • Computed SHA256 hex of raw body
  • Built signing string <timestamp>.<body_hash>
  • Base64-decoded stored secret
  • HMAC-SHA256 computed & constant-time compared
  • (Optional) Freshness window passed

If every box is checked and comparison succeeds, the webhook is authentic.

Download OpenAPI description
Languages
Servers
Mock server

https://docs.ripple.com/_mock/products/collections/api/collections/

https://api.test.ripple.com/

https://api.ripple.com/

Authentication

Endpoints for authentication

Operations

List collections

Request

Retrieves a list of collections, filterable by query parameters.

Security
Bearer
Query
idstring(uuid)

Filter collections by specific collection identifier

Example: id=e8d43598-107d-4694-9fb2-934e7484c3d4
payer_idstring(uuid)

Filter collections by payer identifier

Example: payer_id=0c5479ff-3772-4123-b2b7-e679e71eb570
beneficiary_idstring(uuid)

Filter collections by beneficiary identifier

Example: beneficiary_id=01467076-8bb0-41c1-ad54-5751dd4a9e80
sincestring(date-time)

ISO 8601 timestamp after collection was created

Example: since=2025-06-17T12:00:00Z
untilstring(date-time)

ISO 8601 timestamp before collection was created

Example: until=2025-06-17T12:00:00Z
pageinteger>= 1

Page number (starts at 1)

Default 1
Example: page=1
sizeinteger>= 1

Page size (items per page)

Default 10
Example: size=10
curl -i -X GET \
  'https://docs.ripple.com/_mock/products/collections/api/collections/v0/collections/links?id=e8d43598-107d-4694-9fb2-934e7484c3d4&payer_id=0c5479ff-3772-4123-b2b7-e679e71eb570&beneficiary_id=01467076-8bb0-41c1-ad54-5751dd4a9e80&since=2025-06-17T12%3A00%3A00Z&until=2025-06-17T12%3A00%3A00Z&page=1&size=10' \
  -H 'Authorization: Bearer <YOUR_JWT_HERE>'

Responses

A list of collections.

Bodyapplication/json
contentArray of objects(Collection)
pageobject(PageMetadata)

Pagination metadata.

Response
application/json
{ "content": [ {} ], "page": { "page": 1, "size": 10, "total_elements": 100, "total_pages": 10 } }

Create a collection

Request

Creates a new payment link for a collection.

Security
Bearer
Bodyapplication/jsonrequired
payer_idstring(uuid)required

Unique identifier of the payer partner

Example: "0c5479ff-3772-4123-b2b7-e679e71eb570"
beneficiary_idstring(uuid)required

Unique identifier of the beneficiary partner

Example: "01467076-8bb0-41c1-ad54-5751dd4a9e80"
amountstring^[0-9]+(\.[0-9]{1,8})?$required

Collection amount as a string to preserve precision

Example: "800.00"
currencystringrequired

Currency or asset symbol

Example: "USD"
fee_modestring
Default "EXCLUDED"
Enum"INCLUDED""EXCLUDED"
Example: "EXCLUDED"
reference_idstring

External reference identifier for the collection

Example: "INV-2025-009"
descriptionstring

Human-readable description of the collection purpose

Example: "Payment for Order #2668"
link_expiryinteger[ 300 .. 2592000 ]required

Payment link expiry time in seconds from creation

Example: 172800
return_urlstring(uri)required

URL to redirect user after payment completion

Example: "https://example.com/payment/completion"
curl -i -X POST \
  https://docs.ripple.com/_mock/products/collections/api/collections/v0/collections/links \
  -H 'Authorization: Bearer <YOUR_JWT_HERE>' \
  -H 'Content-Type: application/json' \
  -d '{
    "payer_id": "0c5479ff-3772-4123-b2b7-e679e71eb570",
    "beneficiary_id": "01467076-8bb0-41c1-ad54-5751dd4a9e80",
    "amount": "800.00",
    "currency": "USD",
    "fee_mode": "EXCLUDED",
    "reference_id": "INV-2025-009",
    "description": "Payment for Order #2668",
    "link_expiry": 172800,
    "return_url": "https://example.com/payment/completion"
  }'

Responses

Collection Created Successfully

Bodyapplication/json
idstring(uuid)required

Unique identifier for the collection

Example: "e8d43598-107d-4694-9fb2-934e7484c3d4"
payerobjectrequired

Payer partner details

payer.​idstring(uuid)required

Unique identifier for the payer partner

Example: "0c5479ff-3772-4123-b2b7-e679e71eb570"
payer.​namestringrequired

Full name of the payer partner

Example: "Nigerian Imports Ltd."
payer.​emailstring(email)required

Email address of the payer partner

Example: "nigerian@imports.com"
reference_idstring

External reference identifier for the collection

Example: "INV-2025-009"
beneficiaryobjectrequired

Beneficiary partner details

beneficiary.​idstring(uuid)required

Unique identifier of the beneficiary partner

Example: "01467076-8bb0-41c1-ad54-5751dd4a9e80"
beneficiary.​namestringrequired

Full name of the beneficiary partner

Example: "Hong Kong Exports Ltd."
beneficiary.​emailstring(email)required

Email address of the beneficiary partner

Example: "hongkong@exports.com"
gross_amountstringrequired

Total amount including fees

Example: "808.00"
net_amountstringrequired

Amount excluding buyer fees

Example: "800.00"
currencystringrequired

Currency or asset symbol

Example: "USD"
fee_modestring(FeeMode)required

How fees are handled in the collection

Enum"INCLUDED""EXCLUDED"
Example: "EXCLUDED"
feestringrequired

Fee amount charged for the collection

Example: "8.00"
amount_remainingstringrequired

Amount remaining for an incomplete payment

Example: "758.50"
descriptionstringrequired

Human-readable description of the collection purpose

Example: "Payment for Order #2668"
link_expiryintegerrequired

Payment link expiry time in seconds from creation

Example: 172800
return_urlstring(uri)required
Example: "https://example.com/payment/completion"
expires_atstring(date-time)required

ISO 8601 timestamp when the collection expires

Example: "2025-06-30T23:59:59Z"
transactionsArray of objects(Transaction)

List of blockchain transactions associated with this collection

payment_linkstring(uri)

URL for the payment interface

Example: "https://collections.ripple.com/link/pay/384c5f9b"
statusstring(CollectionStatus)required

The status of the collection

Enum"CREATED""CLOSED""HOLD""EXPIRED""PENDING""PROCESSING""COMPLETED""UNDERPAID""OVERPAID""CANCELLED"
Example: "PENDING"
reasonstring or null

Reason for current status (if applicable)

Example: null
created_atstring(date-time)required

ISO 8601 timestamp when the collection was created

Example: "2025-06-17T12:00:00Z"
updated_atstring(date-time)required

ISO 8601 timestamp when the collection was last updated

Example: "2025-06-17T12:30:00Z"
Response
application/json
{ "id": "e8d43598-107d-4694-9fb2-934e7484c3d4", "payer": { "id": "0c5479ff-3772-4123-b2b7-e679e71eb570", "name": "Nigerian Imports Ltd.", "email": "nigerian@imports.com" }, "reference_id": "INV-2025-009", "beneficiary": { "id": "01467076-8bb0-41c1-ad54-5751dd4a9e80", "name": "Hong Kong Exports Ltd.", "email": "hongkong@exports.com" }, "gross_amount": "808.00", "net_amount": "800.00", "currency": "USD", "fee_mode": "EXCLUDED", "fee": "8.00", "amount_remaining": "808.00", "description": "Payment for Order #2668", "link_expiry": 172800, "return_url": "https://example.com/payment/completion", "expires_at": "2025-06-30T23:59:59Z", "transactions": [], "payment_link": "https://collections.ripple.com/link/pay/384c5f9b", "status": "CREATED", "reason": null, "created_at": "2025-06-17T12:00:00Z", "updated_at": "2025-06-17T12:30:00Z" }

Get collection details

Request

Retrieves the details of a specific collection by its ID.

Security
Bearer
Path
collection_idstring(uuid)required

Unique identifier of the collection to retrieve

Example: 22a0337b-8e62-449c-91ca-a0f830c55733
curl -i -X GET \
  https://docs.ripple.com/_mock/products/collections/api/collections/v0/collections/links/22a0337b-8e62-449c-91ca-a0f830c55733 \
  -H 'Authorization: Bearer <YOUR_JWT_HERE>'

Responses

Successful response

Bodyapplication/json
idstring(uuid)required

Unique identifier for the collection

Example: "e8d43598-107d-4694-9fb2-934e7484c3d4"
payerobjectrequired

Payer partner details

payer.​idstring(uuid)required

Unique identifier for the payer partner

Example: "0c5479ff-3772-4123-b2b7-e679e71eb570"
payer.​namestringrequired

Full name of the payer partner

Example: "Nigerian Imports Ltd."
payer.​emailstring(email)required

Email address of the payer partner

Example: "nigerian@imports.com"
reference_idstring

External reference identifier for the collection

Example: "INV-2025-009"
beneficiaryobjectrequired

Beneficiary partner details

beneficiary.​idstring(uuid)required

Unique identifier of the beneficiary partner

Example: "01467076-8bb0-41c1-ad54-5751dd4a9e80"
beneficiary.​namestringrequired

Full name of the beneficiary partner

Example: "Hong Kong Exports Ltd."
beneficiary.​emailstring(email)required

Email address of the beneficiary partner

Example: "hongkong@exports.com"
gross_amountstringrequired

Total amount including fees

Example: "808.00"
net_amountstringrequired

Amount excluding buyer fees

Example: "800.00"
currencystringrequired

Currency or asset symbol

Example: "USD"
fee_modestring(FeeMode)required

How fees are handled in the collection

Enum"INCLUDED""EXCLUDED"
Example: "EXCLUDED"
feestringrequired

Fee amount charged for the collection

Example: "8.00"
amount_remainingstringrequired

Amount remaining for an incomplete payment

Example: "758.50"
descriptionstringrequired

Human-readable description of the collection purpose

Example: "Payment for Order #2668"
link_expiryintegerrequired

Payment link expiry time in seconds from creation

Example: 172800
return_urlstring(uri)required
Example: "https://example.com/payment/completion"
expires_atstring(date-time)required

ISO 8601 timestamp when the collection expires

Example: "2025-06-30T23:59:59Z"
transactionsArray of objects(Transaction)

List of blockchain transactions associated with this collection

payment_linkstring(uri)

URL for the payment interface

Example: "https://collections.ripple.com/link/pay/384c5f9b"
statusstring(CollectionStatus)required

The status of the collection

Enum"CREATED""CLOSED""HOLD""EXPIRED""PENDING""PROCESSING""COMPLETED""UNDERPAID""OVERPAID""CANCELLED"
Example: "PENDING"
reasonstring or null

Reason for current status (if applicable)

Example: null
created_atstring(date-time)required

ISO 8601 timestamp when the collection was created

Example: "2025-06-17T12:00:00Z"
updated_atstring(date-time)required

ISO 8601 timestamp when the collection was last updated

Example: "2025-06-17T12:30:00Z"
Response
application/json
{ "id": "22a0337b-8e62-449c-91ca-a0f830c55733", "payer": { "id": "0c5479ff-3772-4123-b2b7-e679e71eb570", "name": "Nigerian Imports Ltd.", "email": "nigerian@imports.com" }, "reference_id": "INV-2025-009", "beneficiary": { "id": "01467076-8bb0-41c1-ad54-5751dd4a9e80", "name": "Hong Kong Exports Ltd.", "email": "hongkong@exports.com" }, "gross_amount": "800.00", "net_amount": "792.00", "currency": "USD", "fee_mode": "INCLUDED", "fee": "8.00", "amount_remaining": "750.50", "description": "Payment for Order #2670", "link_expiry": 172800, "return_url": "https://example.com/payment/completion", "expires_at": "2025-06-30T23:59:59Z", "transactions": [ {} ], "payment_link": "https://collections.ripple.com/link/pay/384c5f9b", "status": "CREATED", "reason": null, "created_at": "2025-06-17T12:00:00Z", "updated_at": "2025-06-17T12:30:00Z" }

Cancel a collection

Request

API to cancel a payment collection.

Security
Bearer
Bodyapplication/jsonrequired
idstring(uuid)required

Unique identifier of the collection to cancel

Example: "92e001a4-311a-4a63-ab2a-f050207c5283"
reasonstring

Optional reason for cancelling the collection

Example: "Collection cancelled"
curl -i -X POST \
  https://docs.ripple.com/_mock/products/collections/api/collections/v0/collections/links/cancel \
  -H 'Authorization: Bearer <YOUR_JWT_HERE>' \
  -H 'Content-Type: application/json' \
  -d '{
    "id": "92e001a4-311a-4a63-ab2a-f050207c5283",
    "reason": "Collection cancelled"
  }'

Responses

Collection cancelled successfully.

Bodyapplication/json
idstring(uuid)required

Unique identifier for the collection

Example: "e8d43598-107d-4694-9fb2-934e7484c3d4"
payerobjectrequired

Payer partner details

payer.​idstring(uuid)required

Unique identifier for the payer partner

Example: "0c5479ff-3772-4123-b2b7-e679e71eb570"
payer.​namestringrequired

Full name of the payer partner

Example: "Nigerian Imports Ltd."
payer.​emailstring(email)required

Email address of the payer partner

Example: "nigerian@imports.com"
reference_idstring

External reference identifier for the collection

Example: "INV-2025-009"
beneficiaryobjectrequired

Beneficiary partner details

beneficiary.​idstring(uuid)required

Unique identifier of the beneficiary partner

Example: "01467076-8bb0-41c1-ad54-5751dd4a9e80"
beneficiary.​namestringrequired

Full name of the beneficiary partner

Example: "Hong Kong Exports Ltd."
beneficiary.​emailstring(email)required

Email address of the beneficiary partner

Example: "hongkong@exports.com"
gross_amountstringrequired

Total amount including fees

Example: "808.00"
net_amountstringrequired

Amount excluding buyer fees

Example: "800.00"
currencystringrequired

Currency or asset symbol

Example: "USD"
fee_modestring(FeeMode)required

How fees are handled in the collection

Enum"INCLUDED""EXCLUDED"
Example: "EXCLUDED"
feestringrequired

Fee amount charged for the collection

Example: "8.00"
amount_remainingstringrequired

Amount remaining for an incomplete payment

Example: "758.50"
descriptionstringrequired

Human-readable description of the collection purpose

Example: "Payment for Order #2668"
link_expiryintegerrequired

Payment link expiry time in seconds from creation

Example: 172800
return_urlstring(uri)required
Example: "https://example.com/payment/completion"
expires_atstring(date-time)required

ISO 8601 timestamp when the collection expires

Example: "2025-06-30T23:59:59Z"
transactionsArray of objects(Transaction)

List of blockchain transactions associated with this collection

payment_linkstring(uri)

URL for the payment interface

Example: "https://collections.ripple.com/link/pay/384c5f9b"
statusstring(CollectionStatus)required

The status of the collection

Enum"CREATED""CLOSED""HOLD""EXPIRED""PENDING""PROCESSING""COMPLETED""UNDERPAID""OVERPAID""CANCELLED"
Example: "PENDING"
reasonstring or null

Reason for current status (if applicable)

Example: null
created_atstring(date-time)required

ISO 8601 timestamp when the collection was created

Example: "2025-06-17T12:00:00Z"
updated_atstring(date-time)required

ISO 8601 timestamp when the collection was last updated

Example: "2025-06-17T12:30:00Z"
Response
application/json
{ "id": "92e001a4-311a-4a63-ab2a-f050207c5283", "payer": { "id": "0c5479ff-3772-4123-b2b7-e679e71eb570", "name": "Nigerian Imports Ltd.", "email": "nigerian@imports.com" }, "reference_id": "INV-2025-009", "beneficiary": { "id": "01467076-8bb0-41c1-ad54-5751dd4a9e80", "name": "Hong Kong Exports Ltd.", "email": "hongkong@exports.com" }, "gross_amount": "800.00", "net_amount": "792.00", "currency": "USD", "fee_mode": "INCLUDED", "fee": "8.00", "amount_remaining": "800.00", "description": "Payment for Order #2669", "link_expiry": 172800, "return_url": "https://example.com/payment/completion", "expires_at": "2025-06-30T23:59:59Z", "transactions": [], "payment_link": "https://collections.ripple.com/link/pay/124c5f9b", "status": "CANCELLED", "reason": "Collection cancelled", "created_at": "2025-06-17T12:00:00Z", "updated_at": "2025-06-17T12:30:00Z" }

Collection Channels

Endpoints for managing persistent collection channels

Operations

Partners

Endpoints for managing partners who can transact

Operations

Settlements

Endpoints for managing settlements

Operations

Transactions

Endpoints for viewing transactions across collection links and channels

Operations

Webhooks

Endpoints for managing webhook registrations

Operations