RMT.GG/Seller developer docs
v1

Seller API

Automate listings, fulfill sales, and stream order events. Includes outbound webhooks and reserve endpoints for on-demand inventory refill after payment.

REST Open API

Bearer-authenticated /api/v1 for offers and orders, with discovery and rate-limit headers.

Outbound webhooks

Signed HTTPS (or Discord) deliveries for order and offer lifecycle events.

Reserve / refill

Mint COMPLEX stock from your server after payment when local inventory is short.

What you can build

The Seller Open API is for sellers who want Discord alerts, stock sync, Zapier-style automation, or a custom back office on top of RMT.GG.

  • Manage offers
    Create drafts, update safe fields, publish, and archive via /api/v1/offers.
  • Fulfill sales
    List and inspect seller orders, then mark them delivered with optional evidence URLs.
  • Stay under the limit
    Every key is capped at 300 requests per minute. Responses include X-RateLimit-* headers.
  • React in real time
    Subscribe to order and offer events, or refill COMPLEX inventory with reserve webhooks.

Quick start

Enable developer access, mint a key, then call discovery to print the live catalog.

  1. 1Open Settings → Developer and enable access (self-serve, no approval wait).
  2. 2Create an API key and copy the secret once (rmt_sk_live_…). Store it in your secret manager.
  3. 3Call GET /api/v1 with Authorization: Bearer to confirm scopes, quotas, and operations.
GET/api/v1

Discovery document

Returns scopes, quotas, webhook events, and the full operations catalog. Any valid API key works.

Example request

bash
curl -s -H "Authorization: Bearer rmt_sk_live_…" \
  https://rmt.gg/api/v1 | jq .

Example response

json
{
  "name": "RMT Seller Open API",
  "version": "1",
  "basePath": "/api/v1",
  "scopes": ["offers:read", "offers:write", "orders:read", "orders:write", "webhooks:manage"],
  "webhookEvents": ["order.paid", "order.delivered", "…"],
  "operations": [ /* full catalog */ ]
}

Authentication

Send your live secret key on every /api/v1 request. Prefer HTTPS only. Never embed keys in public clients or browser bundles.

Preferred header

http
Authorization: Bearer rmt_sk_live_<prefix>_<secret>

Alternate header

http
X-Api-Key: rmt_sk_live_<prefix>_<secret>

Rotate on leak

If a key leaks, revoke it in Developer settings and create a new one. Update your automation before revoking if you are live.

Scopes

Each API key carries scopes that gate endpoints. Missing scope returns 403 SCOPE_MISSING.

offers:read
offers:write
orders:read
orders:write
webhooks:manage
  • offers:read: List and get your offers.
  • offers:write: Create, update, publish, and delete offers.
  • orders:read: List and get seller orders.
  • orders:write: Mark orders delivered.
  • webhooks:manage: Reserved for future Open API webhook management. Configure endpoints in Developer settings today.

Default key scopes

New keys receive offers:read, offers:write, orders:read, and orders:write. Outbound webhook CRUD stays in the Settings UI (session auth).

Offers API

Offer identifiers accept the public url slug or numeric id. Responses omit internal id and sellerId.

What PATCH cannot change yet

Stock rows, option prices, media, and attributes are managed in the seller editor (or future endpoints), not via PATCH today.

GET/api/v1/offers
offers:read

List your offers

Filter with archive=active (default), archived, or all.

Parameters

  • archive
    In
    query
    Type
    string
    Description
    One of "active" (default), "archived", or "all".
  • Response: { offers: Offer[], total: number }. Numeric id and sellerId are omitted.

Example request

bash
curl -H "Authorization: Bearer rmt_sk_live_…" \
  "https://rmt.gg/api/v1/offers?archive=active"

Example response

json
{
  "offers": [{ "url": "my-offer", "title": "…", "visibility": "PUBLIC", "published": 1 }],
  "total": 1
}
POST/api/v1/offers
offers:write

Create a draft offer

Creates an empty draft owned by the authenticated seller. No body required.

  • No request body required.
  • Response 201: { offer: Offer }.

Example request

bash
curl -X POST -H "Authorization: Bearer rmt_sk_live_…" \
  https://rmt.gg/api/v1/offers

Example response

json
{
  "offer": { "url": "draft-abc", "title": null, "visibility": "UNPUBLISHED", "published": 0 }
}
GET/api/v1/offers/:urlOrId
offers:read

Get one offer

Load by public url slug or numeric id. Relations (options) may be included; stock items are not.

Parameters

  • urlOrIdrequired
    In
    path
    Type
    string
    Description
    Offer.url slug or Offer.id.
  • Returns relations (options, etc.) when available; items are not included.

Example request

bash
curl -H "Authorization: Bearer rmt_sk_live_…" \
  https://rmt.gg/api/v1/offers/YOUR_OFFER_URL
