Zum Inhalt springen
nuqo

Entwickler

Auf der nuqo-API aufbauen

Ihre eigenen Systeme lesen, was Ihr Betrieb in nuqo entschieden hat: finalisierte Angebote mit dem Arbeitsplan jeder Baugruppe und der Stückliste, die Ereignisse, die melden, wann ein Angebot finalisiert oder wieder geöffnet wird, und Ihre Teile, die Ihr ERP auch senden kann. Binden Sie Ihr ERP an, eine Fertigungsplanung, eine Auswertung oder ein eigenes Skript. JSON über HTTPS, angemeldet mit einem Schlüssel, den Ihr Admin in nuqo anlegt.

Basis-URLhttps://backend.nuqo.io/api/v1Versionv1AnmeldungBearer-Schlüsselopenapi.json

Die Referenz wird aus dem Code erzeugt, der die Anfragen beantwortet.

1Was die API kann

Mit der API lesen Ihre eigenen Systeme — ein ERP, die Middleware davor, eine Fertigungsplanung oder ein Skript — was Ihr Betrieb in nuqo entschieden hat, ohne dass jemand es vom Bildschirm abschreibt. Sie dient vor allem dem Lesen: Ihr System fragt, nuqo antwortet. Annehmen kann sie nur eines: Ihre Teile, aus Ihrem ERP.

Sie kann

  • Ihre finalisierten Angebote lesen: den Kopf, den Arbeitsplan jeder Baugruppe, die Stückliste.
  • Ihrem System melden, wann ein Angebot finalisiert oder wieder geöffnet wird — heute per Abfrage, bald per Webhook.
  • Die Teile lesen, die Ihr Betrieb in nuqo führt, vollständig und als Änderungen seit Ihrem letzten Abruf.
  • Ihre Teile aus Ihrem ERP annehmen: Preise, Bestand und Artikeldaten, in Stapeln.

Sie kann nicht

  • Entwürfe lesen. Der Preis eines Entwurfs ändert sich mit seinen Eingaben, deshalb antwortet er 409.
  • Angebote ändern. Über die API wird nichts angelegt, bearbeitet oder finalisiert.
  • In Ihre Systeme schreiben. nuqo beantwortet Ihre Aufrufe; bald meldet es Ihnen auch ein Ereignis, mehr nicht.

2Anmelden

  1. Schlüssel anlegen. In nuqo öffnet ein Inhaber oder Admin Ihres Betriebs Einstellungen → API-Schlüssel, gibt dem Schlüssel einen Namen (etwa „ERP-Middleware“) und legt ihn an. Der Schlüssel wird einmal angezeigt: nq_live_ und 43 Zeichen. Legen Sie ihn in Ihrem Geheimnisspeicher ab.
  2. Mit jeder Anfrage senden, als Authorization: Bearer nq_live_…. Kein Cookie, kein CSRF-Token. Jede Adresse beginnt mit https://backend.nuqo.io/api/v1.
  3. Prüfen. GET /organization antwortet den Betrieb, dem der Schlüssel gehört.
Anfrage · curl
curl https://backend.nuqo.io/api/v1/organization \
  -H "Authorization: Bearer $NUQO_KEY"
Antwort200
{ "id": 318, "name": "Example Assemblies Inc" }

Widerrufen Sie ihn unter Einstellungen → API-Schlüssel; er gilt sofort nicht mehr. Ein verlorener Schlüssel lässt sich nicht noch einmal anzeigen: legen Sie einen neuen an, stellen Sie Ihr System um und widerrufen Sie dann den alten.

Ein Schlüssel handelt als Ihr Betrieb, nie als eine Person, und sieht nur die Daten Ihres Betriebs. Jeder Schlüssel kann lesen. Ein Schlüssel, bei dem Ihr Admin „Darf auch Teile senden“ angekreuzt hat, kann Ihre Teile auch an nuqo senden: siehe Ihre Teile an nuqo senden.

3Finalisierte Angebote lesen

Die Liste

GET /quotes antwortet Ihre finalisierten Angebote, die älteste Finalisierung zuerst, 50 je Seite (limit bis 100). Blättern Sie mit next_cursor, solange has_more true ist. Dann behalten Sie den letzten next_cursor und fragen damit später wieder: er setzt nach dem letzten gesehenen Angebot fort, Sie bekommen also nur, was seither finalisiert wurde. Ein Cursor ist undurchsichtig — geben Sie ihn unverändert zurück, bauen Sie nie selbst einen. Um ab einem Datum zu beginnen, senden Sie stattdessen finalized_since; zusammen mit einem Cursor gesendet, gilt beides.

Anfrage · curl
curl "https://backend.nuqo.io/api/v1/quotes?finalized_since=2026-10-01T00:00:00Z&limit=50" \
  -H "Authorization: Bearer $NUQO_KEY"
Antwort200
{
  "quotes": [
    {
      "id": 5087,
      "number": "139-1",
      "revision": 1,
      "finalized_at": "2026-10-14T08:52:40.611093Z",
      "valid_until": null,
      "customer": null,
      "total": { "amount": 3920.5, "currency": "EUR" }
    },
    {
      "id": 5120,
      "number": "147-2",
      "revision": 2,
      "finalized_at": "2026-10-20T14:03:11.204518Z",
      "valid_until": "2026-11-19T22:59:59Z",
      "customer": { "id": 903, "name": "Sample Machines Ltd" },
      "total": { "amount": 21480, "currency": "EUR" }
    }
  ],
  "next_cursor": "MjAyNi0xMC0yMFQxNDowMzoxMS4yMDQ1MTgrMDA6MDB8NTEyMA",
  "has_more": false
}

Ein Angebot, das wieder geöffnet, überarbeitet und erneut finalisiert wurde, kommt später noch einmal, mit höherer revision und neuer number (147-2 nach 147-1): ersetzen Sie Ihre Kopie. Während es überarbeitet wird, steht es nicht in der Liste, und es zu lesen antwortet 409.

Ein Angebot und sein Arbeitsplan

GET /quotes/{quote_id} antwortet den Kopf, jede Baugruppe mit ihrem Arbeitsplan und die Stückliste. Die Namen, die nuqo vergibt (Baugruppen, Arbeitsplätze), kommen auf Englisch; mit ?lang=de auf Deutsch. Text aus den Unterlagen Ihres Kunden, etwa die Beschreibung einer Zeile, bleibt, wie er dort steht. Ein Entwurf, oder ein für eine Revision wieder geöffnetes Angebot, antwortet 409 quote_not_finalized. Ein finalisiertes Angebot ohne Arbeitsplan antwortet work_plan_available: false und keine Baugruppen. Jedes Feld steht in der Referenz; der Arbeitsplan ist der Teil, den die meisten Systeme zuerst abbilden:

op_number
integer

Die Arbeitsgangnummer: 10, 20, 30 … in der Reihenfolge, in der die Arbeit läuft.

work_center_id
string | null

Ihr eigener Code für den Arbeitsplatz, wie in nuqo eingerichtet (die Nummer Ihres ERP, wo Sie Ihre Arbeitsplätze nummerieren); null für einen Arbeitsgang ohne Arbeitsplatz — die Zeile bleibt, mit Name und Zeit.

name
string

Der Name des Arbeitsplatzes, bei einer Zeile ohne Arbeitsplatz der des Arbeitsgangs.

setup_seconds
number

Rüstzeit. Gerüstet wird einmal je Auftrag: dies ist der Anteil dieser Baugruppe daran, nach Stückzahl, auf der ersten Zeile, die ihn braucht — so ergibt die Rüstzeit über alle Baugruppen die, die das Angebot berechnet hat.

s
piece_seconds
number | null

Stückzeit, auf 0,01 gerundet; null, wo das Angebot keine angibt.

s / Stück
run_seconds
number

Die Laufzeit der Zeile für alle piece_count Stück. setup_seconds + run_seconds ist die Gesamtzeit der Zeile; nehmen Sie diese, statt die gerundete piece_seconds zurückzurechnen. Über die Zeilen einer Baugruppe ergibt run_seconds die Laufzeit, die das Angebot für sie berechnet hat.

s

Wie die Zeiten das ergeben, was das Angebot berechnet hat

Arbeitsgang 10 · Ablängen · Arbeitsplatz 1010 · piece_count 250

setup_seconds
180,00 s
run_seconds (250 × 42,50 s)
10.625,00 s
Gesamtzeit der Zeile
10.805,00 s
  • Nehmen Sie setup_seconds + run_seconds. Rechnen Sie die gerundete piece_seconds nicht zurück.
  • Gerüstet wird einmal je Auftrag. Jede Baugruppe trägt ihren Anteil nach Stückzahl, so ergibt die Rüstzeit über alle Baugruppen die, die das Angebot berechnet hat.
  • Über die Zeilen einer Baugruppe ergibt run_seconds die Laufzeit, die das Angebot für sie berechnet hat, und setup_seconds + run_seconds die Gesamtzeit der Baugruppe.
  • Eine Zeile mit work_center_id: null ist ein Arbeitsgang ohne Arbeitsplatz: sie behält Name und Zeit, es geht also keine Zeit verloren.

