HTTP API

The hosted agent resources used by the TypeScript SDK are available over HTTP. Use them directly from another language, a workflow engine, or an integration that should not depend on the SDK.

Client-side SDK features are not HTTP resources. Custom tool handlers, the runtime tool catalog, local skill bundles, locally registered MCP clients, composeAgents, and automatic callback handling for human input all require SDK code in your process. Hosted MCP connections, referenced skills, files, artifacts, saved agents, durable runs, events, and manual resume are available directly over HTTP.

Base URL and authentication#

Shell
export CORESOURCE_API_KEY='your-api-key'
export CORESOURCE_API_URL='https://api.coresource.ai/v1'

Every /v1 resource request carries a bearer token. /health is public.

Shell
-H "Authorization: Bearer $CORESOURCE_API_KEY"

One-shot responses#

One-shot requests are synchronous and do not allocate an agent runtime or a durable run resource. They are tool-free by default; the raw endpoint can optionally enable the single hosted web_search tool with "webSearch": true.

Shell
curl --fail-with-body --silent --show-error \
  -X POST "$CORESOURCE_API_URL/responses" \
  -H "Authorization: Bearer $CORESOURCE_API_KEY" \
  -H 'Content-Type: application/json' \
  --data '{
    "instructions": "Answer clearly and concisely.",
    "model": "deepseek/deepseek-v4-flash",
    "input": "Explain three-way invoice matching."
  }' | jq -r '.output_text'

The endpoint accepts input as text or a non-empty message array, plus optional instructions, model, effort, maxOutputTokens, temperature, stop, and webSearch.

Starting a run#

POST /v1/runs takes the agent definition and prompt in one request. An agent or saga normally returns 202 Accepted with a durable run id. An inline one-shot definition instead returns a synchronous OpenAI Responses-shaped body: the same shape as /v1/responses, not a run resource.

