Instnt PrintAPI

Instnt Print v1.0.0

Print labels en bonnen vanaf elk systeem dat een HTTP-verzoek kan doen. Geen driver, geen wachtrij op een pc: je stuurt wat erop moet, en er komt papier uit.

Alles gaat over sjablonen. Een sjabloon legt de vorm vast; jij stuurt alleen de gegevens die per keer verschillen.

In vijf minuten

Maak een sleutel aan in het dashboard onder Sleutels, kijk welke printers en templates je hebt, en stuur er iets naartoe.

# wat heb ik?
curl https://instntprint.com/v1/printers \
  -H "Authorization: Bearer $SLEUTEL"

# print een bon
curl -X POST https://instntprint.com/v1/jobs \
  -H "Authorization: Bearer $SLEUTEL" \
  -H "Idempotency-Key: bon-1043" \
  -H "Content-Type: application/json" \
  -d '{
    "printer": "Kassa balie",
    "template": "Kassabon",
    "data": {
      "bonnummer": "1043",
      "totaal": "17,45",
      "regels": [
        {"aantal": "2", "omschrijving": "Koffie", "bedrag": "6,40"}
      ]
    }
  }'

Zonder template kan ook — dan zijn het gewoon regels tekst op het label dat in de printer zit:

curl -X POST https://instntprint.com/v1/jobs \
  -H "Authorization: Bearer $SLEUTEL" \
  -H "Content-Type: application/json" \
  -d '{"lines": ["Magazijn 3", "Stelling B", "vak 12"]}'

Sleutels

Elke aanroep draagt een integratiesleutel in de Authorization-header. De sleutel bepaalt bij welke organisatie het hoort — niet iets in het verzoek zelf. Zo kan niemand met de printernaam van een ander papier laten komen.

Een sleutel die begint met lbl_test_ doet alles behalve printen: de template wordt gerenderd, de opdracht komt in je overzicht, maar er komt geen papier uit. Bouw daarmee, en zet hem om als het klopt.

Houd een sleutel op je eigen server. Alles wat in een webpagina of app staat, kan een gebruiker lezen.

Twee keer versturen

Netwerken haperen, en een kassa waar iemand twee keer op afrekenen drukt hoort niet twee bonnen te printen. Geef daarom bij elke opdracht een Idempotency-Key mee: een tekst die díe ene gebeurtenis beschrijft, zoals een bonnummer of een ordernummer.

Stuur je hem nog eens, dan krijg je het eerste antwoord terug met Idempotent-Replay: true in de header — en er komt niets uit de printer.

Als het misgaat

Fouten komen terug met een gewone HTTP-code en een uitleg in gewone taal. 404 is een naam die niet bestaat, 400 een verzoek dat niet klopt, 503 een printer die niet bereikbaar is. Die laatste is meestal tijdelijk: probeer het opnieuw met dezelfde idempotentiesleutel, dan kan er niets dubbel gebeuren.

Terug horen

Een opdracht wordt aangenomen en daarna geprint — soms meteen, soms een minuut later omdat de printer nog uit stond. Je kunt blijven vragen met GET /v1/jobs/{id}, maar makkelijker is het om ons te laten bellen.

Meld een adres aan met POST /v1/webhooks, of in het dashboard onder Meldingen. Je krijgt een geheim terug dat je bewaart.

POST /v1/webhooks
{"url": "https://jouwsysteem.nl/instnt",
 "events": ["job.done", "job.failed"]}

Wat er binnenkomt

POST https://jouwsysteem.nl/instnt
X-Instnt-Event: job.done
X-Instnt-Delivery: whd_…
X-Instnt-Timestamp: 1772100000
X-Instnt-Signature: sha256=…

{"event": "job.done",
 "created_at": 1772100000.4,
 "data": {"id": "job_…", "status": "done", "printer": "Kassa",
          "template": "Kassabon", "copies": 1, "error": null}}

De handtekening nakijken

Dat is één regel, en sla hem niet over: zonder controle kan iedereen die je adres raadt jouw systeem laten denken dat er iets geprint is.

# Python
verwacht = hmac.new(geheim.encode(),
                    tijdstip.encode() + b"." + lichaam,
                    hashlib.sha256).hexdigest()
klopt = hmac.compare_digest(f"sha256={verwacht}", handtekening)

Weiger ook wat ouder is dan een paar minuten — dan kan een onderschept bericht niet later opnieuw worden aangeboden.

Als jouw kant even weg is

Wij proberen het drie keer: meteen, na twintig seconden en na twee minuten. Alles wat met 2xx antwoordt geldt als aangekomen. Blijft het misgaan, dan zetten we de webhook na vijfentwintig mislukkingen op rij uit — je ziet in het dashboard waarom.

Antwoord snel en doe het werk daarna. Een ontvanger die er tien seconden over doet, houdt de volgende bezorging op.

Iemand anders laten printen

Het omgekeerde geval: een webshop of formulierendienst die wél een webhook kan versturen, maar waarvan je de uitgaande aanroep niet kunt aanpassen. Die stuurt zijn eigen JSON, in zijn eigen vorm.

Maak in het dashboard onder Meldingen een inkomend adres aan. Dat ziet eruit als /api/in/… met een lang, willekeurig stuk erachter — dat stuk is het geheim, dus deel het adres alleen met het systeem dat het nodig heeft. Je zegt erbij welk veld van hen bij welk veld van jouw template hoort:

{"klant":  "$.customer.name",
 "totaal": "$.total",
 "zaak":   "Café Instnt Coffee"}

Alles dat met $. begint is een pad in hún bericht — $.items[0].sku mag ook. De rest is een vaste waarde die er altijd bij hoort. Een pad dat niet bestaat valt weg in plaats van de hele afdruk te laten stuklopen.

Voor bonnen met artikelregels wijs je hun lijst aan, en zeg je per rij welk veld waar vandaan komt.

Zit er in hun bericht een id, order_id of reference, dan gebruiken we dat als idempotentiesleutel. Webhooks worden opnieuw verstuurd als het antwoord wegvalt — dat is juist hun kracht — en zonder sleutel levert dat een tweede bon op.

Endpoints

POST /v1/jobs

Print één label of bon

Stuur een sjabloonnaam met de gegevens die erin moeten, of lines met kale tekstregels.

Antwoordt met 202 en een opdracht-id: de printer kan uit staan, en daar mag jouw systeem niet op wachten. Wil je het tóch meteen weten, geef dan ?wait=true mee — dan komt er 200 zodra hij klaar is.

Parameters

NaamWaarWat het doet
waitquery

Wacht tot de printer klaar is.

Idempotency-Keyheader

Een tekst die deze ene gebeurtenis beschrijft — een bonnummer, een ordernummer. Stuur je hem twee keer, dan krijg je het eerste antwoord terug en komt er geen tweede bon uit. Onmisbaar zodra er een netwerk tussen zit.

Wat je stuurt

VeldSoortWat het doet
printerstring

De naam uit het dashboard. Heb je er één, dan mag dit weg.

templatestring

dataobject

De velden van het sjabloon. Een lijst (zoals de regels van een bon) zet je hier als array onder zijn eigen naam.

linesarray

Zonder sjabloon: kale tekstregels op het label dat in de printer zit.

copiesinteger

labelstring

Ander formaat dan wat er volgens de instellingen in zit.

cutboolean

Alleen bij bonprinters.

drawerboolean

Open de kassalade.

reverseboolean

Print het ontwerp een halve slag gedraaid, voor een printer die ingebouwd staat.

sampleboolean

Vul lege velden met aannemelijke inhoud. Voor een proefdruk.

idempotency_keystring

Voorbeeld

