Hosted checkout

Apply in Settings, wait for approval, then create a session and send buyers to an RMT pay page. You fulfill after checkout.completed. Approved partners pay 4% of the locked amount.

Take payments from your own shop. RMT.GG is merchant of record. Use the Seller API to send buyers to an RMT pay page.

How hosted checkout works

RMT.GG stays merchant of record. Your partner shop sends a locked amount and currency. The buyer pays on our hosted page. After payment, you deliver in your shop. Orders auto-complete so wallet settlement can run.

  • The buyer pays exactly the amount and currency you send. We do not gross it up.
  • Your seller fee is 4% of that locked amount. Marketplace listings stay at the usual 5%.
  • Card, PayPal, and crypto processing fees are absorbed by the platform on this flow.

Allowlist required

Apply under Settings, Hosted checkout, then wait for admin approval. Unapproved API keys receive CHECKOUT_PARTNER_NOT_APPROVED.

Apply and get approved

After approval, create an API key with checkout:write and a JSON webhook for checkout.completed on the Hosted checkout settings page. Until approval, hosted checkout APIs stay blocked.

  1. 1Open Settings → Hosted checkout and submit your shop URL plus a short note on how you will use checkout.
  2. 2Wait for an admin to approve. You will see a pending badge until then.
  3. 3After approval, create an API key and a JSON webhook for checkout.completed on Settings → Hosted checkout.

Seller API

Use this from any shop or your own server. Create a session with POST /api/v1/checkout/sessions. Send checkout:write and an Idempotency-Key. Redirect the buyer to hosted_url. Listen for checkout.completed, then fulfill in your shop.

Create a hosted checkout session

bash
curl -X POST -H "Authorization: Bearer rmt_sk_live_…" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: inv-12345" \
  https://rmt.gg/api/v1/checkout/sessions \
  -d @session.json

Create session body

javascript
{
  amount: 10, // required when items is omitted
  currency: "USD", // optional; defaults to USD
  itemName: "Gold pack", // required when items is omitted; alias title
  description: "1000 gold for account example", // optional
  imageUrl: "https://cdn.shop.example/gold.png", // optional, HTTPS only
  categorySlug: "games", // send with offering, or omit both
  offering: "Mods", // send with categorySlug
  email: "[email protected]", // optional
  returnUrl: "https://your-shop.example/thanks", // optional
  cancelUrl: "https://your-shop.example/cancel", // optional
  invoiceId: "12345" // optional
}

Multiple locked lines with optional delivery (session.json)

javascript
{
  currency: "USD",
  invoiceId: "12345", // optional
  items: [ // required when amount is omitted
    {
      name: "Gold pack", // required per line
      description: "1000 gold", // optional
      amount: 10, // required per line
      quantity: 1, // optional, default 1
      imageUrl: "https://cdn.shop.example/gold.png", // optional, HTTPS only
      delivery: [ // optional
        { name: "Code", type: "text", value: "XXXX-YYYY" } // name and value required; type is optional
      ]
    }
  ]
}
  • Send amount plus itemName (or title) for a single item, or a non-empty items[] array. Currency defaults to USD. Optional fields: description, HTTPS imageUrl, email (pre-fills the pay page), returnUrl, cancelUrl, invoiceId, categorySlug plus offering (send both or neither), and metadata. itemName is the pay page heading; description is the longer copy underneath. The buyer must confirm a valid email before paying. After payment the buyer stays on the RMT.GG confirmation so they can copy delivery fields. If you set returnUrl and there are delivery fields, they continue to your shop from that screen. If there are none, we send them back after a short countdown. If you omit returnUrl or cancelUrl, the buyer stays on the RMT.GG pay page after payment, cancel, or expiry.
  • On success we append the order uid to returnUrl as ?order= when that URL is HTTPS (or localhost).
  • Repeat Idempotency-Key or invoiceId values reuse the same session instead of creating a duplicate.
  • itemName and description appear on the RMT pay page only. Card, PayPal, and crypto checkout use catalog-coded labels like Games · Add-ons, never your shop title. Set a default under Settings, Hosted checkout, or send categorySlug and offering on the session. categorySlug is a public root slug such as games, not a child game slug. offering can be the name, slug, or coded label (Mods, Add-ons). Matching is case-insensitive. If the pair is missing one side or does not match the catalog, the API returns 400 INVALID_PSP_CATEGORY and no session is created.
  • Sessions last 24 hours. After that the pay page cannot complete, in-flight Stripe and PayPal sessions are closed, and we POST checkout.canceled with reason expired.
  • items[] is the multi-line alternative to a single amount plus itemName body. Each line needs name and amount. With items, amount may be omitted and is computed from the lines, or must match the sum if you send it. Quantity is locked on rmt.gg: buyers cannot add, remove, or change lines. imageUrl must be HTTPS; we do not fetch it. Optional delivery fields (text, password, or textarea) need a name and value. They are shown after payment on the confirmation page and Purchases. Public session GET includes delivery values only after payment. Seller GET and webhooks never include them.

Check payment status

Listen for checkout.completed first. If a webhook is delayed, GET the session. paid is true when the buyer has paid. You can look up by session uid or by the invoiceId you sent.

  • GET /api/v1/checkout/sessions/{uid} using the uid returned when you created the session.
  • GET /api/v1/checkout/sessions?invoiceId=YOUR_INVOICE_ID if you stored your own invoice id instead.