Eine Auftragsposition je Baugruppe

Jede Baugruppe nennt ihren Preis wie ihre Zeile im Angebots-PDF: unit_price für ein Stück (per: "pcs") und amount für die bestellte quantity, netto, in der Währung von total. amount ist quantity × unit_price, so stimmt eine Auftragsposition aus den dreien mit dem PDF überein. Der Rest des Angebots steht nur in total: Rüstkosten, die die Zeilen nicht tragen, Versand, Zuschläge, der Rabatt und bei einem älteren Angebot sein Gesamtaufschlag. Eine Baugruppe, von der keine Stückzahl bestellt ist, hat unit_price: null und amount: null.

Die Stückliste

parts nennt jede Zeile der Stückliste des Angebots, in ihrer Reihenfolge — auch eine Zeile, für die nichts gefunden wurde (part: null). quantity ist, was der ganze Auftrag von dem Teil braucht; ordered ist, was gekauft wird, in derselben Einheit: der Bedarf, aufgerundet auf die Packung, die Mindestbestellmenge und das Bestellintervall des Lieferanten. Bestellen Sie ordered. unit_price ist der Listenpreis des Lieferanten je Einheit, in der Währung, in der das Teil gekauft wird; line_total ist, was der Kauf von ordered kostet, in der Währung des Angebots.

Seit dem 29. Oktober 2026 nennt eine Zeile, die in Fuß oder Zoll gezählt wird, ihren unit_price je Fuß oder je Zoll; per sagt, welches von beiden ("ft" oder "in"). Vorher stand er je Meter. Das ist eine einmalige Ausnahme von der Regel, dass sich unter /v1/ keine Bedeutung ändert — wir haben sie gemacht, solange noch kein Integrator die API nutzt.

4Ereignisse

Ereignisse sagen Ihrem System, welches Angebot es holen und welchen Auftrag es anhalten soll. Fragen Sie GET /events etwa jede Minute ab und senden Sie dabei die ID des zuletzt verarbeiteten Ereignisses als after (beim ersten Mal 0).

Anfrage · curl
curl "https://backend.nuqo.io/api/v1/events?after=20870" \
  -H "Authorization: Bearer $NUQO_KEY"
Antwort200
{
  "data": [
    {
      "id": 20871,
      "type": "quote.reopened",
      "created_at": "2026-10-19T08:41:55.120334Z",
      "quote": { "id": 5120, "revision": 2 }
    },
    {
      "id": 20872,
      "type": "quote.finalized",
      "created_at": "2026-10-20T14:03:11.394120Z",
      "quote": { "id": 5120, "revision": 2 }
    }
  ],
  "next_after": 20872
}
quote.finalized

Holen Sie das Angebot. Eine höhere revision desselben Angebots ersetzt den Plan, den Sie auf der früheren aufgebaut haben. Eines, das Sie in dieser Revision schon haben, ist eine Wiederholung: überspringen Sie es.

quote.reopened

Halten Sie jeden Auftrag an, der auf dem Angebot aufbaut, bis zum nächsten quote.finalized. Inzwischen antwortet das Angebot 409 quote_not_finalized; behalten Sie Ihre Kopie der zuletzt finalisierten Revision. revision ist die neue, an der gearbeitet wird. Haben Sie keine Kopie des Angebots, gibt es nichts anzuhalten: warten Sie auf sein quote.finalized.

  • Speichern Sie next_after und senden Sie es beim nächsten Mal als after. Eine volle Seite (limit, standardmäßig 100) heißt, dass weitere warten: fragen Sie sofort noch einmal. Eine kürzere Seite ist vorerst das Ende.
  • Erkennen Sie Doppelte an der id. Zugestellt wird mindestens einmal: scheitert Ihr System zwischen dem Verarbeiten eines Ereignisses und dem Speichern seiner ID, bekommt es das Ereignis noch einmal.
  • Ignorieren Sie Typen, die Sie nicht kennen. Neue können hinzukommen.
  • Ereignisse werden 30 Tage aufbewahrt. Ein älteres after antwortet die ältesten noch vorhandenen Ereignisse; holen Sie über die Angebotsliste auf.

Webhooks

Kommt · noch nicht verfügbar

Statt abzufragen, kann Ihr System aufgerufen werden. Sie tragen in den Einstellungen eine HTTPS-Adresse ein; nuqo sendet jedes Ereignis per POST dorthin — mit demselben Inhalt wie ein Eintrag von data oben —, sobald ein Angebot finalisiert oder wieder geöffnet wird.

  • Signiert: ein HMAC-SHA256 über timestamp.body im Header Nuqo-Signature, mit einem Geheimnis, das einmal in den Einstellungen angezeigt wird.
  • 24 Stunden lang mit wachsendem Abstand wiederholt, bis Ihre Adresse mit 2xx antwortet. Erkennen Sie Doppelte an der id des Ereignisses.
  • Das Abfragen funktioniert weiter; beide lesen dieselben Ereignisse.

Ihre Antwort bestimmt das mit: siehe Annahme A1.

5Teile abgleichen

Ihre Teile an nuqo senden

Ihr ERP sendet nuqo seine Teile — Preise, Bestand, Artikeldaten —, statt dass jemand eine Datei exportiert und hochlädt. Sie landen auf Ihrer Preisliste ERP-Sync, die nuqo wie jede andere Ihrer Preislisten gegen die übrigen abwägt. Sie brauchen einen Schlüssel, den ein Inhaber oder Admin unter Einstellungen → API-Schlüssel mit angekreuztem „Darf auch Teile senden“ angelegt hat; nachträglich lässt sich das nicht ankreuzen, und ein Schlüssel ohne es antwortet 403.

  1. Einen Stapel senden, bis zu 1.000 Zeilen. Eine Zeile hat die Felder einer Zeile von GET /materials, unter denselben Namen; eine aus nuqo gelesene Zeile können Sie also unverändert zurücksenden. Pflicht sind mpn und manufacturer. Hersteller, mpn und supplier sagen, welches Teil eine Zeile ist; senden Sie also jedes Mal dieselben: eine Zeile ohne ihren Lieferanten ist ein anderes Teil. Jedes andere Feld, das eine Zeile weglässt oder als null sendet, behält den Wert, den nuqo hat, und ein Teil, das der Stapel weglässt, bleibt, wie es ist. valid_from und valid_to sind die Tage, für die die tiers der Zeile gelten; senden Sie sie also mit diesen Staffeln: Staffeln ohne sie gelten ab jetzt ohne Ende, Gültigkeitsdaten ohne Staffeln werden abgelehnt.

    Ein Teil, das Sie nicht mehr führen: senden Sie seine Zeile mit "removed": true, z. B. {"mpn": "1-968849-1", "manufacturer": "TE Connectivity", "supplier": {"name": "Example Supply", "sku": "ES-968849"}, "removed": true}. Es wird nicht mehr aus Ihrer Preisliste ERP-Sync kalkuliert; Ihre anderen Preislisten behalten ihren Eintrag. Hersteller, mpn und supplier sagen, welches Teil, wie bei jeder Zeile; die übrigen Felder der Zeile werden ignoriert. GET /materials liefert es weiter, mit prices_quotes false (nicht als obsolete: das ist ein Teil, das ein Nutzer gelöscht hat), und senden Sie seine Zeile wieder ohne removed, wird es wieder geführt. Entfernungen gelten nach den übrigen Zeilen des Stapels: ein Stapel, der dasselbe Teil sendet und entfernt, endet mit dem Teil entfernt.

    Anfrage · curl
    curl https://backend.nuqo.io/api/v1/materials/batches \
      -H "Authorization: Bearer $NUQO_KEY" \
      -H "Content-Type: application/json" \
      -d '{
      "rows": [
        {
          "org_sku": "A-10442",
          "mpn": "1-968849-1",
          "manufacturer": "TE Connectivity",
          "description": "Receptacle 2.8 mm, tin",
          "supplier": { "name": "Example Supply", "sku": "ES-968849" },
          "tiers": [{"min_qty": 1, "max_qty": null, "price": {"amount": 0.42, "currency": "EUR"}}],
          "valid_from": "2026-11-01",
          "valid_to": "2027-03-31",
          "quantity_in_stock": 4200
        }
      ]
    }'
    Antwort202
    { "batch_id": 88214 }

    Der ganze Stapel wird geprüft, bevor etwas davon übernommen wird. Eine abgelehnte Zeile antwortet 422, und nichts wird eingereiht; die Meldung nennt die erste fehlerhafte Zeile, z. B. rows[3]: tiers.0.price.amount: Input should be a valid number …. Korrigieren Sie sie und senden Sie den Stapel erneut.

  2. Den Stapel abfragen, alle paar Sekunden, solange sein status pending oder running ist.
    Anfrage · curl
    curl https://backend.nuqo.io/api/v1/materials/batches/88214 \
      -H "Authorization: Bearer $NUQO_KEY"
    Antwort200
    { "id": 88214, "status": "done", "summary": {"rows": 1, "imported": 1, "removed": 0, "not_imported": []} }

    done trägt die summary: die gesendeten rows, wie viele imported und removed wurden, und in not_imported jede Zeile, die nuqo nicht geschrieben hat, mit ihrer Stelle (index) in Ihrem Stapel und dem Grund: auch eine Entfernung eines Teils, das Ihre Liste nicht führt („nothing to remove“). failed heißt, die Übernahme ist abgebrochen: senden Sie den Stapel erneut. Das ist gefahrlos: eine zweimal gesendete Zeile schreibt dasselbe Teil, und eine zweimal gesendete Entfernung findet nichts mehr zu entfernen. Solange ein Stapel aussteht oder läuft, antwortet ein weiterer 409 batch_in_progress: senden Sie ihn, sobald die Abfrage done sagt.

  3. Zurücklesen mit GET /materials, changed_since auf eine Minute vor dem Senden des Stapels gesetzt, damit nichts fehlt, wenn Ihre Uhr vorgeht: jedes seither geänderte Teil, die des Stapels darunter, wie nuqo sie führt, mit nuqos listing_id und part_id. Eine Zeile, die nichts geändert hat, kommt nicht zurück. Eine Änderung wird geliefert, sobald sie 3 Minuten alt ist.
    Anfrage · curl
    curl "https://backend.nuqo.io/api/v1/materials?changed_since=2026-10-30T08:00:00Z" \
      -H "Authorization: Bearer $NUQO_KEY"
    Antwort200
    {
      "materials": [
        {
          "listing_id": 918377,
          "part_id": 4410951,
          "catalogue": { "id": 131, "name": "ERP-Sync" },
          "org_sku": "A-10442",
          "mpn": "1-968849-1",
          "manufacturer": "TE Connectivity",
          "description": "Receptacle 2.8 mm, tin",
          "category_leaf": null,
          "supplier": { "name": "Example Supply", "sku": "ES-968849" },
          "tiers": [{"min_qty": 1, "max_qty": null, "price": {"amount": 0.42, "currency": "EUR"}}],
          "unit_price": { "amount": 0.42, "currency": "EUR", "per": "pcs" },
          "valid_from": "2026-11-01",
          "valid_to": "2027-03-31",
          "order_unit": null,
          "content_unit": "pcs",
          "no_cu_per_ou": 1,
          "price_quantity": 1,
          "minimum_order_quantity": null,
          "order_multiple": null,
          "lead_time_days": null,
          "quantity_in_stock": 4200,
          "notes": null,
          "prices_quotes": true,
          "status": "active",
          "changed_at": "2026-10-30T08:00:41.208113Z"
        }
      ],
      "next_cursor": "MjAyNi0xMC0zMFQwODowMDo0MS4yMDgxMTMrMDA6MDB8NDQxMDk1MXw5MTgzNzc",
      "has_more": false
    }

