NinjaBuy Business API
Basis-URL
Jede Route auf dieser Seite liegt unter einer Basis-URL. Die Shopify-App und alles, was du baust, rufen dieselben Routen auf, was die App kann, kann also auch dein Code.
https://www.ninjabuy.com/api/v1
Fragst du lieber einen KI-Assistenten? Dasselbe Konto funktioniert über MCP unter https://www.ninjabuy.com/mcp: KI-Assistenten (MCP).
- ImporteEin Link rein, die vollen Verkaufskosten raus.
- ProdukteWas du verkaufst und wo es gelistet ist.
- VariantenJede Option, verknüpft mit der SKU des Verkäufers.
- BeständeWas du gerade verkaufen kannst.
- Sync-RegelnWas passiert, wenn ein Verkäufer einen Preis ändert.
- BestellungenEin Verkauf, den wir kaufen, prüfen und versenden.
- Fulfillment-AufträgeDie Positionen, die in einem Paket rausgehen.
- SendungenPakete unterwegs, mit Sendungsverfolgung.
- GuthabenDas Geld, aus dem Bestellungen bezahlt werden.
- Webhook-EndpunkteWohin wir Events senden.
curl "https://www.ninjabuy.com/api/v1/balance" \
-H "Authorization: Bearer $NINJABUY_API_KEY" \
-H "NinjaBuy-Version: 2026-11"Authentifizierung
Sende bei jeder Anfrage einen API-Schlüssel als Bearer-Token. Schlüssel beginnen mit nb_. Während der Vorschau stellt unser Team sie aus: Sobald dein Business-Konto eingerichtet ist, schicken wir jeden Schlüssel einmal über einen Kanal deiner Wahl, mit den Scopes, die du angefragt hast. Bitte uns, einen zu widerrufen, und er funktioniert ab der nächsten Anfrage nicht mehr.
Bewahre Schlüssel auf deinem Server auf. Einen Schlüssel in einem Browser, einer App oder einem öffentlichen Repository kann jeder lesen, und er kann dein Guthaben ausgeben.
Eine App, die für andere NinjaBuy-Händler handelt, nutzt stattdessen OAuth 2.1: dynamische Client-Registrierung, den Authorization-Code-Flow mit PKCE (S256) und den eigenen Freigabebildschirm des Händlers. Ihr Access-Token kommt in denselben Header und funktioniert auf denselben Routen. Access-Tokens gelten eine Stunde; Refresh-Tokens verlängern sie sieben Tage lang. KI-Assistenten verbinden sich auf dieselbe Weise (MCP).
products:readscope- Importe, Produkte, Varianten und Sync-Regeln lesen.
products:writescope- Produkte importieren, bearbeiten, übertragen und löschen; Sync-Regeln ändern.
inventory:readscope- Bestände lesen.
orders:readscope- Bestellungen, Fulfillment-Aufträge und Sendungen lesen.
orders:writescope- Bestellungen anlegen, zurückhalten, freigeben und stornieren. Verbraucht dein Guthaben.
balance:readscope- Das Guthaben und seine Transaktionen lesen.
webhooks:writescope- Webhook-Endpunkte verwalten.
Ein Aufruf außerhalb der Scopes eines Schlüssels antwortet mit 403 insufficient-scope und nennt den benötigten Scope.
Authorization: Bearer nb_7Qk2...vX9eHTTP/2 401
{
"type": "https://www.ninjabuy.com/api/v1/problems/unauthorized",
"title": "Unauthorized",
"status": 401,
"detail": "The API key is missing, wrong, expired or revoked.",
"request_id": "req_7Hq2Lw9c"
}Versionierung
Der Pfad trägt die Hauptversion, /v1. Darin ändern datierte Versionen Felder und Verhalten. Fixiere die, gegen die du gebaut hast, mit dem NinjaBuy-Version-Header; jede Antwort nennt im selben Header die Version, die sie verwendet hat.
2026-11 ist die aktuelle Version, und sie ist eine Vorschau: Namen und Felder können sich noch ändern, bevor sie als stabil gilt. Jede Änderung steht im Changelog, und vor einer Änderung, die etwas kaputt machen könnte, informieren wir jeden Schlüsselinhaber per E-Mail.
Innerhalb einer Version fügen wir nur hinzu: neue Routen, neue optionale Parameter, neue Felder in Antworten und neue Event-Typen. Bau deinen Client so, dass er Felder ignoriert, die er nicht kennt.
GET /api/v1/orders
NinjaBuy-Version: 2026-11
HTTP/2 200
NinjaBuy-Version: 2026-11Anfragen und Antworten
- Sende JSON mit
Content-Type: application/json; Antworten sind JSON in UTF-8. Fehler sindapplication/problem+json. - Geld ist ein Objekt mit einem Dezimal-String und einer Währung:
{ "amount": "264.20", "currency": "CNY" }. Was NinjaBuy berechnet, ist in CN¥; deine Verkaufspreise sind in der Währung deines Shops. - IDs sind Strings mit einem Präfix, das ihre Art nennt (
prd_,ord_,shp_). Behandle sie als undurchsichtig. - Zeiten sind ISO 8601 in UTC. Länder sind zweistellige ISO-Codes.
- Jede Antwort trägt einen
X-Request-Id-Header, und jeder Fehler trägt dieselbe ID alsrequest_id. Gib sie an, wenn du uns schreibst.
{
"id": "ord_3n7q",
"created_at": "2026-11-01T09:14:02Z",
"total": { "amount": "264.20", "currency": "CNY" },
"suggested_price": { "amount": "49.99", "currency": "USD" }
}Paginierung
Listen antworten neueste zuerst, als data, has_more und cursor. Schick diesen Cursor für die nächste Seite zurück, solange has_more true ist. Ein Cursor funktioniert nur mit den Filtern, von denen er stammt.
limitinteger- 1 bis 100. Ohne Angabe 25.
cursorstring- Der Cursor der vorherigen Seite. Für die erste Seite weglassen.
curl "https://www.ninjabuy.com/api/v1/orders?limit=25&cursor=c_2v9kq" \
-H "Authorization: Bearer $NINJABUY_API_KEY" \
-H "NinjaBuy-Version: 2026-11"HTTP/2 200 OK
{
"data": [
{ "id": "ord_3n7q", "status": "checked" },
{ "id": "ord_3n6z", "status": "shipped" }
],
"has_more": true,
"cursor": "c_1q4ea"
}Rate-Limits
Limits gelten pro Konto, geteilt von allen Schlüsseln, OAuth-Tokens und der MCP-Verbindung. Jede Antwort sagt in den IETF-Headern RateLimit-Policy und RateLimit, wo du stehst; eine Ablehnung ist 429 rate-limited mit Retry-After in Sekunden.
| Zeitfenster | Was zählt |
|---|---|
| "create-links";q=30;w=60 | Aufrufe, die ein Angebot vom Marktplatz lesen: einen Import anlegen oder aktualisieren, ein Produkt übertragen. 30 pro Minute, geteilt mit der Links-API und MCP. |
| "default";q=120;w=60 | Alle anderen Aufrufe. 120 pro Minute. |
HTTP/2 429
Content-Type: application/problem+json
Retry-After: 12
RateLimit-Policy: "create-links";q=30;w=60
RateLimit: "create-links";r=0;t=12
{
"type": "https://www.ninjabuy.com/api/v1/problems/rate-limited",
"title": "Too many requests",
"status": 429,
"detail": "Try again in 12 seconds.",
"request_id": "req_7Hq2Lw9c"
}Idempotenz
Sende bei jedem POST einen Idempotency-Key (1 bis 255 druckbare ASCII-Zeichen; eine UUID ist ideal), und ein erneuter Versuch nach einem Timeout kann keine zweite Bestellung aufgeben. 24 Stunden lang liefert derselbe Schlüssel auf derselben Route mit demselben Body die erste Antwort Byte für Byte erneut, mit Idempotent-Replayed: true, ohne erneute Ausführung und ohne aufs Limit angerechnet zu werden.
- Derselbe Schlüssel mit anderem Body oder anderer Route:
422 idempotency-key-reused. - Die erste Anfrage läuft noch:
409 idempotency-key-in-progress, mitRetry-After. - Eine Ablehnung wegen Rate-Limit ist keine Antwort: Der Schlüssel bleibt frei, ein erneuter Versuch nach
Retry-Afterführt die Anfrage also aus.
Bestellungen tragen auch deine eigene external_id: Eine zweite Bestellung mit derselben wird mit 409 duplicate-order abgelehnt, egal mit welchem Schlüssel sie gesendet wurde.
POST /api/v1/orders
Idempotency-Key: 4f0c2b4e-9d1a-4e0f-b0a8-5d1d3c7e2f61
HTTP/2 201
Idempotent-Replayed: true
X-Request-Id: req_7Hq2Lw9cFehler
Fehler sind Problem-JSON (RFC 9457): type ist eine stabile URL zum Verzweigen, title benennt ihn, detail erklärt diesen Fall in Worten, die du anzeigen kannst, und request_id findet ihn in unseren Logs. Ein Body, der die Validierung nicht besteht, ergänzt errors, jeweils mit einem JSON-pointer auf das Feld.
| Status | Typ | Wann |
|---|---|---|
| 400 | bad-json | Der Body ist kein JSON. |
| 400 | bad-body | Ein Feld fehlt oder ist falsch; errors[] zeigt darauf. |
| 400 | bad-idempotency-key | Der Idempotency-Key ist leer, zu lang oder kein druckbares ASCII. |
| 401 | unauthorized | Der Schlüssel oder das Token fehlt, ist falsch, abgelaufen oder widerrufen. |
| 403 | insufficient-scope | Dem Schlüssel fehlt der Scope, den die Route braucht. |
| 404 | not-found | Kein solches Objekt in diesem Konto. IDs eines anderen Kontos antworten genauso. |
| 405 | method-not-allowed | Die Route existiert, aber nicht mit dieser Methode; Allow listet die, die sie annimmt. |
| 409 | duplicate-order | Eine Bestellung mit dieser external_id existiert; order nennt sie. |
| 409 | idempotency-key-in-progress | Die erste Anfrage mit diesem Schlüssel läuft noch. |
| 409 | invalid-state | Das Objekt kann das gerade nicht, zum Beispiel eine versendete Bestellung stornieren. |
| 415 | unsupported-media-type | Der Body ist nicht application/json. |
| 422 | idempotency-key-reused | Der Schlüssel wurde für eine andere Anfrage verwendet. |
| 422 | unprocessable | Gültiges JSON, mit dem wir nichts anfangen können: ein nicht lesbarer Link, eine ausverkaufte Variante. detail sagt, was. |
| 429 | rate-limited | Zu viele Aufrufe im Zeitfenster. Warte Retry-After Sekunden. |
| 500 | internal-error | Unser Fehler. Versuch es mit demselben Idempotency-Key erneut. |
| 503 | service-unavailable | Wir konnten den Schlüssel gerade nicht prüfen oder einen Shop nicht erreichen. Versuch es nach Retry-After erneut. |
HTTP/2 400
{
"type": "https://www.ninjabuy.com/api/v1/problems/bad-body",
"title": "Invalid request body",
"status": 400,
"detail": "1 field is invalid.",
"request_id": "req_7Hq2Lw9c",
"errors": [
{
"pointer": "/ship_to/country",
"detail": "Must be a two-letter country code."
}
]
}