Skip to content

REST API

REST is one of two transports for invoking tools on a Wire container. The other is MCP. What tools exist, what they do, and what they return is defined on the Tools page. This page covers how to call them over HTTP.

All REST endpoints accept the same credentials as MCP:

  • API Key: x-api-key: YOUR_API_KEY header
  • Bearer Token: Authorization: Bearer YOUR_TOKEN header

Every endpoint requires a credential, including on public containers. Public visibility decides who is allowed to read a container, not whether the request has to be authenticated.

See Authentication for details on obtaining credentials.

REST exposes two endpoint styles:

1. Generic tool dispatcher, for the standard tools (wire_explore, wire_search, wire_navigate, wire_write, wire_delete):

POST /container/:id/tools/{short-name}

The {short-name} is the tool name without the wire_ prefix. The request body is a JSON object matching the tool’s input schema documented on the Tools page.

The dispatcher also serves wire_query at POST /container/:id/tools/query, but that tool is off for both transports on a new container, so the endpoint returns 404 NOT_FOUND until an organization owner or admin enables it.

Example:

Terminal window
curl -X POST \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"query": "customer feedback on pricing"}' \
https://YOUR_ORG_SLUG.api.usewire.io/container/YOUR_CONTAINER_ID/tools/search

2. Dedicated REST endpoints, for file and status tools, where the underlying operation doesn’t map cleanly to a JSON-body call (multipart upload, GET semantics for status, path-positional file IDs):

ToolREST endpoint
wire_statusGET /container/:id/status
wire_files_listGET /container/:id/files
wire_files_uploadPOST /container/:id/files (multipart, file field, up to 25 MB)
wire_files_deleteDELETE /container/:id/files/:fileId

Both styles share the same gating: if a tool is toggled off for the REST transport on the container’s Tools page, the corresponding endpoint returns 404 NOT_FOUND. The same is true of permissions — the file endpoints answer exactly as their tools do, so listing needs read access and uploading or deleting needs editor or admin access on the container. See Tools for each tool’s input schema, output shape, default visibility, and credit cost.

The dedicated endpoints return the same {"success": true, "data": ...} envelope as everything else on this page; the shapes on the Tools page are what lands in data.

Any automation platform that can make an authenticated HTTP POST (n8n, Zapier, Make, Pipedream, a cron job, a shell script) can drop entries into a Wire container by calling wire_write:

Terminal window
curl -X POST \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"content": "Q2 revenue increased 15% driven by enterprise segment", "tags": ["finance", "q2"]}' \
https://YOUR_ORG_SLUG.api.usewire.io/container/YOUR_CONTAINER_ID/tools/write

When a webhook pushes the same shape repeatedly (a form submission, a deploy event, a row from a spreadsheet), name an object so the records land as queryable rows instead of loose text. A JSON payload is its own field map, so mapping is usually just the one extra key:

Terminal window
curl -X POST \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"object": "deploys", "content": {"service": "api", "version": "1.4.2", "duration_s": 41}}' \
https://YOUR_ORG_SLUG.api.usewire.io/container/YOUR_CONTAINER_ID/tools/write

Pass fields explicitly when the readable content and the queryable values differ. See Objects for how the field profile builds up.

Wire uses the source string to trace where each entry came from. Stick to the <platform>:<identifier> pattern so downstream graph exploration stays tidy:

OriginRecommended source
Claude Code / other MCP agentsagent:session-abc (default: agent:mcp)
REST without explicit sourcewebhook:<api-key-name> (auto-filled)
n8n workflown8n:<workflow-id>:<node-id>
Make scenariomake:<scenario-id>
Zapier zapzapier:<zap-id>
Custom script / anything elsewebhook:<descriptive-name>

See the Sources tab inside any container in the dashboard to grab the endpoint URL pre-filled for your container.

POST /container/:id/claim

Generate a claim link for an ephemeral container. Returns a URL the user can open to sign up or log in and make the container permanent. Requires authentication.

Returns 409 Conflict if the container has already been claimed.

Terminal window
curl -X POST \
-H "x-api-key: YOUR_API_KEY" \
https://YOUR_ORG_SLUG.api.usewire.io/container/YOUR_CONTAINER_ID/claim
{
"success": true,
"data": {
"claim_url": "https://app.usewire.io/onboarding/create-account?claimToken=...",
"expires_in": 3600
}
}

All errors follow the same format:

{
"success": false,
"error": {
"code": "NOT_FOUND",
"message": "Endpoint disabled: 'wire_files_list' is turned off for this container's REST transport"
}
}
CodeHTTP StatusDescription
BAD_REQUEST400Missing required parameter
UNAUTHORIZED401Authentication required on the claim endpoint when the container is being read without credentials
INSUFFICIENT_CREDITS402Not enough credits to execute tool
FORBIDDEN403Action not allowed (e.g., a write tool called with read-only access, scoped key on wrong container)
NOT_FOUND404Container, file, or tool not found; also returned when a tool is toggled off for the REST transport
CONFLICT409Container already claimed
LENGTH_REQUIRED411File upload sent without a Content-Length header
PAYLOAD_TOO_LARGE413Upload exceeds the maximum file size
TOOL_ERROR502Tool execution returned an error
INTERNAL_ERROR500Server error
SERVICE_UNAVAILABLE503Temporary — the container is busy or a dependency is unreachable. Retry; the response carries Retry-After

A missing or invalid credential is rejected before the request reaches any tool, and that rejection does not carry a code. It returns 401 with a flat body:

{
"error": "Unauthorized",
"message": "Invalid API key"
}

The response also carries a WWW-Authenticate header describing the expected resource. Code on the 401 path should branch on the status, not on error.code, because there is no error.code to read. The coded UNAUTHORIZED above is the one narrow case where a coded 401 does appear.