Overview

Base URL, authentication, pagination, and errors for the Context API.

View as Markdown

The Context API reads tickets, their messages, orders, and customers, polls the Needs reply feed, and asks for a mail check of your mailboxes. It returns JSON and never sends email or changes merchant orders. The operation pages are generated from its OpenAPI document, so they list exactly the fields the API returns.

Three ways in

Each operation is one procedure, served three ways with the same inputs, outputs, and permission checks.

SurfaceAddressFor
RESThttps://api.meetwillow.cx/api/v1Integrations with an API key.
MCPhttps://api.meetwillow.cx/api/v1/mcpAssistants. See MCP tools.
tRPChttps://api.meetwillow.cx/api/trpc/<procedure>EcomSquad’s own apps, such as OneInbox, with a member’s sign-in.

Operations

ProcedureRESTMCP toolPermission
context.ticket.listGET /ticketslist_ticketscontext:read
context.ticket.getGET /tickets/{ticketId}get_ticketcontext:read
context.ticket.messagesGET /tickets/{ticketId}/messagesget_ticket_messagescontext:read
context.ticket.refreshPOST /tickets/{ticketId}/refreshrefresh_ticketcontext:refresh
context.order.getGET /ordersget_ordercontext:read
context.order.lookupPOST /orders/lookupNonecontext:lookup, API key only
context.order.lookupByEmailPOST /orders/lookup-by-emailNonecontext:lookupByEmail, API key only
context.customer.getGET /customersget_customercontext:read
context.inbox.changesGET /inbox/changesNoneinbox:read
context.inbox.refreshPOST /inbox/refreshrefresh_inboxinbox:refresh
context.inbox.refreshStatusGET /inbox/refreshget_inbox_refreshinbox:refresh

Reads return stored data and never contact a provider. Only a refresh may call the store, and only a mailbox Refresh asks for a mail check. A key or sign-in given context:refresh also gets context:read, because a refresh returns the ticket; a key given inbox:refresh also gets inbox:read. The Needs reply feed and the mailbox Refresh answer API keys only.

Authentication

Send an EcomSquad API key in the x-api-key header on every request:

Terminal
curl --header "x-api-key: ${ECOMSQUAD_API_KEY}" \
  "https://api.meetwillow.cx/api/v1/tickets?limit=5"

The organization comes from the key; you never send an organization ID. Keys are for server-side use only. Each key carries permissions and connection limits.

REST and tRPC also accept a signed-in member’s session. It uses the member’s role and reaches every connection. When a request carries both a session and a key, the session decides. MCP accepts a key or MCP sign-in, limited to the scopes you approve.

Pagination

List operations return items and a nextCursor. To read the next page, send nextCursor as the URL-encoded cursor query parameter with the same filters. On /tickets and /tickets/{ticketId}/messages, a null nextCursor means you reached the end. Each cursor works only with the operation that returned it. The Needs reply feed’s nextCursor is always present, and hasMore says whether to read again straight away.

Errors

Errors use an HTTP status and a JSON body with code and message, and issues when input validation failed:

Error body
{
  "code": "NOT_FOUND",
  "message": "Ticket not found"
}
StatuscodeMeaning
400BAD_REQUESTInvalid input: a malformed UUID or email, a value out of range, an unknown parameter, or an invalid cursor. Schema failures say Input validation failed and list issues, except on POST /orders/lookup and POST /orders/lookup-by-email, whose 400 has one fixed message and never repeats what was sent.
400PARSE_ERRORA POST body is not valid JSON. Send no body, or a JSON object.
401UNAUTHORIZEDNo session, and the x-api-key header is missing, invalid, expired, or revoked, or the member who created the key has left the organization. The message does not say which.
403FORBIDDENThe message names what is missing: the operation’s permission (This API key lacks the inbox:read permission), an API key on a key-only operation, or a signed-in user’s current organization.
404NOT_FOUNDThe record does not exist, or is outside the key’s organization or connection access.
415UNSUPPORTED_MEDIA_TYPEA POST carries a body that is not application/json.
429TOO_MANY_REQUESTSPOST /orders/lookup and POST /orders/lookup-by-email only: too many failed lookups for this email, order name or key, or too many lookups by email for this email or key, in the last 24 hours, or a wait of more than a second behind the organization’s other lookups. The message does not say which.
500INTERNAL_SERVER_ERROREcomSquad failed. The message is always Request failed. Retry reads; read the ticket before repeating a refresh.

An HTTP 200 means the read succeeded, not that an order was found or recently checked. Inspect the returned orders and, after a refresh, refresh.state. See Troubleshooting for next steps.

A null from GET /orders is often an id in the wrong form. The numeric orderId on a ticket or in a customer’s synced orders matches nothing there. Send the order’s name as orderName, or put gid://shopify/Order/ in front of the number.

Every response, success or error, carries an x-request-id header. Quote it when you report a problem: it finds the request in EcomSquad’s logs. To use your own id, send it as x-request-id, 1 to 128 characters of letters, digits, ., _, : and -, and the response returns it unchanged. Any other value is replaced with a new id. Browsers can read the header.

OpenAPI document

The API serves the document these pages are generated from:

OpenAPI document
https://api.meetwillow.cx/api/v1/openapi.json

Use it to generate a client or to check exact request and response schemas.