PATCH/api/v1/offers/:urlOrId
offers:write

Update offer fields

Patch a safe subset of listing fields. Emits offer.updated when outbound webhooks are configured.

Parameters

  • urlOrIdrequired
    In
    path
    Type
    string
    Description
    Offer.url slug or Offer.id.
  • title
    In
    body
    Type
    string
    Description
    Listing title.
  • description
    In
    body
    Type
    string
    Description
    Listing description.
  • visibility
    In
    body
    Type
    string
    Description
    PUBLIC | PRIVATE | UNPUBLISHED.
  • categoryId
    In
    body
    Type
    number
    Description
    Catalog category id.
  • offeringId
    In
    body
    Type
    number
    Description
    Catalog offering id.
  • thumbnail
    In
    body
    Type
    string
    Description
    Thumbnail URL or asset reference.
  • offerType
    In
    body
    Type
    string
    Description
    Offer type string used by the listing.
  • listingMode
    In
    body
    Type
    string
    Description
    Listing mode (for example STANDARD, RANK_BOOST, SESSION).
  • At least one allowed field is required.
  • Emits offer.updated webhook when configured.
  • Stock, options, media, and attributes are not editable via this endpoint yet.

Example request

bash
curl -X PATCH -H "Authorization: Bearer rmt_sk_live_…" \
  -H "Content-Type: application/json" \
  https://rmt.gg/api/v1/offers/YOUR_OFFER_URL \
  -d @body.json

Request body

json
{
  "title": "Updated title",
  "description": "Buyer-facing description",
  "visibility": "PUBLIC",
  "categoryId": 12,
  "offeringId": 34,
  "thumbnail": "https://…",
  "offerType": "ACCOUNT",
  "listingMode": "STANDARD"
}
DELETE/api/v1/offers/:urlOrId
offers:write

Delete or archive

Same delete/archive rules as the seller UI.

Parameters

  • urlOrIdrequired
    In
    path
    Type
    string
    Description
    Offer.url slug or Offer.id.
  • Response: { ok: true }.

Example request

bash
curl -X DELETE -H "Authorization: Bearer rmt_sk_live_…" \
  https://rmt.gg/api/v1/offers/YOUR_OFFER_URL

Example response

json
{ "ok": true }
POST/api/v1/offers/:urlOrId/publish
offers:write

Publish an offer

Publishes a draft (or changes visibility). Fails with 400 if required listing fields are incomplete.

Parameters

  • urlOrIdrequired
    In
    path
    Type
    string
    Description
    Offer.url slug or Offer.id.
  • visibility
    In
    body
    Type
    string
    Description
    Optional. PUBLIC (default), PRIVATE, or UNPUBLISHED.
  • Response: { offer: Offer }.
  • Fails if the listing is incomplete for publish.

Example request

bash
curl -X POST -H "Authorization: Bearer rmt_sk_live_…" \
  -H "Content-Type: application/json" \
  https://rmt.gg/api/v1/offers/YOUR_OFFER_URL/publish \
  -d '{"visibility":"PUBLIC"}'

Orders API

Orders are scoped to your seller account. Buyer billing details may be redacted under marketplace-of-record privacy rules.

GET/api/v1/orders
orders:read

List seller orders

Supports limit, offset, status, q, and sort (newest, oldest, total_high, total_low).

Parameters

  • limit
    In
    query
    Type
    number
    Description
    Page size.
  • offset
    In
    query
    Type
    number
    Description
    Pagination offset.
  • status
    In
    query
    Type
    string
    Description
    Filter by order status (for example PAID, DELIVERED, COMPLETED).
  • q
    In
    query
    Type
    string
    Description
    Search query (reference / related text).
  • sort
    In
    query
    Type
    string
    Description
    newest | oldest | total_high | total_low.
  • Response: { orders: Order[], total: number }.

Example request

bash
curl -H "Authorization: Bearer rmt_sk_live_…" \
  "https://rmt.gg/api/v1/orders?status=PAID&limit=20&sort=newest"
GET/api/v1/orders/:uid
orders:read

Get one order

Returns the order with line items. Use the public order uid.

Parameters

  • uidrequired
    In
    path
    Type
    string
    Description
    Order.uid.
  • Response: { order } with line items.
  • Buyer billing fields may be redacted under marketplace-of-record privacy rules.

Example request

bash
curl -H "Authorization: Bearer rmt_sk_live_…" \
  https://rmt.gg/api/v1/orders/ORDER_UID
POST/api/v1/orders/:uid/deliver
orders:write

Mark delivered

Manual fulfillment. COMPLEX lines must be fully attached when required. Emits order.delivered.