Shell
RUN=$(curl --fail-with-body --silent --show-error \
  -X POST "$CORESOURCE_API_URL/runs" \
  -H "Authorization: Bearer $CORESOURCE_API_KEY" \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: invoice-research-1' \
  --data '{
    "agent": {
      "type": "saga",
      "systemPrompt": "Act as an evidence auditor. Prefer primary sources.",
      "instructions": "Separate supported, contradicted, and unsubstantiated claims.",
      "model": "openai/gpt-5.5",
      "skills": ["anthropics/skills/skills/pdf"],
      "outputs": ["invoice-report.md"]
    },
    "prompt": "Validate the invoice benchmarks and write invoice-report.md.",
    "input": { "sector": "manufacturing", "region": "EU" },
    "metadata": { "customerId": "customer_123" }
  }')

RUN_ID=$(printf '%s' "$RUN" | jq -r '.id')
FieldRequiredNotes
agentYesThe agent definition, same shape as the SDK's config
promptYesThe objective
inputNoStructured parameters for an agent or saga
filesNoUploaded file references for an agent or saga
artifactsNoPrior-run artifacts to mount for an agent or saga
metadataNoCorrelation data stored with a durable run
idempotencyKeyNoAlso accepted as the Idempotency-Key header

Always send an idempotency key on anything that starts durable work. If a start succeeds but its response is lost, repeating the request without the same key can create a duplicate run.

For an inline one-shot, the gateway uses prompt and the definition's inference settings. It does not pass input, files, artifacts, or run metadata into the model.

Polling and results#

Shell
# Current state.
curl --fail-with-body --silent --show-error \
  -H "Authorization: Bearer $CORESOURCE_API_KEY" \
  "$CORESOURCE_API_URL/runs/$RUN_ID" | jq

# Final result, once terminal.
curl --fail-with-body --silent --show-error \
  -H "Authorization: Bearer $CORESOURCE_API_KEY" \
  "$CORESOURCE_API_URL/runs/$RUN_ID/result" | jq

Terminal statuses are succeeded, partial_success, failed, cancelled, and expired. queued, provisioning, running, retrying, and awaiting_input are not terminal. See core concepts.

Shell
# Projected logs.
curl -H "Authorization: Bearer $CORESOURCE_API_KEY" \
  "$CORESOURCE_API_URL/runs/$RUN_ID/logs" | jq

# Stop the run.
curl -X POST -H "Authorization: Bearer $CORESOURCE_API_KEY" \
  "$CORESOURCE_API_URL/runs/$RUN_ID/cancel" | jq

Streaming events#

The stream is server-sent events. Depending on the run, it may carry state, progress, logs, messages, tool activity, usage, and output updates.

Shell
curl --no-buffer --fail-with-body --silent --show-error \
  -H "Authorization: Bearer $CORESOURCE_API_KEY" \
  -H 'Accept: text/event-stream' \
  "$CORESOURCE_API_URL/runs/$RUN_ID/events"

Resume with the Last-Event-ID header, or fetch retained history explicitly:

Shell
curl --fail-with-body --silent --show-error \
  -H "Authorization: Bearer $CORESOURCE_API_KEY" \
  "$CORESOURCE_API_URL/runs/$RUN_ID/events/replay?after=EVENT_ID" | jq

As with the SDK, a dropped stream says nothing about the run. Reconnect, or poll the result.

Human input#

When an agent calls ask_user, the run enters the non-terminal awaiting_input state. Both the run and its result carry the pending action:

JSON
{
  "id": "run_123",
  "status": "awaiting_input",
  "requiredAction": {
    "type": "provide_input",
    "question": "Which launch date should I use?",
    "inputSchema": {
      "type": "object",
      "required": ["answer"],
      "properties": { "answer": { "type": "string" } }
    }
  }
}

Answer to resume the same run from its durable checkpoint:

Shell
curl --fail-with-body --silent --show-error \
  -X POST "$CORESOURCE_API_URL/runs/$RUN_ID/resume" \
  -H "Authorization: Bearer $CORESOURCE_API_KEY" \
  -H 'Content-Type: application/json' \
  --data '{"input":{"answer":"September 15"}}' | jq

The response is normally queued or running. Keep polling the original run id. Do not create another run. The agent may pause again later.

This endpoint is what makes fully detached human-in-the-loop workflows possible: the service that answers a question does not need the handle, or the process, that started the run.

Saved agents#

Store a definition once and run it by id.

Shell
AGENT=$(curl --fail-with-body --silent --show-error \
  -X POST "$CORESOURCE_API_URL/agents" \
  -H "Authorization: Bearer $CORESOURCE_API_KEY" \
  -H 'Content-Type: application/json' \
  --data '{
    "name": "invoice-researcher",
    "type": "saga",
    "systemPrompt": "Validate claims using primary sources.",
    "model": "openai/gpt-5.5",
    "outputs": ["report.md"]
  }')

AGENT_ID=$(printf '%s' "$AGENT" | jq -r '.id')

curl --fail-with-body --silent --show-error \
  -X POST "$CORESOURCE_API_URL/agents/$AGENT_ID/runs" \
  -H "Authorization: Bearer $CORESOURCE_API_KEY" \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: nightly-2026-07-29' \
  --data '{
    "prompt": "Validate these invoice-management benchmarks.",
    "input": { "quarter": "Q2" }
  }' | jq

For one-shot saved agents this endpoint returns an OpenAI Responses-shaped body. The request remains Coresource-specific: it uses /v1/agents/{agent_id}/runs and requires prompt, so reuse an OpenAI-compatible response parser rather than assuming an OpenAI client can call the endpoint unchanged. See multi-agent orchestration.

SavedAgentRunRequest accepts prompt (required), plus agentVersion, input, files, artifacts, and metadata. The latter four fields apply to durable saved agents; the one-shot gateway transformation uses the prompt and saved inference configuration. Pin agentVersion when a run must use a stable definition. It does not make model output deterministic.

EndpointMethodPurpose
/v1/agentsPOST, GETCreate, list
/v1/agents/{agent_id}GET, PATCH, DELETERetrieve, update, delete
/v1/agents/{agent_id}/versionsGETList immutable versions
/v1/agents/{agent_id}/versions/{version}GETRetrieve one version
/v1/agents/{agent_id}/runsPOSTRun it

Updates use optimistic concurrency: send If-Match with the version you read, and a concurrent edit returns 409 Conflict.

Files and artifacts#

Shell
# Upload an input file.
FILE=$(curl --fail-with-body --silent --show-error \
  -X POST "$CORESOURCE_API_URL/files" \
  -H "Authorization: Bearer $CORESOURCE_API_KEY" \
  -H 'Content-Type: text/csv' \
  -H 'X-CoreSource-Filename: invoices.csv' \
  --data-binary @./invoices.csv)

FILE_ID=$(printf '%s' "$FILE" | jq -r '.id')

# List a run's artifacts, then download one.
curl -H "Authorization: Bearer $CORESOURCE_API_KEY" \
  "$CORESOURCE_API_URL/runs/$RUN_ID/artifacts" | jq

curl -H "Authorization: Bearer $CORESOURCE_API_KEY" \
  "$CORESOURCE_API_URL/runs/$RUN_ID/artifacts/$ARTIFACT_ID/content" \
  --output ./report.md

MCP connections#

Create a connection once; the credential is write-only and never returned.

Shell
curl --fail-with-body --silent --show-error \
  -X POST "$CORESOURCE_API_URL/mcp/connections" \
  -H "Authorization: Bearer $CORESOURCE_API_KEY" \
  -H 'Content-Type: application/json' \
  --data "$(jq -n --arg token "$RESEARCH_MCP_TOKEN" '{
    name: "Research",
    url: "https://mcp.example.com/rpc",
    auth: { type: "bearer", token: $token }
  }')" | jq -r '.id'