{
  "printer": "Kassa balie",
  "template": "Kassabon",
  "data": {
    "bonnummer": "1043",
    "totaal": "17,45",
    "regels": [
      {
        "aantal": "2",
        "omschrijving": "Koffie",
        "bedrag": "6,40"
      }
    ]
  }
}

Wat je terugkrijgt

CodeBetekenis
202

Aangenomen; staat in de rij.

200

Klaar (bij ?wait=true), of een herhaling van een opdracht die je al eerder stuurde.

404

Onbekende printer of sjabloon.

400

Er staat iets niet goed in het verzoek — bij meerdere printers zonder keuze bijvoorbeeld.

503

De printer is niet bereikbaar.

POST /v1/jobs/batch

Print een reeks

Elke rij wordt een label. Naar een bonprinter wordt de hele reeks juist één bon — veertig regels horen op één bon te staan, niet veertig bonnetjes te worden.

Elke rij krijgt een eigen sleutel, afgeleid van die van de reeks. Een herhaalde aanroep levert dus geen dubbele labels op, ook niet als hij halverwege afbrak.

Wat je stuurt

VeldSoortWat het doet
printerstring

templatestring

rows verplichtarray

Per rij de velden voor één label.

intostring

Bij een bon: onder welke lijstnaam de rijen het sjabloon in gaan.

idempotency_keystring

Voorbeeld

{
  "into": "regels"
}

Wat je terugkrijgt

CodeBetekenis
202

Aangenomen.

GET /v1/jobs/{id}

Hoe staat het met een opdracht

Parameters

NaamWaarWat het doet
idpath

Wat je terugkrijgt

CodeBetekenis
200

De opdracht.

404

Onbekende opdracht.

GET /v1/webhooks

Welke webhooks er staan

Wat je terugkrijgt

CodeBetekenis
200

De webhooks van jouw organisatie.

POST /v1/webhooks

Een webhook aanmelden

Wij bellen jouw adres zodra er iets gebeurt, in plaats van dat jij blijft vragen. Elk bericht is ondertekend met het geheim dat je hier terugkrijgt: X-Instnt-Signature is sha256= gevolgd door een HMAC-SHA256 over tijdstip.lichaam, met X-Instnt-Timestamp als tijdstip. Weiger wat ouder is dan een paar minuten.

Mislukt de bezorging, dan proberen we het nog twee keer: na twintig seconden en na twee minuten.

Wat je stuurt

VeldSoortWat het doet
url verplichtstring

events verplichtarray

Voorbeeld

{
  "url": "https://jouwsysteem.nl/instnt",
  "events": [
    "job.done",
    "job.failed"
  ]
}

Wat je terugkrijgt

CodeBetekenis
201

Aangemeld. Bewaar het geheim.

400

Het adres wijst naar een netwerk in plaats van naar buiten, of er is geen gebeurtenis gekozen.

DELETE /v1/webhooks/{id}

Een webhook afmelden

Parameters

NaamWaarWat het doet
idpath

Wat je terugkrijgt

CodeBetekenis
200

Afgemeld.

GET /v1/printers

Welke printers er zijn

Met kind erbij: label of receipt. Daarmee weet je waar een sjabloon naartoe kan zonder het aan de modelnaam te hoeven raden.

Wat je terugkrijgt

CodeBetekenis
200

De printers van jouw organisatie.

GET /v1/templates

Welke sjablonen er zijn

Met per sjabloon de velden die het verwacht, en welk soort invoer erbij hoort — genoeg om er een formulier van te bouwen zonder de vorm te kennen.

Wat je terugkrijgt

CodeBetekenis
200

De sjablonen van jouw organisatie.

POST /v1/preview

Een voorbeeld als afbeelding

Hetzelfde verzoek als printen, maar er komt een PNG terug in plaats van papier. Handig om te laten zien wat er gaat gebeuren.

Wat je terugkrijgt

CodeBetekenis
200

De afdruk als afbeelding.