Die erste vollständige Übernahme ist dasselbe, viele Male: senden Sie Stapel von bis zu 1.000 Zeilen nacheinander, jeden bis done abgefragt, bevor der nächste kommt.

Ihre Teile aus nuqo lesen

GET /materials antwortet die Zeilen Ihres Reiters Materialien in nuqo, mit denselben Werten, die am längsten unveränderte zuerst.

  1. Zuerst ein vollständiger Abruf: ohne changed_since, mit include_removed=true, blätternd mit next_cursor, solange has_more true ist. Ein Teil, das sich während des Abrufs ändert, kommt weiter hinten noch einmal, mit den neuen Werten: ersetzen Sie Ihre Kopie.
  2. Dann die Änderungen: behalten Sie den letzten next_cursor und fragen damit wieder (mit include_removed=true). Sie bekommen die seither angelegten, bearbeiteten, neu bepreisten oder gelöschten Teile. Eine Änderung wird geliefert, sobald sie 3 Minuten alt ist.
  3. Nachts ein vollständiger Abruf mit Abgleich. Er findet die wenigen Änderungen, die keine Abfrage der Änderungen zeigen kann: ein Teil aus nuqos globalem Katalog, das Sie aus Ihren Teilen entfernt haben, ist weg statt markiert, und nuqos eigene Pflege (ein zusammengeführter Herstellername, eine neu zugeordnete Kategorie) ändert den Änderungszeitpunkt eines Teils nicht.
Anfrage · curl
curl "https://backend.nuqo.io/api/v1/materials?include_removed=true&limit=100" \
  -H "Authorization: Bearer $NUQO_KEY"
Antwort200
{
  "materials": [
    {
      "listing_id": 918204,
      "part_id": 4410273,
      "catalogue": { "id": 112, "name": "Example Supply 2026" },
      "org_sku": "300-118",
      "mpn": "EX-H4",
      "manufacturer": "Example Housings",
      "description": "Housing, 4 pole, black",
      "category_leaf": "Connectors > Housings",
      "supplier": { "name": "Example Supply", "sku": "ES-H4-01" },
      "tiers": [
        { "min_qty": 1, "max_qty": 499, "price": {"amount": 1.58, "currency": "EUR"} },
        { "min_qty": 500, "max_qty": null, "price": {"amount": 1.42, "currency": "EUR"} }
      ],
      "unit_price": { "amount": 1.58, "currency": "EUR", "per": "pcs" },
      "valid_from": "2026-01-01",
      "valid_to": "2026-12-31",
      "order_unit": null,
      "content_unit": "pcs",
      "no_cu_per_ou": 1,
      "price_quantity": 1,
      "minimum_order_quantity": 100,
      "order_multiple": 50,
      "lead_time_days": 14,
      "quantity_in_stock": 2400,
      "notes": null,
      "prices_quotes": true,
      "status": "active",
      "changed_at": "2026-10-21T16:20:05.774812Z"
    }
  ],
  "next_cursor": "MjAyNi0xMC0yMVQxNjoyMDowNS43NzQ4MTIrMDA6MDB8NDQxMDI3Mw",
  "has_more": false
}

Die Identität eines Teils ist part_id. org_sku ist Ihre Artikelnummer, wo Sie eine gesetzt haben, aber zwei Teile können sie teilen, sie ist also kein Schlüssel. Ein vollständiger Abruf ist eine Anfrage je 100 Teile: 24.000 Teile sind 240 Anfragen, etwa zwei Minuten innerhalb des Limits.

6Fehler, Limits und Änderungen

Ein Fehler antwortet einen festen code für Ihr Programm und eine message für Menschen, deren Wortlaut sich ändern kann.

Antwort
{
  "error": { "code": "quote_not_finalized", "message": "The quote is a draft or a revision in progress." }
}
StatusCodeWann
400invalid_requestEin Parameter ist fehlerhaft oder außerhalb des Bereichs, oder ein gesendeter Stapel enthält keine Zeilen
401api_key_requiredinvalid_api_keyKein Schlüssel, oder ein unbekannter oder widerrufener
403organization_inactiveinsufficient_scopeIhr Betrieb ist inaktiv; dem Schlüssel fehlt die Berechtigung (ein Schlüssel, der nur liest, sendet Teile). Eine reine Textantwort error code: 1010kommt dagegen von Cloudflare, das vor nuqo steht: Es lehnt den User-Agent Ihres Programms ab, senden Sie also einen eigenen (etwa den Namen Ihres Systems)
404not_foundGibt es in Ihrem Betrieb nicht (das eines anderen Betriebs auch nicht), oder die Adresse gibt es nicht
405method_not_allowedDie Adresse nimmt diese Methode nicht an; der Header Allow nennt die, die sie annimmt
409quote_not_finalizedbatch_in_progresscatalogue_retiredDas Angebot ist ein Entwurf oder wird überarbeitet; ein Stapel Ihrer Teile wird noch übernommen (senden Sie Ihren erneut, sobald er fertig ist); Ihre Preisliste ERP-Sync ist in nuqo zurückgezogen
413batch_too_largeEin Stapel von mehr als 1.000 Teilen
422invalid_rowEin Teil Ihres Stapels wird abgelehnt; die Meldung nennt das erste mit seiner Stelle, z. B. rows[3]: tiers.0.price.amount: …
429rate_limitedÜber dem Limit; warten Sie die Sekunden aus dem Header Retry-After

