RMT.GG/Dokumentation für Entwickler von Verkäufern
v1

Verkäufer API

Automatisiere Angebote, erfülle Verkäufe und streamen Ereignisse von Bestellungen. Beinhaltet ausgehende Webhooks und Reservierungsendpunkte für die Nachfüllung von Beständen nach der Zahlung.

REST Open API

Bearer-authentifiziert /api/v1 für Angebote und Bestellungen, mit Entdeckungs- und Ratenlimit-Headern.

Ausgehende Webhooks

Signierte HTTPS (oder Discord) Lieferungen für Ereignisse im Lebenszyklus von Bestellungen und Angeboten.

Reservieren / Nachfüllen

Mint COMPLEX-Bestände von deinem Server nach der Zahlung, wenn der lokale Bestand knapp ist.

Was du erstellen kannst

Die Verkäufer Open API ist für Verkäufer, die Discord-Benachrichtigungen, Bestands-Synchronisation, Zapier-ähnliche Automatisierung oder ein benutzerdefiniertes Backoffice auf RMT.GG wünschen.

  • Angebote verwalten
    Entwürfe erstellen, sichere Felder aktualisieren, veröffentlichen und archivieren über /api/v1/offers.
  • Verkäufe erfüllen
    Verkäuferbestellungen auflisten und inspizieren, dann als geliefert markieren mit optionalen Beweis-URLs.
  • Unter dem Limit bleiben
    Jeder Schlüssel ist auf 300 Anfragen pro Minute begrenzt. Antworten enthalten X-RateLimit-* Header.
  • In Echtzeit reagieren
    Abonniere Ereignisse von Bestellungen und Angeboten oder fülle COMPLEX-Bestände mit reservierten Webhooks auf.

Schnellstart

Erstelle einen API-Schlüssel in den Entwicklereinstellungen und rufe dann Discovery auf, um den Live-Katalog anzuzeigen.

  1. 1Öffne Einstellungen → Entwickler (kein separater Aktivierungsschritt).
  2. 2Erstelle einen API-Schlüssel und kopiere das Geheimnis einmal (rmt_sk_live_…). Speichere es in deinem Geheimnismanager.
  3. 3Rufe GET /api/v1 mit Authorization: Bearer auf, um Scopes, Quoten und Operationen zu bestätigen.
GET/api/v1

Entdeckungsdokument

Gibt Scopes, Quoten, Webhook-Ereignisse und das vollständige Katalog der Operationen zurück. Jeder gültige API-Schlüssel funktioniert.

Beispielanfrage

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

Beispielantwort

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 */ ]
}

Authentifizierung

Sende deinen Live-Geheimschlüssel bei jeder /api/v1-Anfrage. Bevorzuge nur HTTPS. Betten Sie niemals Schlüssel in öffentlichen Clients oder Browser-Bundles ein.

Bevorzugter Header

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

Alternativer Header

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

Rotieren bei Leck

Wenn ein Schlüssel geleakt wird, widerrufe ihn in den Entwicklereinstellungen und erstelle einen neuen. Aktualisiere deine Automatisierung, bevor du widerrufst, wenn du live bist.

Scopes

Jeder API-Schlüssel trägt Scopes, die Endpunkte steuern. Fehlender Scope gibt 403 SCOPE_MISSING zurück.

offers:read
offers:write
orders:read
orders:write
webhooks:manage
  • offers:read: Liste und hole deine Angebote.
  • offers:write: Erstelle, aktualisiere, veröffentliche und lösche Angebote.
  • orders:read: Liste und hole Verkäuferbestellungen.
  • orders:write: Markiere Bestellungen als geliefert.
  • webhooks:manage: Reserviert für zukünftige Open API Webhook-Verwaltung. Konfiguriere Discord/Telegram in den Benachrichtigungen und JSON-Webhooks in den Entwicklereinstellungen heute.

Standard-Schlüssel-Scope

Neue Schlüssel erhalten offers:read, offers:write, orders:read und orders:write. Ausgehende Webhook CRUD bleibt in der UI der Einstellungen (Sitzungsauthentifizierung).

Angebote API

Angebotsidentifikatoren akzeptieren den öffentlichen URL-Slug oder die numerische ID. Antworten lassen interne ID und sellerId weg.

Was PATCH noch nicht ändern kann

Bestandszeilen, Optionspreise, Medien und Attribute werden im Verkäufer-Editor (oder zukünftigen Endpunkten) verwaltet, nicht über PATCH heute.

GET/api/v1/offers
offers:read

Liste deine Angebote

Filtern mit archive=active (Standard), archiviert oder alle.

Parameter

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

Beispielanfrage

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

Beispielantwort

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

Erstelle ein Entwurfsangebot

Erstellt einen leeren Entwurf, der dem authentifizierten Verkäufer gehört. Kein Körper erforderlich.

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

Beispielanfrage

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

Beispielantwort

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

Hole ein Angebot

Lade nach öffentlichem URL-Slug oder numerischer ID. Beziehungen (Optionen) können enthalten sein; Bestandsartikel sind nicht enthalten.

