Authentication All requests require a Bearer token in the Authorization header. Generate API keys in the Command Center.
Authorization: Bearer rsend_live_sk_abc123...Your merchant_idis derived from your API key — you don't need to pass it separately.
Create Payment Intent POST /api/v1/merchant/payment-intent
Request POST /api/v1/merchant/payment-intent Copy{
"amount": "250.00",
"currency": "USDC",
"recipient": "0x742d35Cc6634C0532925a3b844Bc9e7595f2bD18",
"expires_in": 1800,
"metadata": {
"order_id": "ord_9f3k2",
"customer_email": "buyer@example.com"
}
}Response 201 Created {
"intent_id": "pi_7xk29m",
"status": "pending",
"amount": "250.00",
"currency": "USDC",
"recipient": "0x742d35Cc6634C0532925a3b844Bc9e7595f2bD18",
"expires_at": "2025-04-15T12:30:00Z",
"created_at": "2025-04-15T12:00:00Z"
}Errors 400 — Invalid amount, unsupported currency, or missing fields.401 — Invalid or missing API key.429 — Rate limit exceeded (100 requests/min).Get Intent Status GET /api/v1/merchant/payment-intent/{id}
Response 200 OK {
"intent_id": "pi_7xk29m",
"status": "completed",
"amount": "250.00",
"currency": "USDC",
"tx_hash": "0x1a2b3c4d5e6f...",
"completed_at": "2025-04-15T12:05:32Z",
"metadata": {
"order_id": "ord_9f3k2",
"customer_email": "buyer@example.com"
}
}Errors Register Webhook POST /api/v1/merchant/webhook/register
Request POST /api/v1/merchant/webhook/register Copy{
"url": "https://yourapp.com/webhooks/rsend",
"events": ["payment.completed", "payment.expired", "payment.cancelled"],
"secret": "whsec_your_secret_here"
}Response 201 Created {
"webhook_id": "wh_m3x92p",
"url": "https://yourapp.com/webhooks/rsend",
"events": ["payment.completed", "payment.expired", "payment.cancelled"],
"status": "active"
}Errors 400 — Invalid URL or unsupported event type.409 — Webhook URL already registered.Test Webhook Delivery POST /api/v1/merchant/webhook/test
Sends a test payment.completed event to your registered webhook URL. Use this to verify your endpoint works before going live.
Request POST /api/v1/merchant/webhook/test Copy{
"webhook_id": "wh_m3x92p"
}Response 200 OK {
"delivered": true,
"status_code": 200,
"response_time_ms": 142
}Errors 404 — Webhook ID not found.502 — Your endpoint returned an error or timed out.List Transactions GET /api/v1/merchant/transactions
Returns a paginated list of transactions. Supports filters via query params.
Query Parameters page — Page number (default: 1).limit — Items per page (default: 20, max: 100).status — Filter by status: completed, pending, expired, cancelled.from / to — Date range (ISO 8601).Response 200 OK {
"data": [
{
"tx_id": "tx_a1b2c3",
"intent_id": "pi_7xk29m",
"amount": "250.00",
"currency": "USDC",
"status": "completed",
"tx_hash": "0x1a2b3c4d5e6f...",
"created_at": "2025-04-15T12:00:00Z"
}
],
"pagination": {
"page": 1,
"limit": 20,
"total": 1,
"has_more": false
}
}Webhook Events RSends emits three webhook events:
payment.completed — Payment confirmed and forwarded.payment.expired — Intent expired without payment.payment.cancelled — Intent cancelled by merchant.Payload Format {
"event": "payment.completed",
"intent_id": "pi_7xk29m",
"amount": "250.00",
"currency": "USDC",
"tx_hash": "0x1a2b3c4d5e6f...",
"timestamp": "2025-04-15T12:05:32Z",
"metadata": {
"order_id": "ord_9f3k2"
}
}The X-RSends-Signature header contains the HMAC-SHA256 signature of the raw request body, signed with your webhook secret.
HMAC Verification Always verify the X-RSends-Signatureheader before processing a webhook event. Here's how:
Node.js const crypto = require("crypto");
function verifyWebhook(body, signature, secret) {
const expected = crypto
.createHmac("sha256", secret)
.update(body, "utf8")
.digest("hex");
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expected)
);
}
// Usage in Express
app.post("/webhooks/rsend", (req, res) => {
const signature = req.headers["x-rsend-signature"];
const isValid = verifyWebhook(req.rawBody, signature, WEBHOOK_SECRET);
if (!isValid) {
return res.status(401).json({ error: "Invalid signature" });
}
const event = JSON.parse(req.rawBody);
// Process event...
res.status(200).json({ received: true });
});Python import hmac
import hashlib
def verify_webhook(body: bytes, signature: str, secret: str) -> bool:
expected = hmac.new(
secret.encode("utf-8"),
body,
hashlib.sha256
).hexdigest()
return hmac.compare_digest(signature, expected)
# Usage in Flask
@app.route("/webhooks/rsend", methods=["POST"])
def handle_webhook():
signature = request.headers.get("X-RSends-Signature", "")
is_valid = verify_webhook(request.data, signature, WEBHOOK_SECRET)
if not is_valid:
return {"error": "Invalid signature"}, 401
event = request.get_json()
# Process event...
return {"received": True}, 200Always Verify
Never process webhook events without verifying the HMAC signature. An attacker could send fake events to your endpoint to trigger false payment confirmations.