RapidCents
Embedded checkout
Payment UI runs inside an iframe on your site. The supported browser integration uses RapidCents checkout.js (RapidCentsCheckout) to call checkout/create with ui_mode: embedded and mount the iframe—see checkout.js below (same pattern as rapidcents-iframe-checkout/index.php in this repo).
When to use
- You want the shopper to stay on your domain and layout.
- Subscriptions: same API with
mode: subscription— Subscription checkout.
For full-page redirect instead, see Hosted checkout.
Staging/production hosts: Overview → APIs.
Required API
OAuth access token, then:
Use the API origin for your environment; {business_id} is your business id.
Auth: Overview → token refresh.
All checkout API requests require:
-
Authorization: Bearer <access_token>— from OAuth (see Overview → OAuth). -
Origin— HTTPS origin of your app (for examplehttps://shop.example.com). It must match the origin registered for your API client in RapidCents. -
Content-Type: application/jsonandAccept: application/jsonunless the API specifies otherwise.
Never expose tokens in the browser
Create checkout sessions on your server only. Do not send the access token to client-side JavaScript.
HTTP headers
Required on every checkout/create call from your backend.
Authorization
string
Origin
string
Content-Type
string
Accept
string
Required & common parameters
Path parameters
In the URL path (not the JSON body). Pattern: POST {API origin}/api/{business_id}/checkout/create
business_id
string (UUID)
Payment session (mode: payment)
One-time charge: ui_mode, amounts, return URLs, optional customer fields. Same shape for embedded and hosted.
ui_mode
string
mode
string
amount_total
number
currency
string
amount_subtotal
number
line_items
array
success_url
string (URL)
cancel_url
string (URL)
customer_email
string
customer_name
string
Line item objects (line_items[])
Multiple lines for carts or itemized receipts; one object is enough for a single SKU. Omit or send one row when you do not need a breakdown.
name
string
quantity
number
unit_amount
number
total
number
Example request
curl -sS -X POST "https://uatstage00-api.rapidcents.com/api/YOUR_BUSINESS_ID/checkout/create" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Origin: https://your-https-app.example.com" \
-d '{
"ui_mode": "embedded",
"mode": "payment",
"amount_total": 49.99,
"amount_subtotal": 49.99,
"currency": "CAD",
"success_url": "https://your-https-app.example.com/thank-you?order=1",
"cancel_url": "https://your-https-app.example.com/cart",
"customer_email": "buyer@example.com",
"line_items": [
{ "name": "Item", "quantity": 1, "unit_amount": 49.99, "total": 49.99 }
]
}'
Example response
HTTP 200, checkout_session.checkout_url for the iframe:
{
"ok": true,
"message": "Checkout session created successfully",
"status": "PENDING",
"checkout_session": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"token": "a1b2c3d4e5f6789012345678901234567890abcdef0123456789abcdef012345",
"checkout_url": "https://checkout.rapidcents.com/session/a1b2c3d4\u2026/embedded",
"allowed_origins": [
"https://shop.example.com"
],
"expires_at": "2026-04-21T18:00:00.000000Z",
"session_status": "PENDING",
"payment_status": "UNPAID",
"amount_total": 49.99,
"amount_subtotal": 49.99,
"amount_tax": 0,
"amount_discount": 0,
"surcharge": false,
"amount_surcharge": 0,
"surcharge_rate": null,
"currency": "CAD",
"mode": "payment",
"description": null,
"customer_id": null,
"customer_email": "buyer@example.com",
"customer_name": "Alex Rivera",
"client_reference_id": null,
"success_url": "https://shop.example.com/thank-you?order=1",
"cancel_url": "https://shop.example.com/cart",
"return_url": null,
"metadata": [],
"ui_mode": "embedded",
"created_at": "2026-04-21T12:00:00.000000Z",
"billing_address_collection": null,
"shipping_address_collection": null,
"billing_address": null,
"shipping_address": null,
"consent": null,
"consent_collection": null,
"phone_number_collection": null,
"line_items": [
{
"name": "Premium plan (monthly)",
"quantity": 1,
"unit_amount": 49.99,
"total": 49.99
}
],
"discounts": null,
"apply_discount": null,
"total_details": null,
"invoice_creation": null,
"tax_id_collection": null
},
"transaction": null
}
checkout_session.token— store as your external session or order correlation id.checkout_session.checkout_url— load in an iframe, new tab, or follow as a redirect depending on the mode.
Required for embedded checkout/create: checkout.js
RapidCents ships checkout.js on the same host as the Checkout API. It exposes window.RapidCentsCheckout: call RapidCentsCheckout.init({ … }) once, then RapidCentsCheckout.create({ … }) with the same JSON fields you would send to POST …/checkout/create (including ui_mode: 'embedded'). The library POSTs the session from the browser, then mounts the checkout iframe inside the element you name with containerId. It listens for postMessage (rc:checkout_height, rc:checkout_result) and can verify the session if you configure verifySessionUrl.
URLs:
- Staging:
https://uatstage00-api.rapidcents.com/js/checkout.js - Production:
https://api.rapidcents.com/js/checkout.js
Stubborn Attachments
$20.00
<?php
declare(strict_types=1);
// Example — align field names with payment-testing-app's CreateCheckoutRequest
// (checkout_type + customer_*) and keep amounts / line item titles on the server.
// routes/web.php
Route::post('/create-checkout-session', [ShopCheckoutController::class, 'store']);
// app/Http/Controllers/ShopCheckoutController.php
public function store(Request $request)
{
$validated = $request->validate([
'checkout_type' => 'required|in:embedded,hosted',
'customer_name' => 'nullable|string|max:255',
'customer_email' => 'required|email',
]);
// Prices and line item text must come from your DB/catalog — not unchecked POST fields.
$itemName = 'Stubborn Attachments';
$unit = 20.00;
$res = Http::withToken($this->token())
->acceptJson()
->withHeaders(['Origin' => config('app.url')])
->post("{$this->apiBase}/api/{$this->businessId}/checkout/create", [
'ui_mode' => $validated['checkout_type'] === 'embedded' ? 'embedded' : 'hosted',
'mode' => 'payment',
'amount_total' => $unit,
'amount_subtotal' => $unit,
'currency' => 'CAD',
'success_url' => route('shop.success', [], true),
'cancel_url' => route('shop.cancel', [], true),
'customer_email' => $validated['customer_email'],
'line_items' => [
[
'name' => $itemName,
'quantity' => 1,
'unit_amount' => $unit,
'total' => $unit,
],
],
]);
$data = $res->json();
if (! ($data['ok'] ?? false)) {
abort(422, $data['message'] ?? 'Checkout create failed');
}
return view('pay', [
'checkoutUrl' => $data['checkout_session']['checkout_url'],
]);
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Buy cool new product</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="/style.css">
<!-- Required: checkout.js from your RapidCents API origin -->
<script src="https://api.rapidcents.com/js/checkout.js"></script>
</head>
<body>
<section style="max-width:28rem;margin:2rem auto;font-family:system-ui,sans-serif;">
<div style="display:flex;gap:1rem;align-items:center;padding:1rem;border:1px solid #e2e8f0;border-radius:12px;">
<img src="https://i.imgur.com/EHyR2nP.png" alt="Product" width="96" height="96" style="border-radius:8px;">
<div>
<h3 style="margin:0 0 0.25rem;font-size:1.1rem;">Stubborn Attachments</h3>
<h5 style="margin:0;color:#64748b;font-weight:600;">$20.00</h5>
</div>
</div>
<form action="/create-checkout-session" method="POST" style="margin-top:1.25rem;">
<input type="hidden" name="_token" value="REPLACE_CSRF_TOKEN">
<input type="hidden" name="checkout_type" value="embedded">
<label for="cemail" style="display:block;font-size:0.8rem;color:#64748b;margin-top:0.5rem;">Email</label>
<input id="cemail" type="email" name="customer_email" value="buyer@example.com" required
style="width:100%;margin-top:0.25rem;padding:0.5rem 0.65rem;border:1px solid #e2e8f0;border-radius:8px;box-sizing:border-box;">
<input type="hidden" name="customer_name" value="">
<button type="submit" id="checkout-button"
style="margin-top:0.75rem;width:100%;padding:0.75rem 1rem;border-radius:8px;border:0;background:#4f46e5;color:#fff;font-weight:600;cursor:pointer;">
Checkout
</button>
</form>
<p style="margin-top:1rem;font-size:0.8rem;color:#64748b;">
Same field names as <code>CreateCheckoutRequest</code> in payment-testing-app (<code>checkout_type</code>, <code>customer_email</code>, optional <code>customer_name</code>). The server must set <code>amount_*</code> and <code>line_items</code> — do not take prices from the browser.
</p>
</section>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Thank you</title>
</head>
<body style="font-family:system-ui,sans-serif;padding:2rem;">
<h1>Thanks for your order</h1>
<p>Keep this page idempotent — <code>success_url</code> is not proof of payment. Confirm with your server / webhooks.</p>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Checkout canceled</title>
</head>
<body style="font-family:system-ui,sans-serif;padding:2rem;">
<h1>Checkout canceled</h1>
<p><a href="/">Return to store</a></p>
</body>
</html>
Pattern: {API origin}/js/checkout.js. Reference implementation in this monorepo: rapidcents-iframe-checkout/index.php (loads checkout.js, calls init / create with form data).
Browser usage, success_url / cancel_url, security, and common errors are documented once in
Checkout overview → Browser / frontend,
Success & cancel URLs,
Security, and
Common errors.