Außer der Antwort 1010 oben trägt nur ein Serverfehler, 500, diesen Inhalt nicht. Behandeln Sie jede Antwort ohne code nach ihrem Status. Wiederholen Sie einen 500, einen 502–504 oder einen Netzwerkfehler mit wachsender Wartezeit (etwa 2, 4, 8 … Sekunden, fünfmal), dann geben Sie bis zum nächsten Lauf auf.

Limit

120 Anfragen pro Minute je Schlüssel, über alle Adressen. Darüber antwortet die API 429 rate_limited mit einem Header Retry-After, der die ganzen Sekunden bis zum nächsten Versuch nennt.

Wie sich die API ändert

  • Ergänzungen kommen ohne Ankündigung. Ein neues Feld, eine neue Adresse, ein neuer Parameter oder Ereignistyp kann jederzeit erscheinen. Ihr System ignoriert, was es nicht liest.
  • Ein Feld geht langsam. Es wird hier und in einem Header der Antwort als veraltet markiert, in den Neuigkeiten angekündigt und frühestens 6 Monate später entfernt.
  • Ein echter Bruch kommt als /v2/ neben /v1/, das weiterläuft, während Sie umstellen. Eine Prüfung bei jeder unserer Änderungen weist alles andere zurück.

7Was wir über Ihr System annehmen

Wir haben v1 auf diesen Annahmen gebaut. Sagen Sie uns, welche für Ihr System zutreffen, und korrigieren Sie die anderen — die Nummern genügen.

  1. A1
    Ereignisse

    Ihr System fragt GET /events regelmäßig ab, oder es kann HTTPS-Aufrufe aus dem Internet annehmen.

    Wenn nicht: Sagen Sie uns, was zutrifft. Nimmt es eingehende HTTPS-Aufrufe an, rücken Webhooks auf unserer Liste nach oben.

  2. A2
    Anmeldung

    Ein fester Schlüssel im Authorization-Header ist für Ihr System in Ordnung.

    Wenn nicht: Sagen Sie uns, was es braucht (z. B. OAuth2 Client Credentials).

  3. A3
    Angebote

    Ihr ERP führt eine Baugruppe unter Ihrer eigenen Nummer dafür, shop_part_number, und sie ist auf jedem Angebot gesetzt, das Sie finalisieren.

    Wenn nicht: Sagen Sie uns, unter welcher Nummer Ihr ERP einen Arbeitsplan ablegt.

  4. A4
    Arbeitsplan

    Eine Zeile des Arbeitsplans ohne Arbeitsplatz (work_center_id: null, mit Name und Zeit) ist annehmbar.

    Wenn nicht: Jede Zeile muss einen Arbeitsplatz nennen, und wir brauchen von Ihnen einen Standard-Arbeitsplatz.

  5. A5
    Revisionen

    Eine höhere Revision eines Angebots ersetzt den Plan, den Sie dafür haben.

    Wenn nicht: Sagen Sie uns, wie Ihr ERP Revisionen nebeneinander führt.

  6. A6
    Teile abgleichen

    Ihr ERP führt bei Preisen, Bestand, Lieferzeit und Artikeldaten.

    Wenn nicht: Nennen Sie die Gruppen, bei denen nuqo führen soll.

  7. A7
    Teile abgleichen

    Ihre Artikelnummer (org_sku) ist Ihr Schlüssel für ein Teil.

    Wenn nicht: Sagen Sie uns, welches Feld es ist.

  8. A8
    Teile abgleichen

    Einige tausend Teile, einmal am Tag abgeglichen, und in nuqo angelegte Teile müssen in Ihrem ERP keine neuen Artikel werden.

    Wenn nicht: Nennen Sie uns die Zahl der Teile, wie oft, und ob neue Teile zurückfließen sollen.

Kopieren Sie die Liste als Text, markieren Sie bei jeder, ob sie zutrifft, und schicken Sie sie Ihrem Ansprechpartner bei nuqo.

Referenz

Erzeugt aus dem Code, der die Anfragen beantwortet, kann sie also nicht von dem abweichen, was die API sendet. Alle Zeiten sind Sekunden; jeder Zeitstempel ist ISO 8601 in UTC; Geld trägt seine Währung. Ignorieren Sie Felder, die Sie nicht lesen: neue können hinzukommen. Adressen stehen hier vollständig; die Basis-URL oben endet schon auf /api/v1.

GET/api/v1/organizationDer Betrieb des Schlüssels

Der Betrieb, dem der Schlüssel gehört. Damit prüfen Sie einen Schlüssel.

Anmeldung
Bearer-Schlüssel · Berechtigung read
Limit
Gemeinsam, 120 pro Minute je Schlüssel

Antworten

200
Organization
401
api_key_requiredinvalid_api_key
403
organization_inactiveinsufficient_scope
405
method_not_allowed
429
rate_limited

Felder der Antwort · 200 · Organization

id
integer

Die ID Ihres Betriebs in nuqo.

name
string

Der Name Ihres Betriebs.

Beispiel

Anfrage · curl
curl https://backend.nuqo.io/api/v1/organization \
  -H "Authorization: Bearer $NUQO_KEY"
Antwort200
{ "id": 318, "name": "Example Assemblies Inc" }
GET/api/v1/quotesFinalisierte Angebote, älteste zuerst

Ihre finalisierten Angebote, die älteste Finalisierung zuerst, nur die Köpfe: den Arbeitsplan eines Angebots lesen Sie mit GET /quotes/{quote_id}. Blättern Sie mit next_cursor, solange has_more true ist, dann behalten Sie den letzten next_cursor und fragen damit regelmäßig: er antwortet nur, was seither finalisiert wurde. Ein überarbeitetes und erneut finalisiertes Angebot kommt später noch einmal, mit höherer Revision. Jedes finalisierte Angebot wird gelistet, auch wenn Ihre Organisation finalisierte Angebote nicht mit allen Mitgliedern teilt.

Anmeldung
Bearer-Schlüssel · Berechtigung read
Limit
Gemeinsam, 120 pro Minute je Schlüssel

Abfrageparameter

finalized_since
timestamp

Nur Angebote, die zu oder nach diesem Zeitpunkt finalisiert wurden. Ohne Zeitzone gilt UTC.

cursor
string

Ein next_cursor, den diese API geantwortet hat, unverändert zurückgegeben: liest nach der letzten Zeile weiter, auf der er endete. Bauen Sie nie selbst einen.

limit
integer · 1–100 · Standard 50

Wie viele höchstens geantwortet werden.

Antworten

200
QuoteList
400
invalid_request
401
api_key_requiredinvalid_api_key
403
organization_inactiveinsufficient_scope
405
method_not_allowed
429
rate_limited

Felder der Antwort · 200 · QuoteList

quotes[]
Liste von QuoteHeader

Diese Seite, die älteste Finalisierung zuerst.

id
integer

Die ID des Angebots, die GET /quotes/{id} nimmt.

number
string

Die Nummer, die Ihr Kunde liest, <Angebotsnummer>-<Revision>, z. B. "42-3".

revision
integer

1 für die erste; zählt hoch, jedes Mal wenn das Angebot wieder geöffnet und erneut finalisiert wird.

finalized_at
timestamp

Wann diese Revision finalisiert wurde.

UTC
valid_until
timestamp | null

Wann das Angebot abläuft.

UTC
customer
Customer | null

Für wen das Angebot ist; null, wenn es niemanden nennt.

id
integer

Die ID Ihres Kunden in nuqo.

name
string

Die Firma des Kunden, sonst der Name des Kontakts.

total
Money

Die Summe des Angebots wie finalisiert, netto, in der Währung, in der nuqo es kalkuliert hat (das PDF kann sie umgerechnet zeigen).

amount
number | null

Der Betrag, netto, in currency; null, wo es keinen gibt (ein nie kalkuliertes Angebot, eine Zeile ohne Angebot eines Lieferanten).

currency
string

Währungscode nach ISO 4217, z. B. "EUR".

next_cursor
string | null

Undurchsichtig: geben Sie ihn unverändert als cursor zurück, um nach dem letzten Angebot dieser Seite weiterzulesen. Auf einer Seite ohne Angebote ist es der gesendete cursor (null, wenn keiner gesendet wurde).

has_more
boolean

Ob die nächste Seite schon Angebote enthält; false, sobald Sie aufgeholt haben.

Beispiel

Anfrage · curl
curl https://backend.nuqo.io/api/v1/quotes \
  -H "Authorization: Bearer $NUQO_KEY"
