Use cases
Four end-to-end scenarios that combine the pieces of the other pages. Each one shows the setup in Console, the request, and the response you should expect. All examples assume:
export CONSOLE_URL="https://console.example.com"
export COGNIPEER_API_TOKEN="cpeer_..."Document analysis
Goal: a person or a system drops in a contract (PDF). You want the key terms as structured data, and a CSV of the obligations to open in a spreadsheet.
Setup
- Create an agent
contract-analystwith instructions such as "Extract the parties, term, renewal and every obligation. Put the obligations in a CSV file withsession_files_create." - Configure → Files: switch on Let people attach files and pick a bucket. Agent file outputs (the
session_files_createandsession_files_appendtools) are on by default once uploads are on and a bucket is set; their limits (files per turn, size) are in the same section. See Files and images. - Publish.
Request. The PDF travels in the request as an input_file; a json_schema shapes the final answer; the CSV is written by the agent through its file tools. The run is async-first on the runs API, so the call never holds a connection.
PDF_B64=$(base64 < contract-17.pdf | tr -d '\n')
RUN=$(curl -sS -X POST "$CONSOLE_URL/api/client/v1/agents/contract-analyst/runs" \
-H "Authorization: Bearer $COGNIPEER_API_TOKEN" -H "Content-Type: application/json" \
-H "Idempotency-Key: contract-17-analysis" \
-d @- <<JSON
{
"input": [{
"role": "user",
"content": [
{ "type": "input_text", "text": "Analyse this contract." },
{ "type": "input_file", "filename": "contract-17.pdf", "file_data": "data:application/pdf;base64,$PDF_B64" }
]
}],
"metadata": { "contract": "17" },
"response_format": {
"type": "json_schema",
"json_schema": { "name": "contract_terms", "strict": true, "schema": {
"type": "object", "additionalProperties": false,
"required": ["parties", "term_months", "auto_renews", "obligation_count"],
"properties": {
"parties": { "type": "array", "items": { "type": "string" } },
"term_months": { "type": "integer" },
"auto_renews": { "type": "boolean" },
"obligation_count": { "type": "integer" }
} } }
},
"wait": 60
}
JSON
)
echo "$RUN" | jq '{id, status}'Response (200 when it finished inside the 60 s wait; otherwise 202 with status: "running", and you long-poll GET /agents/runs/{id}?wait=60):
{
"id": "run_65f1c0a2b9d3e4f5a6b7c8d9",
"object": "agent.run",
"status": "succeeded",
"agent": "contract-analyst",
"session_id": "6f1c0a2b9d3e4f5a6b7c8d9e",
"output_parsed": { "parties": ["Acme Ltd", "Globex GmbH"], "term_months": 24, "auto_renews": true, "obligation_count": 18 },
"output_text": "{\"parties\":[\"Acme Ltd\",\"Globex GmbH\"],\"term_months\":24,\"auto_renews\":true,\"obligation_count\":18}",
"result": {
"status": "completed",
"output_files": [
{ "id": "6f1c0a2b9d3e4f5a6b7c8da0", "name": "obligations.csv", "mime_type": "text/csv", "size": 2214,
"download_url": "/api/client/v1/agents/sessions/6f1c0a2b9d3e4f5a6b7c8d9e/files/6f1c0a2b9d3e4f5a6b7c8da0/content" }
]
}
}Download the CSV (download_url is relative to the Console origin):
curl -sS -H "Authorization: Bearer $COGNIPEER_API_TOKEN" -o obligations.csv \
"$CONSOLE_URL$(echo "$RUN" | jq -r '.result.output_files[0].download_url')"Many documents? Send each as its own run with "class": "deferred", tag them with metadata, and collect results with a callback or GET /agents/runs?class=deferred&metadata[batch]=2026-10.
Expense receipts
Goal: employees photograph a receipt; your expense tool sends the image, gets structured fields, and the result lands in the ERP without anyone polling.
Setup: an agent receipt-reader on a model that reads images, with files switched on. Its instructions say to extract merchant, date, currency, total, VAT and category, and to answer in the schema.
Request. An image goes in as an input_image; the schema is the contract with the ERP; a per-request callback delivers the result.
curl -sS -X POST "$CONSOLE_URL/api/client/v1/agents/receipt-reader/runs" \
-H "Authorization: Bearer $COGNIPEER_API_TOKEN" -H "Content-Type: application/json" \
-H "Idempotency-Key: expense-8841-receipt-1" \
-d '{
"input": [{ "role": "user", "content": [
{ "type": "input_text", "text": "Read this receipt." },
{ "type": "input_image", "image_url": "https://files.example.com/receipts/8841-1.jpg" }
] }],
"metadata": { "expense_id": "8841", "employee": "e-204" },
"response_format": { "type": "json_schema", "json_schema": { "name": "receipt", "strict": true, "schema": {
"type": "object", "additionalProperties": false,
"required": ["merchant", "date", "currency", "total", "vat", "category"],
"properties": {
"merchant": { "type": "string" }, "date": { "type": "string" }, "currency": { "type": "string" },
"total": { "type": "number" }, "vat": { "type": "number" },
"category": { "type": "string", "enum": ["travel", "meals", "lodging", "supplies", "other"] }
} } } },
"callback": { "url": "https://erp.example.com/hooks/receipts?claim=8841", "secret": "a-shared-secret-of-16-plus-chars" }
}'Immediate response (202; Location header points at the run):
{ "id": "run_65f1c0a2b9d3e4f5a6b7c8e1", "object": "agent.run", "status": "queued", "class": "default",
"metadata": { "expense_id": "8841", "employee": "e-204" },
"callback": { "url": "https://erp.example.com/hooks/receipts?claim=8841", "status": "pending", "attempts": 0, "signed": true } }Callback to the ERP (signed with x-cognipeer-signature; verify it as on the webhooks page):
{
"id": "evt_65f1c0a2b9d3e4f5a6b7c8e1_succeeded",
"event": "agent_run.succeeded",
"createdAt": "2026-10-14T09:15:02.000Z",
"runId": "run_65f1c0a2b9d3e4f5a6b7c8e1",
"sessionId": "6f1c0a2b9d3e4f5a6b7c8e2",
"conversationId": "6f1c0a2b9d3e4f5a6b7c8e2",
"data": {
"result": { "id": "resp_65f1c0a2b9d3e4f5a6b7c8e1", "object": "response", "status": "completed",
"output_parsed": { "merchant": "Hotel Aurora", "date": "2026-10-14", "currency": "EUR", "total": 184.5, "vat": 16.77, "category": "lodging" } }
}
}The callback is small: data holds only the result (a failure has errorReason and message instead). The ERP finds the claim from the claim parameter it put in the callback URL (or by reading the run's metadata with GET /agents/runs/{runId}), deduplicates on the event id (a callback can repeat), and answers 2xx. If the callback never arrives, GET /agents/runs/{runId} has the same result. A receipt the agent cannot read is a succeeded run whose output_error explains why validation failed (check it before writing to the ERP), not an HTTP error.
Nightly report
Goal: every night at 02:00 a report is produced from yesterday's data, saved as a file, and announced to a chat channel.
Setup
Agent
report-writerwith the tools it needs (a database or MCP tool) and file outputs on.A trigger of type
schedule, classdeferredso it never competes with interactive traffic:bashcurl -X POST "$CONSOLE_URL/api/client/v1/agents/report-writer/triggers" \ -H "Authorization: Bearer $COGNIPEER_API_TOKEN" -H "Content-Type: application/json" \ -d '{ "name": "Nightly operations report", "type": "schedule", "schedule": { "cron": "0 2 * * *", "timezone": "Europe/Istanbul" }, "prompt": "Write yesterday’s operations report. Save it as report.md with session_files_create and answer with a three-line summary.", "class": "deferred", "metadata": { "report": "nightly-ops" } }'A webhook subscription to hear when it is done:
bashcurl -X POST "$CONSOLE_URL/api/client/v1/webhooks" \ -H "Authorization: Bearer $COGNIPEER_API_TOKEN" -H "Content-Type: application/json" \ -d '{ "url": "https://hooks.example.com/console", "events": ["agent_run.succeeded", "agent_run.failed", "trigger.failed"] }'
What happens at 02:00. One Console node claims the slot and creates a deferred run (trigger: "schedule", trigger_id set). The run waits for a deferred slot, executes, writes report.md through the file tools, and finishes. You receive:
{
"id": "evt_65f1c0a2b9d3e4f5a6b7c8f2_succeeded",
"type": "agent_run.succeeded",
"projectId": "6a1b2c3d4e5f60718293a4b5",
"data": { "runId": "run_65f1c0a2b9d3e4f5a6b7c8f2", "agentKey": "report-writer", "sessionId": "6f1c0a2b9d3e4f5a6b7c8db1", "conversationId": "6f1c0a2b9d3e4f5a6b7c8db1",
"status": "succeeded", "class": "deferred", "triggerId": "6720b4c3d2e1f0a9b8c7d6e5", "metadata": { "report": "nightly-ops" } }
}Your receiver fetches the run and the file, then posts to chat:
RUN=$(curl -sS "$CONSOLE_URL/api/client/v1/agents/runs/run_65f1c0a2b9d3e4f5a6b7c8f2" -H "Authorization: Bearer $COGNIPEER_API_TOKEN")
echo "$RUN" | jq -r .output_text # the three-line summary
URL=$(echo "$RUN" | jq -r '.result.output_files[0].download_url')
curl -sS -H "Authorization: Bearer $COGNIPEER_API_TOKEN" -o report.md "$CONSOLE_URL$URL"Check last night's history at any time with GET /agents/runs?trigger_id=…&limit=7. If a night is missed because Console was down for under an hour, the trigger fires once to catch up; after an hour that slot is skipped (misfire policy).
Release notes and PR review in CI
Goal: when a tag is pushed, an agent writes the release notes; on every pull request, an agent leaves a review comment.
Setup: agents release-notes and code-reviewer, published, with a token stored as a CI secret. Both use response_format so the pipeline can read fields instead of parsing prose.
Request (the same in every CI system; the key makes a retried step safe):
curl -sS -X POST "$CONSOLE_URL/api/client/v1/agents/release-notes/runs" \
-H "Authorization: Bearer $COGNIPEER_API_TOKEN" -H "Content-Type: application/json" \
-H "Idempotency-Key: build-4821-release-notes" \
-d "$(jq -n --rawfile log commits.txt '{
input: ("Write release notes for these commits:\n" + $log),
metadata: { build: "4821", repo: "shop-api" },
response_format: { type: "json_schema", json_schema: { name: "notes", strict: true, schema: {
type: "object", additionalProperties: false, required: ["version_bump", "markdown"],
properties: { version_bump: { type: "string", enum: ["major","minor","patch"] }, markdown: { type: "string" } } } } },
wait: 30 }')"Response (200 inside the wait, else 202):
{ "id": "run_65f1c0a2b9d3e4f5a6b7c903", "status": "succeeded",
"output_parsed": { "version_bump": "minor", "markdown": "## What's new\n- Faster checkout (#312)\n…" } }If the status is not final, long-poll: GET /agents/runs/run_…?wait=50 until it is. A failed or cancelled run should fail the pipeline step, and a cancelled pipeline should cancel the run (POST /agents/runs/{id}/cancel).
Complete pipelines with the polling loop, the failure handling and the cancel step:
- GitHub Actions: PR review that posts a comment and a job summary, and a tag-triggered release-notes workflow.
- Azure DevOps: PowerShell and bash versions with
##vsovariables, secrets in a variable group and a cancel-on-abort step.
To have the agent react to pull requests, failed builds or alerts without a pipeline step (and without waiting for the verdict), use a webhook trigger: the sender posts the event, Console starts the run. The recipes cover pull request review on GitHub and Azure DevOps, build triage and alert runbooks.

