Motherboard X Web API
The External Display API displays text on a specific motherboard in Home mode or supplies an input to its current routine step. It is a public, board-scoped API and does not require an end-user login. The motherboard owner supplies the board’s API ID.
POST https://api.motherboard.conjuringlab.com/api/displayHeaders
Section titled “Headers”| Header | Required | Value |
|---|---|---|
X-Motherboard-Api-Id |
Yes | The board’s API ID, such as mb_... |
Content-Type |
Yes | application/json |
Idempotency-Key |
For later status checks | A new UUID for each logical display request |
Keep the API ID, idempotency key, and exact body together. To check the request later, resend all three unchanged. There is no public status endpoint.
The owner can rotate the API ID at any time. Old IDs stop working immediately.
Request body
Section titled “Request body”{ "kind": "text", "text": "Hello world", "orientation": "portrait", "zone": "bottom-half"}| Field | Type | Required | Description |
|---|---|---|---|
kind |
string | Yes | Must be "text". |
text |
string | Yes | Text or routine input. Empty and whitespace-only strings are rejected. Send numbers as strings, such as "42". |
orientation |
string or null | No | "landscape" or "portrait", lowercase. Omit or use null for landscape. Other values, including uppercase names, are rejected. |
zone |
string or null | No | "top-half" or "bottom-half". Omit or use null for the full display. |
In Home mode, the selected half follows the text orientation. Text fits inside that half and content outside it is preserved. Orientation applies to this request only and does not change board settings. During routines, orientation and zone are ignored; the routine controls rendering.
Literal \n, \r\n, and \r sequences in text are converted to line breaks before delivery. For example, the JSON value "Hello\\nworld" contains a literal backslash followed by n; the API converts it into a line break.
Text size
Section titled “Text size”The complete notification payload, including metadata and JSON encoding, must fit within 4,096 UTF-8 bytes. This is not a 4,096-character allowance for text: the available space depends on the payload and characters used. Oversized text returns 400 invalid_request with the message The display text is too large for reliable notification delivery. before an attempt is stored.
Send text
Section titled “Send text”Replace mb_... with your board’s API ID and use a fresh UUID for your first request. Run the exact same command again later to check that request’s state.
curl -i -X POST 'https://api.motherboard.conjuringlab.com/api/display' \ -H 'X-Motherboard-Api-Id: mb_...' \ -H 'Content-Type: application/json' \ -H 'Idempotency-Key: 3f36dc0d-3576-4f4e-aae0-86235913cf81' \ -d '{ "kind": "text", "text": "Hello\\nworld", "orientation": "portrait", "zone": "bottom-half" }'JavaScript
Section titled “JavaScript”Create the key and body once per logical display request, outside the function used to submit or recheck it.
const apiId = 'mb_...';const idempotencyKey = crypto.randomUUID();const body = JSON.stringify({ kind: 'text', text: 'Hello world', orientation: 'portrait', zone: 'bottom-half',});
async function submitOrCheck() { const response = await fetch( 'https://api.motherboard.conjuringlab.com/api/display', { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-Motherboard-Api-Id': apiId, 'Idempotency-Key': idempotencyKey, }, body, }, );
return { httpStatus: response.status, body: await response.json(), };}
const initialResult = await submitOrCheck();// For 202, call submitOrCheck() later with bounded backoff and a deadline.Handle network failures in your calling code. If you check the same request after a failure, retain the original key and body; generating a new key starts a new attempt. See delivery and retries.
Responses
Section titled “Responses”200: handled
Section titled “200: handled”{ "requestId": "uuid", "status": "delivered"}The firmware or app bridge reported the request handled.
202: pending
Section titled “202: pending”{ "requestId": "uuid", "status": "accepted", "message": "The request was accepted and is pending delivery."}This is not a terminal result. Recheck the same request using its original idempotency key and body. The requestId cannot be queried directly.
202 is the normal initial response while delivery is pending, including when the board is offline. The request remains stored if a wake notification or app bridge broadcast fails.
Errors
Section titled “Errors”Errors normally use this shape:
{ "requestId": "uuid", "status": "error", "code": "invalid_request", "message": "The request body is invalid."}405 Method Not Allowed is an exception: it returns {"error":"METHOD_NOT_ALLOWED"} with an Allow: GET, POST header. GET is reserved for firmware polling with a separate board credential; it is not a public status lookup using your API ID. Use POST for this integration.
See delivery, rate limits, and errors for retry guidance. This HTTP interface accepts text only.