Antwort200
{
  "quotes": [
    {
      "id": 5087,
      "number": "139-1",
      "revision": 1,
      "finalized_at": "2026-10-14T08:52:40.611093Z",
      "valid_until": null,
      "customer": null,
      "total": { "amount": 3920.5, "currency": "EUR" }
    },
    {
      "id": 5120,
      "number": "147-2",
      "revision": 2,
      "finalized_at": "2026-10-20T14:03:11.204518Z",
      "valid_until": "2026-11-19T22:59:59Z",
      "customer": { "id": 903, "name": "Sample Machines Ltd" },
      "total": { "amount": 21480, "currency": "EUR" }
    }
  ],
  "next_cursor": "MjAyNi0xMC0yMFQxNDowMzoxMS4yMDQ1MTgrMDA6MDB8NTEyMA",
  "has_more": false
}
GET/api/v1/quotes/{quote_id}Ein finalisiertes Angebot

Ein finalisiertes Angebot: sein Kopf, jede Baugruppe mit ihrem Arbeitsplan, und seine Stückliste. Ein finalisiertes Angebot ohne Arbeitsplan antwortet work_plan_available: false und assemblies: []. Ein Entwurf, oder ein für eine Revision wieder geöffnetes Angebot, antwortet 409 quote_not_finalized: behalten Sie Ihre Kopie der zuletzt finalisierten Revision. Jedes finalisierte Angebot wird geliefert, auch wenn Ihre Organisation finalisierte Angebote nicht mit allen Mitgliedern teilt.

Anmeldung
Bearer-Schlüssel · Berechtigung read
Limit
Gemeinsam, 120 pro Minute je Schlüssel

Pfadparameter

quote_idPflicht
integer

Die ID des Angebots, aus der Liste oder einem Ereignis.

Abfrageparameter

lang
"de" | "en" · Standard "en"

Die Sprache der name-Felder.

Antworten

200
Quote
400
invalid_request
401
api_key_requiredinvalid_api_key
403
organization_inactiveinsufficient_scope
404
not_found
405
method_not_allowed
409
quote_not_finalized
429
rate_limited

Felder der Antwort · 200 · Quote

id
integer

Die ID des Angebots, die GET /quotes/{id} nimmt.

number
string

Die Nummer, die Ihr Kunde liest, <Angebotsnummer>-<Revision>, z. B. "42-3".

revision
integer

1 für die erste; zählt hoch, jedes Mal wenn das Angebot wieder geöffnet und erneut finalisiert wird.

finalized_at
timestamp

Wann diese Revision finalisiert wurde.

UTC
valid_until
timestamp | null

Wann das Angebot abläuft.

UTC
customer
Customer | null

Für wen das Angebot ist; null, wenn es niemanden nennt.

id
integer

Die ID Ihres Kunden in nuqo.

name
string

Die Firma des Kunden, sonst der Name des Kontakts.

total
Money

Die Summe des Angebots wie finalisiert, netto, in der Währung, in der nuqo es kalkuliert hat (das PDF kann sie umgerechnet zeigen).

amount
number | null

Der Betrag, netto, in currency; null, wo es keinen gibt (ein nie kalkuliertes Angebot, eine Zeile ohne Angebot eines Lieferanten).

currency
string

Währungscode nach ISO 4217, z. B. "EUR".

work_plan_available
boolean

Ob das Angebot einen Arbeitsplan hat; false für ein nie kalkuliertes Angebot oder eines, das auf nuqos älterem Arbeitszeitmodell kalkuliert wurde.

assemblies[]
Liste von Assembly

Die Baugruppen des Angebots, in der Reihenfolge des Reiters Arbeitsplan; leer, wenn es keinen Arbeitsplan gibt.

id
string | null

Die Referenz der Baugruppe im Angebot; null bei einem Angebot ohne Baugruppen (ein Plan für den ganzen Auftrag).

name
string

Der Name der Baugruppe, sonst ihre Referenz.

shop_part_number
string | null

Ihre eigene Nummer für die Baugruppe, unter der Ihr ERP den Plan ablegt; null, wenn nicht gesetzt.

quantity
integer | null

Die bestellte Stückzahl dieser Baugruppe; null, wo das Angebot keine je Baugruppe angibt.

Stück
piece_count
integer | null

Die Stückzahl, auf die sich piece_seconds jeder Zeile bezieht (über die die Laufzeit berechnet wurde); null, wo ihre Arbeitsgänge über verschiedene Stückzahlen berechnet wurden.

Stück
work_plan[]
Liste von WorkPlanRow

Eine Zeile je Besuch eines Arbeitsplatzes, in der Reihenfolge, in der die Arbeit läuft.

op_number
integer

Die Arbeitsgangnummer: 10, 20, 30 … in der Reihenfolge, in der die Arbeit läuft.

work_center_id
string | null

Ihr eigener Code für den Arbeitsplatz, wie in nuqo eingerichtet (die Nummer Ihres ERP, wo Sie Ihre Arbeitsplätze nummerieren); null für einen Arbeitsgang ohne Arbeitsplatz — die Zeile bleibt, mit Name und Zeit.

name
string

Der Name des Arbeitsplatzes, bei einer Zeile ohne Arbeitsplatz der des Arbeitsgangs.

setup_seconds
number

Rüstzeit. Gerüstet wird einmal je Auftrag: dies ist der Anteil dieser Baugruppe daran, nach Stückzahl, auf der ersten Zeile, die ihn braucht — so ergibt die Rüstzeit über alle Baugruppen die, die das Angebot berechnet hat.

s
piece_seconds
number | null

Stückzeit, auf 0,01 gerundet; null, wo das Angebot keine angibt.

s / Stück
run_seconds
number

Die Laufzeit der Zeile für alle piece_count Stück. setup_seconds + run_seconds ist die Gesamtzeit der Zeile; nehmen Sie diese, statt die gerundete piece_seconds zurückzurechnen. Über die Zeilen einer Baugruppe ergibt run_seconds die Laufzeit, die das Angebot für sie berechnet hat.

s
unit_price
UnitPrice | null

Der Preis eines Stücks der Baugruppe, netto, wie ihn die Zeile im Angebots-PDF druckt (per ist "pcs"), in der Währung von total. amount ist quantity × unit_price, wie im PDF (bei einem vor Oktober 2026 kalkulierten Angebot kann eine Zeile um einen Cent abweichen, wie sie gedruckt wurde). Null, wo das PDF keine Zeile für sie druckt (keine Stückzahl bestellt).

amount
number | null

Der Betrag, netto, in currency; null, wo es keinen gibt (ein nie kalkuliertes Angebot, eine Zeile ohne Angebot eines Lieferanten).

currency
string

Währungscode nach ISO 4217, z. B. "EUR".

per
string | null

Die Einheit, für die amount gilt: "pcs" für ein Stück, "m" für einen Meter, "ft" für einen Fuß, "in" für einen Zoll, "kg" für ein Kilogramm; null für jede andere Einheit (der Betrag gilt, schlagen Sie die Zeile nach). Die Liste wächst nur durch Ergänzung.

amount
Money | null

Die Zeile der Baugruppe im Angebots-PDF: ihr Preis für die bestellte Stückzahl, netto. Die übrigen Posten des Angebots stehen nur in total: Rüstkosten, die die Zeile nicht trägt, Versand, Zuschläge, der Rabatt und bei einem vor September 2026 kalkulierten Angebot sein Gesamtaufschlag. Null, wo unit_price null ist.

amount
number | null

Der Betrag, netto, in currency; null, wo es keinen gibt (ein nie kalkuliertes Angebot, eine Zeile ohne Angebot eines Lieferanten).

currency
string

Währungscode nach ISO 4217, z. B. "EUR".

parts[]
Liste von PartLine

Eine je Stücklistenzeile, in der Reihenfolge der Stückliste, gefunden oder nicht.

Die 12 Felder von PartLine zeigen
line_number
integer | null

Die Nummer der Zeile in der Stückliste.

spec_id
string | null

Die ID der Zeile im Angebot.

requested
RequestedPart

Was die Stückliste Ihres Kunden verlangt.

mpn
string | null

Die Herstellerteilenummer laut Stückliste.

manufacturer
string | null

Der Hersteller laut Stückliste.

internal_part_number
string | null

Die eigene Nummer Ihres Kunden für das Teil.

description
string | null

Die Beschreibung der Zeile.

status
string | null

Wo die Materialsuche der Zeile endete: selected, direct_match, manual (ein Nutzer hat das Teil gewählt), customer_supplied (der Kunde stellt es bei), not_found, unavailable, needs_search, pending; null, wo die Zeile nie gesucht wurde. Neue Werte können hinzukommen.

is_substitute
boolean

Ob das gewählte Teil ein anderer Artikel ist, als die Zeile verlangt (eine vom Kunden freigegebene Alternative ist es nicht).

part
ChosenPart | null

Das zum Kauf gewählte Teil; null, wenn für die Zeile nichts gefunden wurde.

mpn
string

Die Herstellerteilenummer des gewählten Teils.

manufacturer
string | null

Sein Hersteller.

name
string | null

Sein Produktname.

