Skip to content

Guide

Test mode

Build and test your integration with a test key. Test mode behaves like the real API, but no real money, chain or payment provider is involved.

Keys

Create a key under API & apps in the dashboard with Mode set to Test. Its secret starts with rvk_test_; live secrets start with rvk_. A test key can never be used as a live key and the other way round, and the SDKs tell the mode from the prefix (isTestKey and ravelo.livemode in TypeScript, is_test_key and livemode in Python). Objects created with a test key carry "livemode": false.

How test and live stay apart

The first test key creates one sandbox account linked to your merchant account. A test key acts on that account, so everything it creates is its own: balances, payment intents, payouts, deposit addresses and the address book. Lists under a test key show only test objects and lists under a live key show only live ones, because they are different accounts. Test traffic never reaches the payment provider and is kept out of live fee and reconciliation figures.

Payments

POST /v1/payment-intents with a test key returns an intent with a synthetic deposit address. Fund it with POST /v1/sandbox/payment-intents/{id}/simulate-funding. The simulator sends a signed callback through the same intake, verification, crediting and risk checks as a real deposit, so the intent moves on its own a moment later. A live key gets 403 test_mode_only.

SendTo testResult
{}A customer who pays exactly what is dueThe intent becomes succeeded.
{ "amount": "10000000" }A short payment (or a larger one, for an overpayment)The intent becomes partially_funded, or succeeded with the excess held for the payer; return it with POST /v1/overpayment-returns as in live mode.
{ "asset_id": "usdc-ethereum" }A customer who sends the wrong coinThe funds are credited but never counted and the intent stays unpaid.

Both fields are optional. The amount defaults to what is still due, which includes our fee, and the asset to the intent's own.

A test deposit a risk rule would hold is held and then cleared on its own, since nobody reviews test money: the payment's disposition goes to hold and back to none, and the funds become available. In live mode the same deposit waits for our compliance team.

curl

# Pay less than is due; leave the body as {} to pay exactly what is due.
curl -sS "$RAVELO_API/v1/sandbox/payment-intents/$INTENT_ID/simulate-funding" \
  -H "Authorization: Bearer $RAVELO_TEST_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{ "amount": "10000000" }'

TypeScript

import { Ravelo } from "@ravelo/sdk";

const ravelo = new Ravelo({ apiKey: process.env.RAVELO_TEST_KEY!, baseUrl: process.env.RAVELO_API! });
const create = (order_ref: string) => ravelo.paymentIntents.create({ order_ref, asset_id: "usdt-tron", amount: "25000000" });

await ravelo.sandbox.simulateFunding((await create("full")).id); // pays what is due
await ravelo.sandbox.simulateFunding((await create("short")).id, { amount: "10000000" }); // underpays
await ravelo.sandbox.simulateFunding((await create("wrong-asset")).id, { asset_id: "usdc-ethereum" }); // wrong coin: held in a case, the intent stays unpaid

Python

import os

from ravelo import Ravelo

ravelo = Ravelo(os.environ["RAVELO_TEST_KEY"], os.environ["RAVELO_API"])


def create(order_ref):
    return ravelo.payment_intents.create(order_ref=order_ref, asset_id="usdt-tron", amount="25000000")


ravelo.sandbox.simulate_funding(create("full")["id"])  # pays what is due
ravelo.sandbox.simulate_funding(create("short")["id"], amount="10000000")  # underpays
ravelo.sandbox.simulate_funding(create("wrong-asset")["id"], asset_id="usdc-ethereum")  # wrong coin: held in a case, the intent stays unpaid

Payouts and refunds

Save a destination with POST /v1/sandbox/address-book (label, network, address): it is usable at once, with no step-up code and no 24-hour cooling-off. Then prepare a payout as usual. A test payout is approved immediately and settled by the worker with a simulated result and transaction hash. The real payment client refuses anything not bound to the sandbox, so a test payout cannot be sent for real even by mistake.

Webhooks

Register an endpoint with your test key (POST /v1/webhook-endpoints) and it receives the events of test payments, signed with its own secret and retried like live ones. Follow the quickstart for the full flow, and webhooks for verification.

What is different

  • The dashboard shows live data only. Read test objects through the API.
  • A deployment without test mode answers 503 test_mode_unavailable to creating a test key and to using one.
  • Rate limits, idempotency, pagination and error codes behave exactly as they do for live keys.

Going live

  • Create a live key with the scopes your server needs and nothing more.
  • Register a live webhook endpoint and keep its secret apart from the sandbox one.
  • Swap the key, the webhook secret and nothing else; the paths, fields and codes are the same.
  • Read errors, idempotency and rate limits once more with live traffic in mind.

No key approves money out

Payouts and refunds you prepare with a live key wait in Approvals until a team member confirms them with a passkey or authenticator code, whichever SDK or call prepared them.