Skip to content

order_status: skill contract

order_status returns an order’s status and line items. It is customer-scoped: every call includes the customer_email the agent supplied, and your endpoint must confirm that email owns the order before returning anything. Only your systems can make that check.

Request: { "order_id": "#1001", "customer_email": "[email protected]" }
1. Look up order #1001.
2. Compare its customer email with "[email protected]".
3. Match: return the order in the response shape below.
4. No match, or no such order: return 404 with an empty body.

If you skip step 2, anyone who guesses an order number can read that order through an agent, including the items and dates.

Normalize both emails the same way before comparing, and compare in constant time so response timing does not reveal a near match. In Node.js:

import { timingSafeEqual } from 'node:crypto';
function emailsMatch(a: string, b: string): boolean {
const na = a.trim().toLowerCase().normalize('NFKC');
const nb = b.trim().toLowerCase().normalize('NFKC');
const ba = Buffer.from(na, 'utf8');
const bb = Buffer.from(nb, 'utf8');
if (ba.length !== bb.length) return false;
return timingSafeEqual(ba, bb);
}

Return the same 404 for a wrong email and for an order that does not exist, so a caller cannot tell which order numbers are real. A 404 reaches the agent as “not found” and does not affect your endpoint’s health.

Machine-readable: /skills/v1/order_status.request.schema.json

FieldTypeRequiredNotes
order_idstringyesThe order number the customer knows (for example #1001) or your internal ID. 1–128 chars.
customer_emailstringyesThe email the agent says owns the order. Not verified by Sill. 3–320 chars.
{
"additionalProperties": false,
"properties": {
"customer_email": {
"maxLength": 320,
"minLength": 3,
"type": "string"
},
"order_id": {
"maxLength": 128,
"minLength": 1,
"type": "string"
}
},
"required": ["order_id", "customer_email"],
"type": "object"
}
{
"skill_id": "order_status",
"site_id": "01EXAMPLE00000000000000000",
"arguments": {
"order_id": "#1001",
"customer_email": "[email protected]"
},
"observed_at": "2026-07-05T18:22:15.140Z",
"nonce": "01K1EXAMPLE0000000000000000"
}

Machine-readable: /skills/v1/order_status.response.schema.json

FieldTypeRequiredNotes
order_idstringyesEcho the order id. 1–256 chars.
statusenumyespending, paid, fulfilled, cancelled or refunded. Map your own statuses to the closest one.
placed_atstringyesWhen the order was placed, ISO-8601 UTC, for example 2026-06-30T14:12:03Z. 20–40 chars.
fulfilled_atstringnoWhen the order was fulfilled, ISO-8601 UTC. 20–40 chars.
line_itemsarrayyesUp to 128 items. Each has sku, title, quantity, unit_price.

Return only these fields. A response with any other field, such as the customer’s name, address, phone, payment method or internal notes, fails the schema: it is not passed to the agent and counts as a failed call (3 failures in a row mark the skill UNREACHABLE).

Each line item:

FieldTypeRequiredNotes
skustringyes1–256 chars.
titlestringyes1–512 chars.
quantityintegeryes0 or more.
unit_priceobjectyes{ amount, amount_decimal, currency }, as in browse_catalog.
{
"additionalProperties": false,
"properties": {
"fulfilled_at": { "maxLength": 40, "minLength": 20, "type": "string" },
"line_items": {
"items": {
"additionalProperties": false,
"properties": {
"quantity": { "minimum": 0, "type": "integer" },
"sku": { "maxLength": 256, "minLength": 1, "type": "string" },
"title": { "maxLength": 512, "minLength": 1, "type": "string" },
"unit_price": {
"additionalProperties": false,
"properties": {
"amount": { "type": "number" },
"amount_decimal": { "maxLength": 64, "minLength": 1, "type": "string" },
"currency": { "maxLength": 8, "minLength": 3, "type": "string" }
},
"required": ["amount", "amount_decimal", "currency"],
"type": "object"
}
},
"required": ["sku", "title", "quantity", "unit_price"],
"type": "object"
},
"maxItems": 128,
"type": "array"
},
"order_id": { "maxLength": 256, "minLength": 1, "type": "string" },
"placed_at": { "maxLength": 40, "minLength": 20, "type": "string" },
"status": {
"enum": ["pending", "paid", "fulfilled", "cancelled", "refunded"],
"type": "string"
}
},
"required": ["order_id", "status", "placed_at", "line_items"],
"type": "object"
}
{
"order_id": "#1001",
"status": "fulfilled",
"placed_at": "2026-06-30T14:12:03.000Z",
"fulfilled_at": "2026-07-02T09:41:18.000Z",
"line_items": [
{
"sku": "beans_medium_12oz",
"title": "Medium roast, 12 oz bag",
"quantity": 2,
"unit_price": {
"amount": 1800,
"amount_decimal": "18.00",
"currency": "USD"
}
}
]
}

Return 404 with an empty body when:

  • the order does not exist;
  • the email does not match the order’s customer email;
  • the order is deleted or archived.

Do not return a placeholder order (empty line_items, status: "pending") instead: it tells the caller the order number exists.

Sill checks every 2xx response against the response schema. A response that fails is not passed to the agent and counts as a failed call; 3 failures in a row mark the skill UNREACHABLE. Common causes:

  • an extra field at any depth, such as customer_address or payment_method;
  • a status outside the five values;
  • a placed_at shorter than 20 or longer than 40 characters.

Sill cannot check that the email matched. Run the self-test with your own orders to confirm it.

Check the X-Sill-Signature header on every request before answering. The scheme is the same for every skill; see Verify the signature for tested TypeScript, Python and Go code.