shop_part_number
string | null

Ihre eigene Nummer für das Teil, aus Ihrem Eintrag dazu in nuqo; null, wenn nicht gesetzt.

supplier
Supplier | null

Bei wem das Teil gekauft wird; null, wenn die Zeile kein Angebot eines Lieferanten hat.

name
string | null

Bei wem das Teil gekauft wird, wie nuqo ihn nennt (z. B. "DigiKey"); ein Teil aus Ihrem eigenen Katalog heißt "<Kurzname>-Teile".

sku
string | null

Die Bestellnummer des Lieferanten für das Teil.

quantity
Quantity

Wie viel von dem Teil der ganze Auftrag braucht.

value
number | null

Die Menge, in unit; null, wenn die Zeile kein Angebot eines Lieferanten hat.

unit
string | null

Ihre Einheit: "pcs" oder das Maß der Zeile ("m", "mm", …).

ordered
Quantity

Wie viel von dem Teil für den ganzen Auftrag gekauft wird, in derselben Einheit wie quantity: was er braucht, aufgerundet auf die Packung, die Mindestbestellmenge und das Bestellintervall des Lieferanten. value null bei einem vor Oktober 2026 finalisierten Angebot, dessen Aufzeichnung sie nicht nennt.

value
number | null

Die Menge, in unit; null, wenn die Zeile kein Angebot eines Lieferanten hat.

unit
string | null

Ihre Einheit: "pcs" oder das Maß der Zeile ("m", "mm", …).

unit_price
UnitPrice | null

Der Listenpreis des Lieferanten je Einheit, in der Währung, in der das Teil gekauft wird; null, wo das Angebot keinen Preis je Einheit nennt (nur den einer Packung), und bei einem vor Oktober 2026 finalisierten Angebot, dessen Aufzeichnung ihn nicht nennt.

amount
number | null

Der Betrag, netto, in currency; null, wo es keinen gibt (ein nie kalkuliertes Angebot, eine Zeile ohne Angebot eines Lieferanten).

currency
string

Währungscode nach ISO 4217, z. B. "EUR".

per
string | null

Die Einheit, für die amount gilt: "pcs" für ein Stück, "m" für einen Meter, "ft" für einen Fuß, "in" für einen Zoll, "kg" für ein Kilogramm; null für jede andere Einheit (der Betrag gilt, schlagen Sie die Zeile nach). Die Liste wächst nur durch Ergänzung.

line_total
Money

Was der Kauf von ordered kostet, in der Währung des Angebots, zum Listenpreis vor Ihren Rabatten und Aufschlägen, die Mehrmenge über quantity hinaus eingeschlossen; amount null, wenn die Zeile kein Angebot eines Lieferanten hat.

amount
number | null

Der Betrag, netto, in currency; null, wo es keinen gibt (ein nie kalkuliertes Angebot, eine Zeile ohne Angebot eines Lieferanten).

currency
string

Währungscode nach ISO 4217, z. B. "EUR".

lead_time_days
integer | null

Tage bis zur Lieferung: die Lieferzeit des Lieferanten, seine Lieferzeit ab Lager, wenn der Bestand den Auftrag deckt, oder die Standard-Lieferzeit Ihrer Preisliste, wo deren Zeile keine nennt; null, wenn unbekannt.

Tage

Beispiel

Anfrage · curl
curl https://backend.nuqo.io/api/v1/quotes/5120 \
  -H "Authorization: Bearer $NUQO_KEY"
Antwort200
{
  "id": 5120,
  "number": "147-2",
  "revision": 2,
  "finalized_at": "2026-10-20T14:03:11.204518Z",
  "valid_until": "2026-11-19T22:59:59Z",
  "customer": { "id": 903, "name": "Sample Machines Ltd" },
  "total": { "amount": 21480, "currency": "EUR" },
  "work_plan_available": true,
  "assemblies": [
    {
      "id": "A1",
      "name": "Control cabinet assembly",
      "shop_part_number": "KS-40-117",
      "quantity": 250,
      "piece_count": 250,
      "work_plan": [
        {
          "op_number": 10,
          "work_center_id": "1010",
          "name": "Cutting",
          "setup_seconds": 180,
          "piece_seconds": 42.5,
          "run_seconds": 10625
        },
        {
          "op_number": 20,
          "work_center_id": "2030",
          "name": "Crimping",
          "setup_seconds": 300,
          "piece_seconds": 96.12,
          "run_seconds": 24030
        },
        {
          "op_number": 30,
          "work_center_id": null,
          "name": "Special labeling",
          "setup_seconds": 0,
          "piece_seconds": 3.6,
          "run_seconds": 900
        }
      ],
      "unit_price": { "amount": 84.32, "currency": "EUR", "per": "pcs" },
      "amount": { "amount": 21080, "currency": "EUR" }
    }
  ],
  "parts": [
    {
      "line_number": 1,
      "spec_id": "k7p2q9",
      "requested": {
        "mpn": "EX-H4",
        "manufacturer": "Example Housings",
        "internal_part_number": "C-100",
        "description": "Housing, 4 pole"
      },
      "status": "selected",
      "is_substitute": false,
      "part": {
        "mpn": "EX-H4",
        "manufacturer": "Example Housings",
        "name": "Housing 4p",
        "shop_part_number": "300-118"
      },
      "supplier": { "name": "Example Supply", "sku": "ES-H4-01" },
      "quantity": { "value": 480, "unit": "pcs" },
      "ordered": { "value": 500, "unit": "pcs" },
      "unit_price": { "amount": 1.42, "currency": "EUR", "per": "pcs" },
      "line_total": { "amount": 710, "currency": "EUR" },
      "lead_time_days": 14
    },
    {
      "line_number": 2,
      "spec_id": "m3r8t1",
      "requested": {
        "mpn": null,
        "manufacturer": null,
        "internal_part_number": "C-215",
        "description": "Cable tie, black, 100 mm"
      },
      "status": "not_found",
      "is_substitute": false,
      "part": null,
      "supplier": null,
      "quantity": { "value": null, "unit": "pcs" },
      "ordered": { "value": null, "unit": "pcs" },
      "unit_price": null,
      "line_total": { "amount": null, "currency": "EUR" },
      "lead_time_days": null
    }
  ]
}
GET/api/v1/eventsWas mit Ihren Angeboten geschah

Die Ereignisse Ihres Betriebs nach der gesendeten ID, das älteste zuerst: ein Angebot finalisiert, oder für eine Revision wieder geöffnet. Speichern Sie next_after und senden Sie es beim nächsten Mal als after; eine volle Seite heißt, dass weitere warten. Ereignisse werden 30 Tage aufbewahrt.

Anmeldung
Bearer-Schlüssel · Berechtigung read
Limit
Gemeinsam, 120 pro Minute je Schlüssel

Abfrageparameter

after
integer · ≥ 0 · Standard 0

Nur Ereignisse mit höherer ID antworten.

limit
integer · 1–100 · Standard 100

Wie viele höchstens geantwortet werden.

Antworten

200
EventList
400
invalid_request
401
api_key_requiredinvalid_api_key
403
organization_inactiveinsufficient_scope
405
method_not_allowed
429
rate_limited

Felder der Antwort · 200 · EventList

data[]
Liste von Event

Die Ereignisse nach after, das älteste zuerst.

id
integer

Die ID des Ereignisses: erkennen Sie Doppelte daran, und senden Sie die zuletzt verarbeitete als after.

type
string

quote.finalized oder quote.reopened. Ignorieren Sie einen Typ, den Sie nicht kennen: neue können hinzukommen.

created_at
timestamp

Wann es geschah.

UTC
quote
EventQuote

Das Angebot, dem es geschah.

id
integer

Die ID des Angebots: lesen Sie es mit GET /quotes/{id}.

revision
integer

quote.finalized: die finalisierte Revision. quote.reopened: die neue Revision, an der gearbeitet wird.

next_after
integer

Was Sie beim nächsten Mal als after senden: die ID des letzten Ereignisses, oder das gesendete after, wenn nichts Neues da ist.

Beispiel

Anfrage · curl
curl https://backend.nuqo.io/api/v1/events \
  -H "Authorization: Bearer $NUQO_KEY"
Antwort200
{
  "data": [
    {
      "id": 20871,
      "type": "quote.reopened",
      "created_at": "2026-10-19T08:41:55.120334Z",
      "quote": { "id": 5120, "revision": 2 }
    },
    {
      "id": 20872,
      "type": "quote.finalized",
      "created_at": "2026-10-20T14:03:11.394120Z",
      "quote": { "id": 5120, "revision": 2 }
    }
  ],
  "next_after": 20872
}
GET/api/v1/materialsIhre Teile, die am längsten unveränderten zuerst