Parameter

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

Beispielanfrage

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

Aktualisiere Angebotsfelder

Patch ein sicheres Teilset von Angebotsfeldern. Gibt offer.updated aus, wenn ausgehende Webhooks konfiguriert sind.

Parameter

  • urlOrIderforderlich
    In
    path
    Typ
    string
    Beschreibung
    Offer.url slug or Offer.id.
  • title
    In
    body
    Typ
    string
    Beschreibung
    Listing title.
  • description
    In
    body
    Typ
    string
    Beschreibung
    Listing description.
  • visibility
    In
    body
    Typ
    string
    Beschreibung
    PUBLIC | PRIVATE | UNPUBLISHED.
  • categoryId
    In
    body
    Typ
    number
    Beschreibung
    Catalog category id.
  • offeringId
    In
    body
    Typ
    number
    Beschreibung
    Catalog offering id.
  • thumbnail
    In
    body
    Typ
    string
    Beschreibung
    Thumbnail URL or asset reference.
  • offerType
    In
    body
    Typ
    string
    Beschreibung
    Offer type string used by the listing.
  • listingMode
    In
    body
    Typ
    string
    Beschreibung
    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.

Beispielanfrage

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

Anfragekörper

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

Löschen oder archivieren

Die gleichen Lösch-/Archivierungsregeln wie die Verkäufer-UI.

Parameter

  • urlOrIderforderlich
    In
    path
    Typ
    string
    Beschreibung
    Offer.url slug or Offer.id.
  • Response: { ok: true }.

Beispielanfrage

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

Beispielantwort

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

Veröffentliche ein Angebot

Veröffentlicht einen Entwurf (oder ändert die Sichtbarkeit). Schlägt mit 400 fehl, wenn erforderliche Angebotsfelder unvollständig sind.

Parameter

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

Beispielanfrage

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"}'

Bestellungen API

Bestellungen sind auf dein Verkäuferkonto beschränkt. Käuferabrechnungsdetails können gemäß den Datenschutzbestimmungen des Marktplatzes anonymisiert werden.

GET/api/v1/orders
orders:read

Liste Verkäuferbestellungen

Unterstützt limit, offset, status, q und sort (neueste, älteste, total_high, total_low).

Parameter

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

Beispielanfrage

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

Hole eine Bestellung

Gibt die Bestellung mit Positionen zurück. Verwende die öffentliche Bestell-UID.

Parameter

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

Beispielanfrage

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

Markiere als geliefert

Manuelle Erfüllung. COMPLEX-Positionen müssen vollständig angehängt sein, wenn erforderlich. Gibt order.delivered aus.

Parameter

  • uiderforderlich
    In
    path
    Typ
    string
    Beschreibung
    Order.uid.
  • evidence
    In
    body
    Typ
    string[]
    Beschreibung
    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.

Beispielanfrage

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

Anfragekörper

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

Ausgehende Webhooks

Konfiguriere HTTPS-Endpunkte (oder Discord-Webhooks) in Einstellungen → Entwickler. RMT POSTs, wenn abonnierte Ereignisse ausgelöst werden.

order.paid
order.delivered
order.completed
order.refunded
order.disputed
offer.published
offer.updated
  • JSON-Format sendet einen strukturierten Umschlag mit id, type, created und data.
  • Discord-Format sendet reichhaltige Einbettungen mit Links zu Bestellungen oder Angeboten.
  • Optionale Signierung verwendet X-RMT-Timestamp und X-RMT-Signature (das gleiche Schema wie bei der Reservierung).
  • Die Lieferhistorie erscheint unter jedem Endpunkt, damit du fehlgeschlagene Versuche erneut versuchen kannst. Endpunkte pausieren automatisch nach wiederholten Fehlern.

JSON-Lieferumschlag

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 */ ]
    }
  }
}

Signierte Lieferheader

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

Webhook-Signaturen überprüfen

Wenn ein Signierungsgeheimnis festgelegt ist, berechne HMAC-SHA256 über timestamp + '.' + rawBody und vergleiche mit dem Hex nach v1=.

Verwende die rohen Bytes des Anfragekörpers, nicht ein neu serialisiertes JSON-Objekt. Lehn abgelaufene Zeitstempel ab (zum Beispiel älter als fünf Minuten).

  • Lese die rohen Body-Bytes genau so, wie sie empfangen wurden. Parste kein JSON und serialisiere nicht neu, bevor du hasht.
  • Verwende den Wert des X-RMT-Timestamp-Headers als Zeitstempel-Präfix (derselbe String, nicht umformatiert).
  • Vergleiche mit einem zeit-sicheren Gleichheitscheck. Lehne Anfragen mit fehlenden oder nicht übereinstimmenden Signaturen ab, wenn ein Geheimnis konfiguriert ist.
  • Lehne optional Zeitstempel ab, die älter als ein paar Minuten sind, um Replay zu begrenzen. Dasselbe Schema gilt für reserve.item und ausgehende Bestellereignisse.

Node.js Skizze

javascript
import crypto from "node:crypto";

