Missions.

The REST Missions API is the most direct way to drive a Houston agent. Create a mission, then poll it, stream it, or wait for a signed webhook. All paths are on https://poc-gateway.gethouston.ai and take Authorization: Bearer hst_....

Create a mission

POST /v1/agents/:slug/missions

Starts a mission and returns 202 Accepted right away. The agent runs in the background; use the id in the response to track it.

Request body

FieldTypeDescription
input requiredstringThe instruction for the agent, in natural language.
mode optionalstringOne of execute, plan, or auto. Defaults to auto (the agent decides whether to plan first or act directly).
model optionalstringOverride the model for this mission. Defaults to the agent's configured model.
effort optionalstringReasoning effort for the mission. Defaults to the agent's setting.
title optionalstringA label for the mission, shown in the Houston app. Auto-generated if omitted.
webhook optionalobjectDelivers a signed callback when the mission finishes. See Webhooks.
webhook.urlstringPublic https:// URL to POST to. Private and internal addresses are rejected.
webhook.secretstringSigning secret used to compute the X-Houston-Signature HMAC.
curl -X POST https://poc-gateway.gethouston.ai/v1/agents/revenue-manager/missions \
  -H "Authorization: Bearer hst_9f2c1a7b4e8d0364f1a2b3c4d5e6f7089f2c1a7b4e8d0364f1a2b3c4d5e6f708" \
  -H "Content-Type: application/json" \
  -d '{
    "input": "Draft the weekly competitor summary for the Lisbon property.",
    "mode": "auto",
    "model": "claude-opus-4-5",
    "title": "Weekly competitor summary",
    "webhook": {
      "url": "https://api.acme.com/hooks/houston",
      "secret": "whsec_a1b2c3d4e5f6"
    }
  }'

202 Accepted

{
  "id": "msn_7Q4c1a9f2b",
  "agentSlug": "revenue-manager",
  "conversationId": "cnv_3e8d0364f1",
  "status": "running",
  "createdAt": "2026-07-12T09:31:07.482Z"
}

List missions

GET /v1/agents/:slug/missions

Returns the agent's missions, newest first.

QueryTypeDescription
limit optionalintegerHow many to return. Defaults to 50, maximum 200.
curl "https://poc-gateway.gethouston.ai/v1/agents/revenue-manager/missions?limit=20" \
  -H "Authorization: Bearer hst_9f2c1a7b4e8d0364f1a2b3c4d5e6f7089f2c1a7b4e8d0364f1a2b3c4d5e6f708"
{
  "missions": [
    {
      "id": "msn_7Q4c1a9f2b",
      "agentSlug": "revenue-manager",
      "conversationId": "cnv_3e8d0364f1",
      "status": "completed",
      "createdAt": "2026-07-12T09:31:07.482Z"
    }
  ]
}

Get a mission

GET /v1/agents/:slug/missions/:id

Returns the mission's current state. status is one of running, completed, failed, or canceled. Once the status is terminal, result carries the agent's final text. If the mission was created with a webhook, the response includes a webhook block recording when it was delivered, or the last error if delivery has not yet succeeded.

curl https://poc-gateway.gethouston.ai/v1/agents/revenue-manager/missions/msn_7Q4c1a9f2b \
  -H "Authorization: Bearer hst_9f2c1a7b4e8d0364f1a2b3c4d5e6f7089f2c1a7b4e8d0364f1a2b3c4d5e6f708"
{
  "id": "msn_7Q4c1a9f2b",
  "agentSlug": "revenue-manager",
  "conversationId": "cnv_3e8d0364f1",
  "status": "completed",
  "result": "Weekly competitor summary is ready. Three properties moved rates...",
  "createdAt": "2026-07-12T09:31:07.482Z",
  "webhook": {
    "url": "https://api.acme.com/hooks/houston",
    "deliveredAt": "2026-07-12T09:34:52.140Z"
  }
}

Stream events (SSE)

GET /v1/agents/:slug/missions/:id/events