For a Coresource-managed GitHub authorization send "auth":{"type":"oauth","provider":"github"} and open the returned authorization_url. To use your organization's own app, register it at /v1/mcp/oauth-apps first and reference it with "auth":{"type":"oauth","oauth_app_id":"..."}. With neither field, Coresource falls back to the standards-based path for servers supporting Client ID Metadata Documents or dynamic client registration.

Reference the connection id from an agent definition:

JSON
{
  "mcpServers": [
    { "connectionId": "mcpconn_0123456789abcdef", "alias": "research", "timeoutMs": 90000 }
  ]
}

Endpoint reference#

PathMethods
/healthGET
/v1/responsesPOST
/v1/runsPOST
/v1/runs/{run_id}GET
/v1/runs/{run_id}/resultGET
/v1/runs/{run_id}/cancelPOST
/v1/runs/{run_id}/resumePOST
/v1/runs/{run_id}/eventsGET (SSE)
/v1/runs/{run_id}/events/replayGET
/v1/runs/{run_id}/logsGET
/v1/runs/{run_id}/audit_eventsGET
/v1/runs/{run_id}/artifactsGET
/v1/runs/{run_id}/artifacts/{artifact_id}/contentGET
/v1/filesPOST, GET
/v1/files/{file_id}GET, DELETE
/v1/files/{file_id}/contentGET
/v1/agentsPOST, GET
/v1/agents/{agent_id}GET, PATCH, DELETE
/v1/agents/{agent_id}/versionsGET
/v1/agents/{agent_id}/versions/{version}GET
/v1/agents/{agent_id}/runsPOST
/v1/mcp/connectionsPOST, GET
/v1/mcp/connections/{connection_id}GET, PATCH, DELETE
/v1/mcp/connections/{connection_id}/credentialsPUT
/v1/mcp/connections/{connection_id}/authorizePOST
/v1/mcp/oauth-appsPOST, GET
/v1/mcp/oauth-apps/{oauth_app_id}GET, PATCH, DELETE
/v1/mcp/oauth-apps/{oauth_app_id}/credentialsPUT

The SDK package ships the OpenAPI document for the hosted agent resource API, so you can generate a client for those declared routes:

TypeScript
// no-check: resolves the package's `./openapi.json` subpath export, which
// needs the published package installed rather than the source checkout
// this documentation is typechecked against.
import spec from '@coresourceai/sdk/openapi.json';

The compatibility /v1/responses route, inline One shot definitions on /v1/runs, and saved One shot agents return OpenAI Responses-shaped results.

Errors#

Failures return a JSON envelope:

JSON
{
  "error": {
    "code": "invalid_request",
    "message": "agent.type must be one of one-shot, agent, saga"
  }
}

error.message is always present, and most failures carry a short error.code. Some errors add type and param fields and may leave code null. The SDK chooses an error subclass primarily from the HTTP status and preserves the server's code when one is set. See errors and retries for the mapping.