Die Zeilen Ihres Reiters Materialien in nuqo, seitenweise. Blättern Sie mit next_cursor, solange has_more true ist, dann behalten Sie den letzten next_cursor und fragen damit regelmäßig: er antwortet nur die seither geänderten Teile. Eine Änderung wird geliefert, sobald sie 3 Minuten alt ist.

Anmeldung
Bearer-Schlüssel · Berechtigung read
Limit
Gemeinsam, 120 pro Minute je Schlüssel

Abfrageparameter

changed_since
timestamp

Nur Teile, deren Zeile sich zu oder nach diesem Zeitpunkt geändert hat. Ohne Zeitzone gilt UTC.

include_removed
boolean · Standard false

true antwortet auch die Teile, die ein Nutzer gelöscht hat, mit status "obsolete".

cursor
string

Ein next_cursor, den diese API geantwortet hat, unverändert zurückgegeben: liest nach der letzten Zeile weiter, auf der er endete. Bauen Sie nie selbst einen.

limit
integer · 1–100 · Standard 50

Wie viele höchstens geantwortet werden.

Antworten

200
MaterialList
400
invalid_request
401
api_key_requiredinvalid_api_key
403
organization_inactiveinsufficient_scope
405
method_not_allowed
429
rate_limited

Felder der Antwort · 200 · MaterialList

materials[]
Liste von Material

Diese Seite, die am längsten unveränderte zuerst.

listing_id
integer

Die ID dieser Zeile in nuqo: ihre Identität, solange sie besteht. Zwei Ihrer Kataloge, die ein Teil führen, sind zwei Zeilen mit einer part_id, jede mit eigener listing_id und eigenem Preis.

part_id
integer

Die ID des Teils in nuqo, solange es besteht.

catalogue
Catalogue | null

Aus welchem Ihrer Kataloge der Preis der Zeile stammt; null für einen eingegebenen Preis oder ein aus nuqos Katalog übernommenes Teil, und sobald der Katalog gelöscht ist.

id
integer

Die ID des Katalogs in nuqo.

name
string

Sein Name, wie nuqo ihn zeigt: der, den Sie ihm gegeben haben, sonst Lieferant und Ausgabe (z. B. "Stocko 2025").

org_sku
string | null

Ihre eigene Artikelnummer dafür; null, wenn nicht gesetzt. Zwei Teile können sie teilen, sie ist also kein Schlüssel.

mpn
string | null

Die Herstellerteilenummer.

manufacturer
string | null

Der Hersteller, mit dem Namen aus dem Reiter Materialien.

description
string

Seine Beschreibung, sonst sein Name; "", wenn es keins von beiden hat.

category_leaf
string | null

Die Kategorie, unter der nuqo es führt, als Pfad, z. B. "Protection > Sleeving"; solange nuqo es unter keiner führt, die Kategorie aus Ihrer Datei.

supplier
Supplier

Wo es gekauft wird.

name
string | null

Bei wem das Teil gekauft wird, wie nuqo ihn nennt (z. B. "DigiKey"); ein Teil aus Ihrem eigenen Katalog heißt "<Kurzname>-Teile".

sku
string | null

Die Bestellnummer des Lieferanten für das Teil.

tiers[]
Liste von PriceBreak

Ihr Preis, ein Eintrag je Mengenstaffel; leer, wenn ohne Preis.

min_qty
integer

Die kleinste Menge, für die der Preis gilt.

max_qty
integer | null

Die größte; null für kein oberes Ende.

price
Money

Der Preis für price_quantity Bestelleinheiten.

amount
number | null

Der Betrag, netto, in currency; null, wo es keinen gibt (ein nie kalkuliertes Angebot, eine Zeile ohne Angebot eines Lieferanten).

currency
string

Währungscode nach ISO 4217, z. B. "EUR".

unit_price
UnitPrice | null

Der Preis der ersten Staffel je Inhaltseinheit (per ist die eigene Inhaltseinheit des Teils, nie umgerechnet); null, wenn ohne Preis.

amount
number | null

Der Betrag, netto, in currency; null, wo es keinen gibt (ein nie kalkuliertes Angebot, eine Zeile ohne Angebot eines Lieferanten).

currency
string

Währungscode nach ISO 4217, z. B. "EUR".

per
string | null

Die Einheit, für die amount gilt: "pcs" für ein Stück, "m" für einen Meter, "ft" für einen Fuß, "in" für einen Zoll, "kg" für ein Kilogramm; null für jede andere Einheit (der Betrag gilt, schlagen Sie die Zeile nach). Die Liste wächst nur durch Ergänzung.

valid_from
string | null

Der erste Tag, an dem die Preise der Staffel gelten; null, wenn kein Beginn angegeben ist.

valid_to
string | null

Der letzte Tag, an dem die Preise der Staffel gelten; null, wenn kein Ende angegeben ist.

order_unit
string | null

Als was eins bestellt wird, z. B. "stick", "reel"; null, wenn nicht angegeben.

content_unit
string | null

Die Einheit, die eine Bestelleinheit enthält ("pcs", "m", "ft", "kg"); null, wenn nicht angegeben oder keine davon.

no_cu_per_ou
number

Wie viele Inhaltseinheiten eine Bestelleinheit enthält.

price_quantity
number

Für wie viele Bestelleinheiten der Preis einer Staffel gilt. Der Preis einer Staffel kauft price_quantity Bestelleinheiten zu je no_cu_per_ou Inhaltseinheiten.

minimum_order_quantity
integer | null

Die kleinste Bestellmenge, in Bestelleinheiten.

order_multiple
integer | null

Die Schrittweite einer Bestellung, in Bestelleinheiten.

lead_time_days
integer | null

Lieferzeit.

Tage
quantity_in_stock
integer | null

Bestand wie zuletzt angegeben; null, wenn unbekannt.

notes
string | null

Ihre Notizen dazu.

prices_quotes
boolean

Ob dieser Preis neue Angebote kalkulieren darf: false für einen Eintrag, den ein Import abgeschaltet hat, oder einen aus einer Preisliste, die ein Nutzer zurückgezogen hat; das Teil und seine letzten Preise werden weiter geliefert. Wo zwei Ihrer Preislisten dasselbe Teil bepreisen, können beide true sein: Angebote nutzen eine davon, die Ihre Einkaufsregel zuerst reiht, sonst eine, deren Gültigkeit nicht abgelaufen ist, sonst die zuletzt bepreiste.

status
string

"active", oder "obsolete" für ein Teil, das ein Nutzer gelöscht hat (geliefert mit include_removed=true); ein Teil aus nuqos globalem Katalog, das Sie hinzugefügt haben, kann auch "soft_deleted" oder "confirmed_gone" sein, sobald sein Lieferant es nicht mehr führt.

changed_at
timestamp

Wann sich die Zeile zuletzt geändert hat: danach ist die Liste sortiert.

UTC
next_cursor
string | null

Undurchsichtig: geben Sie ihn unverändert als cursor zurück, um nach dem letzten Teil dieser Seite weiterzulesen. Auf einer Seite ohne Teile ist es der gesendete cursor (null, wenn keiner gesendet wurde).

has_more
boolean

Ob die nächste Seite schon Teile enthält; false, sobald Sie aufgeholt haben.

Beispiel

Anfrage · curl
curl https://backend.nuqo.io/api/v1/materials \
  -H "Authorization: Bearer $NUQO_KEY"
Antwort200
{
  "materials": [
    {
      "listing_id": 918204,
      "part_id": 4410273,
      "catalogue": { "id": 112, "name": "Example Supply 2026" },
      "org_sku": "300-118",
      "mpn": "EX-H4",
      "manufacturer": "Example Housings",
      "description": "Housing, 4 pole, black",
      "category_leaf": "Connectors > Housings",
      "supplier": { "name": "Example Supply", "sku": "ES-H4-01" },
      "tiers": [
        { "min_qty": 1, "max_qty": 499, "price": {"amount": 1.58, "currency": "EUR"} },
        { "min_qty": 500, "max_qty": null, "price": {"amount": 1.42, "currency": "EUR"} }
      ],
      "unit_price": { "amount": 1.58, "currency": "EUR", "per": "pcs" },
      "valid_from": "2026-01-01",
      "valid_to": "2026-12-31",
      "order_unit": null,
      "content_unit": "pcs",
      "no_cu_per_ou": 1,
      "price_quantity": 1,
      "minimum_order_quantity": 100,
      "order_multiple": 50,
      "lead_time_days": 14,
      "quantity_in_stock": 2400,
      "notes": null,
      "prices_quotes": true,
      "status": "active",
      "changed_at": "2026-10-21T16:20:05.774812Z"
    }
  ],
  "next_cursor": "MjAyNi0xMC0yMVQxNjoyMDowNS43NzQ4MTIrMDA6MDB8NDQxMDI3Mw",
  "has_more": false
}
POST/api/v1/materials/batchesIhre Teile senden