Parameters

  • uidrequired
    In
    path
    Type
    string
    Description
    Order.uid.
  • evidence
    In
    body
    Type
    string[]
    Description
    Optional array of evidence URLs (screenshots, transfer proofs).
  • Response: { success: true, order }.
  • COMPLEX inventory lines must be fully attached before deliver when the product requires it.
  • Emits order.delivered webhook when configured.

Example request

bash
curl -X POST -H "Authorization: Bearer rmt_sk_live_…" \
  -H "Content-Type: application/json" \
  https://rmt.gg/api/v1/orders/ORDER_UID/deliver \
  -d @evidence.json

Request body

json
{
  "evidence": [
    "https://cdn.example.com/proof-1.png"
  ]
}

Outbound webhooks

Configure HTTPS endpoints (or Discord webhooks) in Settings → Developer. RMT POSTs when subscribed events fire.

order.paid
order.delivered
order.completed
order.refunded
order.disputed
offer.published
offer.updated
  • JSON format posts a structured envelope with id, type, created, and data.
  • Discord format posts rich embeds with order or offer links.
  • Optional signing uses X-RMT-Timestamp and X-RMT-Signature (same scheme as reserve).
  • Delivery history appears under each endpoint so you can retry failures. Endpoints auto-pause after repeated failures.

JSON delivery envelope

json
{
  "id": "whd_…",
  "type": "order.paid",
  "created": "2026-07-23T12:00:00.000Z",
  "data": {
    "order": {
      "uid": "ord_…",
      "reference": "RMT-…",
      "status": "PAID",
      "url": "https://rmt.gg/orders/ord_…",
      "items": [ /* line items with offer names */ ]
    }
  }
}

Signed delivery headers

json
{
  "X-RMT-Event": "order.paid",
  "X-RMT-Delivery": "whd_…",
  "X-RMT-Timestamp": "1710000000",
  "X-RMT-Signature": "v1=abc123…"
}

Verify webhook signatures

When a signing secret is set, compute HMAC-SHA256 over timestamp + '.' + rawBody and compare to the hex after v1=.

Use the raw request body bytes, not a re-serialized JSON object. Reject stale timestamps (for example older than five minutes).

Node.js sketch

javascript
import crypto from "node:crypto";

const expected = crypto
  .createHmac("sha256", secret)
  .update(`${timestamp}.${rawBody}`)
  .digest("hex");
const provided = signatureHeader.replace(/^v1=/, "");
const ok =
  expected.length === provided.length &&
  crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(provided));

Reserve webhooks (inventory refill)

For COMPLEX (unique unit) listings, RMT can POST your HTTPS endpoint after payment to mint the next license, account, or key when local stock is short.

Payment-safe failures

If your endpoint times out or returns invalid data, the order stays PAID. The buyer is charged; you see an error on the order and can retry reserve or attach keys manually.

  • Local stock is always preferred; the webhook fills only the shortfall.
  • Configure an offer-level default, or override per pricing option, on the Items step of the offer editor.
  • HTTPS only. Optional HMAC signing matches outbound webhooks (X-RMT-Event: reserve.item).
  • Test in the editor sends dryRun: true. On the order page, use Retry reserve after fixing your endpoint.

Canonical POST body (truncated)

json
{
  "id": "rsv_…",
  "type": "reserve.item",
  "order": { "uid": "ord_…", "reference": "RMT-…", "url": "https://rmt.gg/orders/ord_…" },
  "offer": { "url": "my-offer", "title": "Game key", "pageUrl": "https://rmt.gg/offers/my-offer" },
  "option": { "id": 1, "name": "Standard" },
  "fields": [{ "id": 10, "name": "License", "type": "text", "required": true }],
  "quantity": 1
}

Convenience response

json
{
  "entries": [
    { "name": "License", "value": "AAAA-BBBB-CCCC" }
  ]
}

Mapped JSON fields (with responseMap paths like $.license)

json
{
  "license": "AAAA-BBBB-CCCC",
  "email": "[email protected]",
  "password": "temporary-pass"
}

Do not call reserve before payment

RMT only calls your endpoint after payment succeeds, so abandoned checkouts do not burn licenses.

Errors and rate limits

Errors return JSON { error, code? }. Open API traffic is limited to 300 requests per minute per API key.

  • API_KEY_REQUIRED
    401

    Missing Authorization or X-Api-Key header.

  • API_KEY_INVALID
    401

    Key unknown, revoked, expired, or developer access disabled.

  • SCOPE_MISSING
    403

    Key lacks the scope required by the endpoint.

  • RATE_LIMITED
    429

    Too many requests. Honor Retry-After and X-RateLimit-Reset.

  • RESERVE_FAILED
    400

    Reserve webhook timed out, returned invalid data, or missed required fields.

Handle 429

Back off using Retry-After seconds. Do not rotate keys to bypass limits; the limit is per key and flat for all sellers.

Successful responses include X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset.

Ready to automate?

Enable developer access, create a key, and wire your first webhook in Settings.