Look up by invoice id

bash
curl -H "Authorization: Bearer rmt_sk_live_…" \
  https://rmt.gg/api/v1/checkout/sessions?invoiceId=inv-12345

Digiseller and similar shops

Skip this if you create checkouts with the Seller API. Use it when your shop (for example Digiseller) sends the buyer here through Setup individual payment methods. Digiseller posts to our Payment URL, we take the payment, then Digiseller checks the Status URL.

  1. 1Copy the Payment URL, Status URL, and payment secret from Settings → Hosted checkout.
  2. 2Paste them into Digiseller under Setup individual payment methods. Keep the secret private. If Digiseller generated the secret, paste that secret into Settings instead.
  3. 3Digiseller then sends buyers to us to pay, and checks the Status URL for paid or unpaid.
  • item_name (or title) is the heading on the pay page. description is the longer copy underneath. If both names are omitted, description is used as the heading.

Example request Digiseller sends

json
{
  "invoice_id": "12345",
  "amount": "10.00",
  "currency": "USD",
  "item_name": "Gold pack",
  "description": "1000 gold for account example",
  "signature": "…"
}

Prefer a JSON webhook

The Status URL is for Digiseller. If you fulfill from your own server, add a JSON webhook and listen for checkout.completed. You can also GET the session as a backup.

Hosted checkout events

On Settings → Hosted checkout, add a JSON HTTPS endpoint and subscribe to hosted checkout events. After payment we POST checkout.completed. If the buyer leaves unpaid we POST checkout.canceled. After a refund we POST checkout.refunded. Match the sale with invoiceId or checkout.uid. These are separate from marketplace order.paid events.

checkout.completed payload

json
{
  "id": "whd_…",
  "type": "checkout.completed",
  "created": "2026-08-14T12:00:00.000Z",
  "data": {
    "checkout": {
      "uid": "pcs_…",
      "status": "paid",
      "amount": 10,
      "currency": "USD",
      "itemName": "Gold pack",
      "invoiceId": "inv-12345",
      "source": "api",
      "orderUid": "ord_…",
      "items": [
        {
          "name": "Gold pack",
          "description": "1000 gold for account example",
          "amount": 10,
          "quantity": 1,
          "imageUrl": "https://cdn.shop.example/gold.png"
        }
      ]
    }
  }
}
  • source is api for Seller API sessions.
  • Optional signing uses X-RMT-Timestamp and X-RMT-Signature. Verify HMAC the same way as any other seller webhook.
  • checkout.canceled includes reason buyer_canceled when the buyer leaves the pay page unpaid, or reason expired when the 24-hour session TTL elapses unpaid.
  • checkout.items lists locked lines (name, description, amount, quantity, imageUrl). Delivery values are never included in webhooks.

Do not double-fulfill

Digiseller also gets its own payment callback. If you also listen for checkout.completed, fulfill the order only once. Seller API sessions never send that Digiseller callback.

Guest email and receipts

Buyers must enter an email on the pay page so we can send the receipt and tax invoice. Matching RMT accounts are attached without signing the buyer in.

  • If the email already belongs to an RMT account, the order appears in that account's Purchases. No login cookie is set on the pay page.
  • A new email creates a lightweight user so receipts and later sign-in still work.
  • Email is required to complete payment. Your shop should still listen for checkout.completed.

Currencies and limits

Use a supported ISO currency such as USD or EUR. Card checkout works best in USD or EUR. Crypto and PayPal can still work for other currencies when the provider accepts them.

Not in this version

There is no iframe SDK, custom pay-page domain, or wallet balance on the hosted pay page. Buyers use card, PayPal, or crypto redirect checkout.

Before you go live

Staging checklist

Unit tests cover fees, HMAC, and reuse. Walk through this list on staging before you send real buyers.

  • Apply, confirm the pending badge, then have an admin approve. Credentials appear only when approved. An unapproved key on POST /api/v1/checkout/sessions returns 403.
  • Create a session with itemName, description, and categorySlug plus offering (or a saved default). Open hosted_url. The heading is the item name; the description is underneath. The pay page has no top nav or sidebar. Pay with card in USD or EUR. Card, PayPal, and crypto pages should show a catalog label such as Games · Add-ons, not your shop title.
  • Confirm checkout.completed includes invoiceId, checkout.uid, and source, then fulfill in your shop. Cancel the pay page and confirm checkout.canceled with reason buyer_canceled. Let a session sit past 24 hours and confirm checkout.canceled with reason expired cannot still be paid.
  • For Digiseller, paste the Payment URL, Payment status URL, and payment secret into Setup individual payment methods, or paste Digiseller's generated secret into Settings. Confirm Digiseller can see paid status, and that you fulfill the order only once.
  • Pay with an existing RMT email: the order lands in Purchases and a receipt is sent, with no login cookie. A new email creates a lightweight user. Email is required on the pay page.
  • The hidden synthetic offer must not appear in marketplace search. On a waitlist-gated host, /pay/:uid and adapter routes still work.
  • Send optional imageUrl and items[] if you need a product image or multiple locked lines. Confirm the pay page has no quantity controls. After payment, delivery fields appear on Purchases and the order page. HTTPS image URLs only.

Related guides

Apply for hosted checkout

Open Settings → Hosted checkout to apply. After approval, create an API key and a checkout.completed webhook on that same page.