// secret = the signing secret you saved on RMT (never sent in the request)
// rawBody = exact POST body string (do not JSON.parse then re-stringify)
const timestamp = req.headers["x-rmt-timestamp"];
const signatureHeader = req.headers["x-rmt-signature"]; // "v1=<hex>"

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

if (!ok) {
  // Reject: 401 Unauthorized
}

Webhook reservieren (Bestandsauffüllung)

Für COMPLEX (einzigartige Einheit) Angebote kann RMT dein HTTPS-Endpunkt nach der Zahlung POSTen, um die nächste Lizenz, das Konto oder den Schlüssel zu minten, wenn der lokale Bestand knapp ist.

Zahlungssichere Fehler

Wenn dein Endpunkt zeitlich begrenzt ist oder ungültige Daten zurückgibt, bleibt die Bestellung BEZAHLT. Der Käufer wird belastet; du siehst einen Fehler bei der Bestellung und kannst die Reservierung erneut versuchen oder Schlüssel manuell anhängen.

So richtest du es ein

  1. Erstelle ein KOMPLEXES Angebot mit Artikel-Feldern (zum Beispiel Lizenz).
  2. Aktiviere im Schritt Artikel den On-Demand-Inventar-Endpunkt und füge deine öffentliche HTTPS-URL ein.
  3. Setze optional ein Signing-Geheimnis, damit RMT bei jedem Aufruf X-RMT-Timestamp und X-RMT-Signature sendet.
  4. Führe einen Test durch (oder füge ein Beispiel-JSON ein), mappe die Antwortpfade auf die Artikel-Felder und speichere dann.
  5. Veröffentliche das Angebot. Käufer können mit leerem lokalem Bestand kaufen; Schlüssel werden nach der Zahlung erstellt.
  • Lokaler Bestand hat immer Vorrang; der Webhook füllt nur die Lücke.
  • Konfiguriere einen Standard auf Angebotsebene oder überschreibe pro Preisoption im Schritt 'Artikel' des Angebotseditors.
  • Nur HTTPS. Optionale HMAC-Signierung entspricht ausgehenden Webhooks (X-RMT-Event: reserve.item).
  • Testen im Editor sendet dryRun: true. Auf der Bestellseite verwende 'Retry reserve', nachdem du deinen Endpunkt behoben hast.

Kanonicischer POST-Körper (gekürzt)

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
}

Anforderungsheader (wenn ein Signing-Geheimnis gesetzt ist)

json
{
  "Content-Type": "application/json",
  "X-RMT-Event": "reserve.item",
  "X-RMT-Delivery": "rsv_…",
  "X-RMT-Timestamp": "1710000000",
  "X-RMT-Signature": "v1=abc123…"
}

Bequeme Antwort

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

Zuordnungs-JSON-Felder (mit responseMap-Pfaden wie $.license)

json
{
  "license": "AAAA-BBBB-CCCC",
  "email": "buyer-account@example.com",
  "password": "temporary-pass"
}

So verifizierst du das Signing-Geheimnis

Wenn du ein Geheimnis für das Angebot festlegst, ist jeder Reserve-POST signiert. Berechne HMAC-SHA256(secret, timestamp + '.' + rawBody) neu und vergleiche mit X-RMT-Signature, nachdem du das v1= Präfix entfernt hast. Das Geheimnis selbst ist niemals in der Anfrage enthalten.

Siehe vollständiges Verifizierungsbeispiel

Rufe die Reservierung nicht vor der Zahlung auf

RMT ruft deinen Endpunkt nur nach erfolgreicher Zahlung auf, sodass abgebrochene Bestellungen keine Lizenzen verbrauchen.

Fehler und Ratenlimits

Fehler geben JSON { error, code? } zurück. Open API-Verkehr ist auf 300 Anfragen pro Minute pro API-Schlüssel begrenzt.

  • API_KEY_REQUIRED
    401

    Fehlender Authorization- oder X-Api-Key-Header.

  • API_KEY_INVALID
    401

    Schlüssel unbekannt, widerrufen, abgelaufen oder Entwicklerzugang ausgesetzt.

  • SCOPE_MISSING
    403

    Schlüssel hat nicht den für den Endpunkt erforderlichen Scope.

  • RATE_LIMITED
    429

    Zu viele Anfragen. Beachte Retry-After und X-RateLimit-Reset.

  • RESERVE_FAILED
    400

    Webhook-Reservierung hat zeitlich begrenzt, ungültige Daten zurückgegeben oder erforderliche Felder verpasst.

429 behandeln

Reduziere die Nutzung mit Retry-After Sekunden. Drehe keine Schlüssel, um Limits zu umgehen; das Limit gilt pro Schlüssel und ist für alle Verkäufer gleich.

Erfolgreiche Antworten enthalten X-RateLimit-Limit, X-RateLimit-Remaining und X-RateLimit-Reset.

Bereit zu automatisieren?

Erstelle einen Schlüssel in den Entwicklereinstellungen und verbinde Discord oder Telegram unter Benachrichtigungen.