Create a USB Print Job
POST https://www.expedy.fr/api/v2/devices/{device_uid}/usb/{usb_port}/print
Sends a print job to a printer plugged into one of the USB ports of your Expedy device.
Base URL: https://www.expedy.fr/api/v2
Authentication
This endpoint requires an Authorization header containing your SID and TOKEN, separated by a single colon.
Authorization: <SID>:<TOKEN>
Authorization: 9F3K7Q2WZ1ABCDEF:b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5e6
⚠️ This is not a Bearer token. Do not add a
BearerorBasicprefix — send the rawSID:TOKENvalue.
Both values are available in the Expedy console under API. All requests must be made over HTTPS (TLS).
Path parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
device_uid |
string |
Yes | UID of the device, found in the console under Machines (e.g. OOBBZ100PI). |
usb_port |
string |
Yes | The USB port the printer is plugged into: 1, 2, 3 or 4, matching the ports shown in the console. Use /usb/scan/read to see what is connected to each one. |
A port only accepts jobs once a printer has been detected on it and configured. If the port is empty, or the printer on it was never configured, the job is rejected.
Request body
Content-Type: application/json
| Parameter | Type | Required | Description |
|---|---|---|---|
usb_msg |
string |
Yes | The content to print, built with the receipt layout tags (<C>, <BOLD>, <IMG>, <QR>, <CUT/>, …). Plain text, QR codes, images, or a PDF URL. |
notification_url |
string |
No | A URL the print service calls once it has handed the job to the printer. Use it to close the loop in your own system instead of assuming the job printed. |
origin |
string |
No | A free-form label to tag the source of the job (a URI, an app name, a department…). Useful for filtering and debugging in your logs. |
printer_han |
string |
No | The script to compose the receipt in: cn Chinese, kr Korean, jp Japanese. Omit it for Latin scripts. See Asian characters. |
Request example:
{
"usb_msg": "<C><BOLD>ORDER #1234</BOLD></C>\n<C>Table 7</C>\n--------------------------------\n1 x Burger\n2 x Fries\n<CUT/>",
"notification_url": "https://www.example.com/print-callback",
"origin": "pos-kitchen-01"
}
cURL example:
curl -X POST "https://www.expedy.fr/api/v2/devices/OOBBZ100PI/usb/1/print" \
-H "Authorization: <SID>:<TOKEN>" \
-H "Content-Type: application/json" \
-d '{"usb_msg":"<C><BOLD>Hello</BOLD></C><CUT/>","origin":"my-app"}'
Asian characters
Chinese, Japanese and Korean need printer_han, set to the script you are printing.
| Value | Script |
|---|---|
cn |
Chinese |
kr |
Korean |
jp |
Japanese |
1 is still accepted as a synonym of cn.
By default the receipt is composed in single-byte mode: each character is mapped through one of the printer's code pages. No single-byte code page contains Hanzi, Kana or Hangul, so without this parameter every such character is replaced with a ? before the job even reaches the device.
{
"usb_msg": "<C><BOLD>주문 #1234</BOLD></C>\n<CUT/>",
"printer_han": "kr"
}
The value has to match the script. Each one selects a different encoding and they do not overlap: Korean sent as cn comes out as ?, exactly as if the parameter had been left out.
The printer has to carry the matching font. printer_han switches the data stream to multi-byte mode; the glyphs themselves come from the printer's font ROM. A model shipped without that font will not print the characters even with the right value, and a printer sold for the Chinese market carries Hanzi, which does not mean it carries Hangul or Kana. Test the exact script you need on the exact model you deploy, and contact support if the result isn't readable.
Latin text does not need it. Leave printer_han out for European languages; accented characters are handled in the default mode.
Send your content as UTF-8 in every mode. The API stores and returns exactly what it receives, so the print history in the console shows the text as it arrived, which is the quickest way to tell a data problem from a printer one.
Response 200 OK
The job was accepted and queued.
ℹ️ A
200confirms server-side reception only — not that the ticket was physically printed. Delivery is asynchronous: the device receives the job when it next connects. The printer may be offline, out of paper, powered off, or unreachable at that moment. Pass anotification_urlif you need to know what actually happened.
| Parameter | Type | Description |
|---|---|---|
request_uid |
string |
Unique identifier of the accepted print job (e.g. 1X5ERXL94BYVWHP92DK3MCASUGJ). |
last_ping |
integer |
Unix timestamp of the device's last contact with the server. A value far in the past means the device was not online when you sent the job. |
Response example:
{
"last_ping": 1641509604,
"request_uid": "1X5ERXL94BYVWHP92DK3MCASUGJ"
}
last_ping is worth reading on every call: it is the cheapest signal that a device has gone silent.
Errors
| Status | Meaning |
|---|---|
403 |
Missing or invalid credentials (SID / TOKEN), or the device does not belong to this account. |
404 |
Unknown device_uid, or no configured printer on that usb_port. |
405 |
Wrong HTTP method — this endpoint is POST only. |
422 |
Empty or malformed usb_msg. |
500 |
The job could not be handed to the device. Retry, then contact support if it persists. |
Good practices
- Idempotency. Every accepted request produces a print. The endpoint does not de-duplicate, so if you retry after a network error, guard against double printing on your side.
- Keep
usb_msgwithin the paper width. 32 characters per line at 58 mm, 48 at 80 mm. See the layout reference. - Test with and without images. Some printer models reject certain image types and may fail the whole job — validate before production.
Related endpoints
GET https://www.expedy.fr/api/v2/devices/{device_uid}/usb/scan/read
Returns what is currently plugged into each USB port, with the detected manufacturer and model. Use it to discover which port to print to, and to confirm a printer is still where you expect.
/usb/conf returns the saved configuration of each port — paper width, print mode, graphic mode.
SDK & examples
Prefer a ready-made client? Use the official Node.js SDK: