three91 Quote API
Mit der API holt ein Programm (ERP, OmniFab, eigener Import) die Anfragen ab, die in three91 Quote ausgelesen und übernommen wurden: Kopfdaten, Positionen mit Material, Dicke, Menge und Maßen und die CAD-Datei jeder Position.
| Basis-URL | https://api.quote.three91.comTestumgebung: https://api.quote.stage.three91.com |
|---|---|
| Format | JSON (UTF-8), Zeiten in ISO 8601 mit Zeitzone, Längen in mm, Gewichte in kg |
| Zugriff | nur lesend, ein API-Key pro Programm, ausschließlich über HTTPS |
Die API liefert nur, was im Unternehmen übernommen wurde. Anfragen, die noch geprüft werden, sowie abgelehnte oder entfernte Positionen erscheinen nicht.
API-Key
Einen Key erzeugt ein Administrator in three91 Quote unter Einstellungen → Unternehmen → API-Keys. Der Key wird nur ein einziges Mal angezeigt. Er gehört zu genau einem Unternehmen und sieht nur dessen Daten. Dort sieht man auch, wann ein Key zuletzt benutzt wurde, und kann ihn widerrufen.
Das Programm schickt den Key bei jedem Aufruf im Header Authorization mit:
Authorization: Bearer t91_live_…
Behandeln Sie den Key wie ein Passwort: nicht in Quelltext oder Logdateien, nicht per E-Mail. Für jedes anbindende Programm sollte es einen eigenen Key geben, dann lässt sich jeder einzeln widerrufen.
GET /v1/ping
Prüft den Key. Antwortet mit dem Unternehmen, zu dem er gehört.
curl -H "Authorization: Bearer $THREE91_KEY" https://api.quote.three91.com/v1/ping
{ "ok": true, "tenant_id": "ca2e241e-90ab-4b02-8bc5-4580fa596040" }
GET /v1/requests
Übernommene Anfragen mit allen Positionen, sortiert nach der letzten Änderung, die älteste zuerst, seitenweise.
| Parameter | Bedeutung |
|---|---|
updated_since | optional, ISO 8601 (z. B. 2026-11-10T08:00:00Z): nur Anfragen, die zu diesem Zeitpunkt oder danach übernommen oder geändert wurden |
cursor | optional, der Wert next_cursor der vorigen Seite |
limit | optional, Anfragen pro Seite, 1–100, Standard 20 |
status | optional, derzeit nur accepted (Standard) |
curl -H "Authorization: Bearer $THREE91_KEY" \
"https://api.quote.three91.com/v1/requests?updated_since=2026-11-10T08:00:00Z&limit=20"
{
"data": [ { …Anfrage… }, { …Anfrage… } ],
"next_cursor": "MjAyNi0xMS0xMFQwODoxNToy…"
}
Ist next_cursor nicht null, gibt es weitere Seiten: denselben Aufruf mit cursor=<next_cursor> wiederholen, bis next_cursor null ist.
GET /v1/requests/{id}
Eine einzelne Anfrage, gleiches Format wie ein Eintrag in data. 404, wenn es sie nicht gibt, sie (noch) nicht übernommen wurde oder archiviert ist.
GET /v1/requests/{id}/positions/{position_id}/geometry
Die CAD-Datei der Position (DXF oder STEP) als Download. Die Adresse steht fertig in geometry_file.url; Name, Typ und Größe ebenfalls dort. Andere Dateien der Anfrage (E-Mail, Excel, PDF-Zeichnungen) liefert die API nicht aus.
curl -H "Authorization: Bearer $THREE91_KEY" -o AT-1201.dxf \
https://api.quote.three91.com/v1/requests/c60cee13-…/positions/b11809bb-…/geometry
Gibt es mehrere Dateien zu einem Teil, wählt die API in dieser Reihenfolge: eine DXF des Kunden, dann die STEP des Einzelteils (aus einer Baugruppe herausgetrennt), dann die STEP, wie sie kam, zuletzt eine von three91 abgeleitete DXF (z. B. aus einer PDF-Zeichnung).
Positionen ohne CAD-Datei haben geometry_file: null. Ist das Teil ein einfacher Zuschnitt, steht stattdessen die Form in shape (Rechteck, Kreis oder Ring), damit es sich als Makro anlegen lässt.
Neue Daten abholen
Die API arbeitet per Abruf. Das anbindende Programm braucht nur ausgehende HTTPS-Verbindungen und kann z. B. alle 5 Minuten fragen:
- Merken Sie sich den größten
updated_at-Wert der zuletzt verarbeiteten Anfrage (am Anfang leer). GET /v1/requests?updated_since=<dieser Wert>aufrufen und alle Seiten übernext_cursorabholen.- Jede Anfrage über ihre
idanlegen oder aktualisieren. Eine Anfrage kommt erneut, wenn sie oder eine ihrer Positionen in three91 geändert wurde. - Den neuen größten
updated_at-Wert speichern.
Weil updated_since den Zeitpunkt selbst einschließt, kommt die zuletzt verarbeitete Anfrage einmal doppelt. Der Import sollte daher über id (Anfrage) und positions[].id (Position) erkennen, was er schon hat.
Feld-Referenz: Anfrage
| Feld | Typ | Bedeutung |
|---|---|---|
id | UUID | feste Kennung der Anfrage in three91 |
reference | Text | Betreff der Anfrage-Mail |
customer_reference | Text | null | Anfrage- oder Bestellnummer des Kunden |
status | Text | accepted |
language | Text | null | Sprache der Anfrage (z. B. de) |
received_at · accepted_at · updated_at | Zeit | eingegangen · übernommen · letzte Änderung (Anfrage oder eine Position) |
customer | Objekt | null | aus Absender und Signatur gelesen: company, contact_name, contact_role, contact_email, phone, street, postal_code, city, country, vat_id, homepage. Eine Kundennummer aus Ihrem System kennt three91 nicht. Zuordnen lässt sich der Kunde über Firma, USt-IdNr. oder E-Mail. |
delivery_deadline · response_deadline | Objekt | date (ISO-Datum oder null) und text (wie in der Anfrage, z. B. „KW 48“) |
delivery_address · payment_terms · incoterms | Text | null | wenn in der Anfrage genannt |
operations | Liste | Arbeitsgänge aus dem Anfragetext: code, scope (all = alle Positionen, items = einzelne), text (Originalwortlaut), confidence |
notes | Liste von Texten | Hinweise zur ganzen Anfrage |
positions | Liste | die Positionen, siehe unten |
Feld-Referenz: Position
| Feld | Typ | Bedeutung |
|---|---|---|
id | UUID | feste Kennung der Position |
position_no | Zahl | laufende Nummer ab 1 |
item_no · drawing_no · article_no · revision | Text | null | Positions-, Zeichnungs-, Artikelnummer und Revision, wie in der Anfrage (oft nicht numerisch, z. B. AT-1201) |
part_name | Text | Teilename, sonst Zeichnungs- oder Positionsnummer; immer gefüllt |
quantity | Zahl | null | Stückzahl |
material | Objekt | text (z. B. S235JR, normalisiert) und category (mild_steel, structural, high_strength, wear_plate, pressure_vessel, alloy_steel, stainless, aluminum …) |
thickness_mm | Zahl | null | Blechdicke |
width_mm · length_mm | Zahl | null | Außenmaße (umschließendes Rechteck) |
shape | Objekt | null | nur ohne CAD-Datei: {type: "rectangle", width_mm, length_mm}, {type: "circle", diameter_mm} oder {type: "ring", outer_diameter_mm, inner_diameter_mm} |
cutting_length_mm | Zahl | null | Schnittlänge aller Konturen |
net_area_mm2 · surface_area_m2 | Zahl | null | Netto-Fläche |
weight_per_piece_kg · weight_total_kg | Zahl | null | Gewicht je Stück und gesamt |
bevels | Liste | Fasen: type (V, Y, X, K), angle_deg, depth_mm, length_mm |
operations | Liste | Arbeitsgänge für diese Position: code, text, from |
notes | Liste | Hinweise zur Position: text, category |
geometry_file | Objekt | null | name, type (dxf, step, stp), size_bytes, url (relativ zur Basis-URL) |
status | Text | Bearbeitungsstand in three91 (z. B. identified, priced) |
quality | Objekt | completeness (0–1), flags (offene Prüfhinweise), sources (woher Material, Dicke, Menge, Maße stammen, z. B. xlsx_csv, dxf_analysis), edited_by_user (von Hand korrigierte Felder) |
Jeder Wert steht direkt im Feld. Wie sicher er ist, steht getrennt in quality; ein einfacher Import kann quality ignorieren.
Fehler & Grenzen
| Status | Bedeutung |
|---|---|
400 | Parameter ungültig, z. B. updated_since kein ISO-Datum oder cursor beschädigt |
401 | kein Key, falscher Key oder widerrufener Key |
404 | Anfrage, Position oder Datei nicht vorhanden (oder nicht für diesen Key) |
429 | zu viele Aufrufe: höchstens 5 pro Sekunde und Key, kurze Spitzen bis 20. Nach der im Header Retry-After genannten Zahl von Sekunden erneut versuchen. |
5xx | Störung bei three91; später erneut versuchen |
Fehler kommen als JSON: { "detail": "…" }.
Beispiel einer Anfrage
{
"id": "c60cee13-7145-4484-8a09-68357c0babaf",
"reference": "Brennteile AT-1200 – please quote",
"customer_reference": "AT-1200",
"status": "accepted",
"language": "de",
"received_at": "2026-11-02T15:38:45.094887+00:00",
"accepted_at": "2026-11-02T18:20:19.468397+00:00",
"updated_at": "2026-11-02T18:20:19.468397+00:00",
"customer": {
"company": "Huber Anlagenbau GmbH", "contact_name": "Stefan Huber",
"contact_email": "s.huber@huber-anlagen.example", "city": "Linz", "country": "AT",
"contact_role": null, "phone": null, "street": null, "postal_code": null,
"vat_id": null, "homepage": null
},
"delivery_deadline": { "date": null, "text": "KW 48" },
"response_deadline": { "date": null, "text": null },
"delivery_address": null, "payment_terms": null, "incoterms": null,
"operations": [ { "code": "deburr", "scope": "all", "text": "alle Teile entgratet", "confidence": 0.9 } ],
"notes": [],
"positions": [
{
"id": "b11809bb-1cfd-4834-9d08-9a2d600172f2",
"position_no": 1,
"item_no": "AT-1201", "part_name": "AT-1201", "drawing_no": "AT-1201",
"article_no": null, "revision": null,
"quantity": 8,
"material": { "text": "S235JR", "category": "mild_steel" },
"thickness_mm": 12,
"width_mm": 400, "length_mm": 60,
"shape": null,
"cutting_length_mm": 920,
"net_area_mm2": 24000, "surface_area_m2": 0.024,
"weight_per_piece_kg": 2.26, "weight_total_kg": 18.08,
"bevels": [],
"operations": [ { "code": "deburr", "text": "alle Teile entgratet", "from": "request" } ],
"notes": [],
"geometry_file": {
"name": "AT-1201.dxf", "type": "dxf", "size_bytes": 14425,
"url": "/v1/requests/c60cee13-7145-4484-8a09-68357c0babaf/positions/b11809bb-1cfd-4834-9d08-9a2d600172f2/geometry"
},
"status": "identified",
"quality": {
"completeness": 0.8, "flags": [],
"sources": { "material": "xlsx_csv", "thickness_mm": "xlsx_csv", "quantity": "xlsx_csv", "width_mm": "dxf_analysis" },
"edited_by_user": []
}
}
]
}
Versionierung
Die Version steht im Pfad (/v1). Innerhalb von v1 kommen höchstens neue Felder hinzu; bestehende Felder werden nicht umbenannt, entfernt oder in ihrer Bedeutung geändert. Ein Import sollte unbekannte Felder daher ignorieren. Was sich nicht so ändern lässt, kommt als /v2, und v1 bleibt dann mit Vorlauf erhalten.
Fragen zur Anbindung: info@three91.com