Bis zu 1000 Ihrer Teile, auf Ihre Preisliste ERP-Sync in nuqo: ein neues Teil wird angelegt, eines, das Sie schon gesendet haben, aktualisiert, ein Feld, das Sie weglassen, behält seinen Wert, und eine Zeile mit removed: true nimmt ihr Teil von der Liste. Antwortet sofort die ID des Stapels; fragen Sie GET /materials/batches/{id} ab, bis er fertig ist. Ein Stapel nach dem anderen: senden Sie mehr Teile als aufeinanderfolgende Stapel.

Anmeldung
Bearer-Schlüssel · Berechtigung catalogue:write
Limit
Gemeinsam, 120 pro Minute je Schlüssel

Inhalt der Anfrage · MaterialBatch

rows[]
Liste von MaterialRow

Ihre Teile, höchstens 1000; senden Sie mehr als aufeinanderfolgende Stapel. Ein Teil, das Sie weglassen, bleibt, wie es ist.

org_sku
string | null

Ihre eigene Artikelnummer dafür.

mpn
string

Die Herstellerteilenummer. Mit manufacturer und supplier sagt sie, welches Ihrer Teile die Zeile ist.

manufacturer
string

Der Hersteller, wie Ihr System ihn nennt oder wie GET /materials ihn antwortet. Einen, den nuqo noch nicht kennt, legt nuqo so an, wie Sie ihn schreiben.

description
string | null

Seine Beschreibung.

supplier
Supplier | null

Wo Sie es kaufen: Name und Bestellnummer Ihres Lieferanten. Lassen Sie es weg für ein Teil, das Sie selbst fertigen oder lagern.

name
string | null

Bei wem das Teil gekauft wird, wie nuqo ihn nennt (z. B. "DigiKey"); ein Teil aus Ihrem eigenen Katalog heißt "<Kurzname>-Teile".

sku
string | null

Die Bestellnummer des Lieferanten für das Teil.

tiers[]
Liste von PriceBreak | null

Ihr Preis, ein Eintrag je Mengenstaffel, alle in einer Währung; die Staffeln dürfen sich nicht überschneiden.

min_qty
integer

Die kleinste Menge, für die der Preis gilt.

max_qty
integer | null

Die größte; null für kein oberes Ende.

price
Money

Der Preis für price_quantity Bestelleinheiten.

amount
number | null

Der Betrag, netto, in currency; null, wo es keinen gibt (ein nie kalkuliertes Angebot, eine Zeile ohne Angebot eines Lieferanten).

currency
string

Währungscode nach ISO 4217, z. B. "EUR".

valid_from
string | null

Der erste Tag, an dem die Preise der Staffel gelten. Mit der Staffel gesendet; eine Staffel ohne ihn gilt ab sofort.

valid_to
string | null

Der letzte Tag, an dem die Preise der Staffel gelten. Mit der Staffel gesendet; eine Staffel ohne ihn gilt ohne Ende.

order_unit
string | null

Als was eins bestellt wird, z. B. "stick", "reel".

content_unit
string | null

Die Einheit, die eine Bestelleinheit enthält.

no_cu_per_ou
number | null

Wie viele Inhaltseinheiten eine Bestelleinheit enthält.

price_quantity
number | null

Für wie viele Bestelleinheiten der Preis einer Staffel gilt.

minimum_order_quantity
integer | null

Die kleinste Bestellmenge, in Bestelleinheiten.

order_multiple
integer | null

Die Schrittweite einer Bestellung, in Bestelleinheiten.

lead_time_days
integer | null

Lieferzeit.

Tage
quantity_in_stock
integer | null

Bestand; 0 heißt nicht auf Lager.

notes
string | null

Ihre Notizen dazu.

removed
boolean | null

true: Sie führen es nicht mehr, und es wird nicht mehr aus Ihrer Preisliste ERP-Sync kalkuliert. Ihre anderen Preislisten behalten ihren Eintrag. mpn und manufacturer sagen, welches Teil, supplier, welches von zwei Angeboten dafür; die übrigen Felder der Zeile werden ignoriert. GET /materials liefert es weiter, mit prices_quotes false; senden Sie es wieder ohne removed, wird es wieder geführt. Entfernungen gelten nach den übrigen Zeilen des Stapels: ein Stapel, der ein Teil sendet und entfernt, endet mit dem Teil entfernt.

Antworten

202
BatchCreated
400
invalid_request
401
api_key_requiredinvalid_api_key
403
organization_inactiveinsufficient_scope
405
method_not_allowed
409
batch_in_progresscatalogue_retired
413
batch_too_large
422
invalid_row
429
rate_limited

Felder der Antwort · 202 · BatchCreated

batch_id
integer

Die ID des Stapels: fragen Sie damit GET /materials/batches/{id} ab.

Beispiel

Anfrage · curl
curl https://backend.nuqo.io/api/v1/materials/batches \
  -H "Authorization: Bearer $NUQO_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "rows": [
    {
      "org_sku": "A-10442",
      "mpn": "1-968849-1",
      "manufacturer": "TE Connectivity",
      "description": "Receptacle 2.8 mm, tin",
      "supplier": { "name": "Example Supply", "sku": "ES-968849" },
      "tiers": [
        { "min_qty": 1, "max_qty": 999, "price": {"amount": 0.42, "currency": "EUR"} },
        { "min_qty": 1000, "max_qty": null, "price": {"amount": 0.31, "currency": "EUR"} }
      ],
      "valid_from": "2026-11-01",
      "valid_to": "2027-03-31",
      "order_unit": "bag",
      "content_unit": "pcs",
      "no_cu_per_ou": 100,
      "price_quantity": 1,
      "minimum_order_quantity": 1,
      "order_multiple": 1,
      "lead_time_days": 5,
      "quantity_in_stock": 4200,
      "notes": null
    },
    { "mpn": "FLRY-B 0.5", "manufacturer": "Coroplast", "lead_time_days": 10, "quantity_in_stock": 0 },
    {
      "mpn": "GR-1100",
      "manufacturer": "Example Grommets",
      "supplier": { "name": "digikey.com", "sku": null }
    },
    {
      "mpn": "1-968850-1",
      "manufacturer": "TE Connectivity",
      "supplier": { "name": "Example Supply", "sku": "ES-968850" },
      "removed": true
    }
  ]
}'
Antwort202
{ "batch_id": 88214 }
GET/api/v1/materials/batches/{batch_id}Ein Stapel Ihrer Teile

Wo ein Stapel steht, den Sie gesendet haben, und sobald er fertig ist, was er bewirkt hat.

Anmeldung
Bearer-Schlüssel · Berechtigung catalogue:write
Limit
Gemeinsam, 120 pro Minute je Schlüssel

Pfadparameter

batch_idPflicht
integer

Die batch_id, die POST /materials/batches antwortete.

Antworten

200
Batch
401
api_key_requiredinvalid_api_key
403
organization_inactiveinsufficient_scope
404
not_found
405
method_not_allowed
429
rate_limited

Felder der Antwort · 200 · Batch

id
integer

Die ID des Stapels.

status
string

"pending" (wartet), "running", "done" oder "failed" (es wird nichts mehr übernommen; senden Sie ihn erneut). Fragen Sie ab, bis done oder failed.

summary
BatchSummary | null

Was der Stapel bewirkt hat, sobald er fertig ist; bis dahin null, und bei einem fehlgeschlagenen Stapel.

rows
integer

Wie viele Zeilen der Stapel hatte.

imported
integer

Wie viele davon jetzt in nuqo sind, neu oder aktualisiert.

removed
integer

Wie viele davon ein Teil von Ihrer Preisliste ERP-Sync genommen haben (removed: true).

not_imported[]
Liste von RowNotImported

Die Zeilen, die nicht übernommen wurden, jede mit Grund — auch eine Entfernung, die nichts zu entfernen fand.

index
integer

Die Stelle der Zeile in rows, ab 0.

mpn
string | null

Ihre Herstellerteilenummer.

reason
string

Warum sie nicht übernommen wurde, für Menschen; der Wortlaut kann sich ändern.

Beispiel

Anfrage · curl
curl https://backend.nuqo.io/api/v1/materials/batches/88214 \
  -H "Authorization: Bearer $NUQO_KEY"
Antwort200
{
  "id": 88214,
  "status": "done",
  "summary": {
    "rows": 4,
    "imported": 2,
    "removed": 1,
    "not_imported": [
      {
        "index": 2,
        "mpn": "GR-1100",
        "reason": "'digikey.com' is on a domain several markets' storefronts share — name the storefront you buy from"
      }
    ]
  }
}

Noch nicht in der Referenz: Webhooks. Sie erscheinen hier, erzeugt wie der Rest, an dem Tag, an dem sie freigeschaltet werden.