Streams the mission's progress as Server-Sent Events and closes when the mission reaches a terminal state. Each event has an id; if the connection drops, reconnect and send the Last-Event-ID header to resume without gaps. Native SSE clients and curl do this for you.

curl -N https://poc-gateway.gethouston.ai/v1/agents/revenue-manager/missions/msn_7Q4c1a9f2b/events \
  -H "Authorization: Bearer hst_9f2c1a7b4e8d0364f1a2b3c4d5e6f7089f2c1a7b4e8d0364f1a2b3c4d5e6f708"
Browser (EventSource)

EventSource cannot send an Authorization header, so this endpoint also accepts the key as a query parameter: ?token=hst_.... Keep that URL out of logs.

Cancel a mission

POST /v1/agents/:slug/missions/:id/cancel

Requests cancellation of a running mission. If the mission has already reached a terminal state, you get 409 Conflict:

{ "code": "mission_finished" }

List agents

GET /agents

Lists the agents this key can reach, with the slugs you pass to the mission endpoints.

curl https://poc-gateway.gethouston.ai/agents \
  -H "Authorization: Bearer hst_9f2c1a7b4e8d0364f1a2b3c4d5e6f7089f2c1a7b4e8d0364f1a2b3c4d5e6f708"

API-key scope & limits

API keys are deliberately narrow. A key works only on the programmatic surfaces: the Missions endpoints, A2A, MCP, and GET /agents. Point it at any other part of the gateway and you get 403 Forbidden:

{ "code": "api_key_scope" }

You can hold up to 20 active keys. Creating a 21st returns 400 Bad Request; revoke an old one first.

{ "code": "key_limit" }

Webhooks

Pass a webhook object when you create a mission and Houston will POST a signed payload to your URL the instant the mission finishes. This is the recommended pattern for servers: no polling, no open connections.

Payload

{
  "event": "mission.completed",
  "mission": {
    "id": "msn_7Q4c1a9f2b",
    "agentSlug": "revenue-manager",
    "conversationId": "cnv_3e8d0364f1",
    "status": "completed",
    "result": "Weekly competitor summary is ready...",
    "createdAt": "2026-07-12T09:31:07.482Z"
  }
}

event is one of mission.completed, mission.failed, or mission.canceled.

Headers

HeaderValue
X-Houston-EventThe event name, e.g. mission.completed.
X-Houston-DeliveryA unique id for this delivery attempt group. Use it to deduplicate.
X-Houston-Signaturesha256=<hex>, the HMAC-SHA256 of the raw request body keyed with your webhook.secret.

Delivery & reliability

Verify the signature

Compute the HMAC over the raw request body (not a re-serialized object) and compare in constant time:

import crypto from "node:crypto";

// `rawBody` is the exact bytes Houston sent (a Buffer or string).
// In Express, capture it with express.raw({ type: "application/json" }).
function verifyHoustonWebhook(rawBody, signatureHeader, secret) {
  const expected =
    "sha256=" +
    crypto.createHmac("sha256", secret).update(rawBody).digest("hex");
  const a = Buffer.from(signatureHeader ?? "");
  const b = Buffer.from(expected);
  return a.length === b.length && crypto.timingSafeEqual(a, b);
}

app.post("/hooks/houston", express.raw({ type: "application/json" }), (req, res) => {
  const ok = verifyHoustonWebhook(
    req.body,
    req.get("X-Houston-Signature"),
    process.env.HOUSTON_WEBHOOK_SECRET,
  );
  if (!ok) return res.sendStatus(401);

  // Deduplicate on the delivery id, then process.
  const deliveryId = req.get("X-Houston-Delivery");
  const payload = JSON.parse(req.body.toString("utf8"));
  // ... handle payload.event / payload.mission ...
  res.sendStatus(200);
});
Sign over raw bytes

Frameworks that auto-parse JSON change the byte stream. Verify against the untouched body Houston sent, or the HMAC will not match even with the right secret.