> ## Documentation Index
> Fetch the complete documentation index at: https://docs.checkfu.com/llms.txt
> Use this file to discover all available pages before exploring further.

> ## Agent Instructions
> Base URL: https://api.checkfu.com. Current wire version: `2026-08-31` (`Checkfu-Version: 2026-08-31`).
> Mutating HTTP requests require `Authorization: Bearer $CHECKFU_API_KEY`, `Checkfu-Version: 2026-08-31`, `Content-Type: application/json`, and `Idempotency-Key` on retriable writes. Ordinary API keys are Workspace-bound; do not send a Workspace selector header.
> Core workflow: create an Agent (`POST /v1/agents`) and Environment (`POST /v1/environments`), grant `use_environment` (`POST /v1/permission-assignments`), create a Session (`POST /v1/sessions`), send events (`POST /v1/sessions/{id}/events`), stream progress (`GET /v1/sessions/{id}/events/stream`), and read the input result (`GET /v1/sessions/{id}/inputs/{input_id}/result`).
> Domain model: an Agent is mutable configuration; a Session freezes its AgentVersion and Environment at creation and owns its private workspace and ordered event history. Vault stores secret credentials; Connection links an external account; ActionApproval records human approval before an action runs.
> Capability status combines `audience`, `stability`, `availability`, evaluated prerequisites, and release evidence; check https://docs.checkfu.com/getting-started/status (`GET /v1/support/capabilities`) for live `available` status.

# Call an Agent for its result

> Let a caller send work to a placed Agent and read back only the answer to their own message.

A result-only service lets another system, or a person, send work to your [Agent](https://docs.checkfu.com/concepts/agents.md) and get back the answer to their own message. The Agent runs as a fixed service Principal you chose. The caller never sees its prompts, tool output, sources, approvals, or anyone else's work.

The caller talks to an `AgentPlacement` over [A2A](https://docs.checkfu.com/reference/a2a.md) with `createPlacementCaller` from the [TypeScript SDK](https://docs.checkfu.com/reference/typescript-sdk.md). It holds only `invoke` on the placement.

Before starting, have:

* An autonomous `AgentPlacement` (`aplace_…`) with its service Principal in `acted_as`. See [Installations and placements](https://docs.checkfu.com/reference/a2a.md#installations).
* The caller's `service` or `person` Principal (`prin_…`).

> [!NOTE]
>
> Plain HTTP against the Checkfu API needs no private package.
> The Checkfu CLI and TypeScript SDK are optional private-alpha artifacts; the HTTP requests work without them.
> The documented path is usable as written for an admitted Workspace.
> Confirm [capability status](https://docs.checkfu.com/getting-started/status.md) before making availability part of your application's contract.

## 1. Give the caller `invoke` and a credential

Grant the caller `invoke` on the placement. Do not grant `observe`: that would let them read whole tasks and history.

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl --request POST https://api.checkfu.com/v1/permission-assignments \
  --header "Authorization: Bearer $CHECKFU_API_KEY" \
  --header "Checkfu-Version: 2026-08-31" \
  --header "Idempotency-Key: partner-invoke-grant" \
  --header "Content-Type: application/json" \
  --data '{
    "subject": { "type": "principal", "id": "prin_fedcba9876543210fedcba9876543210" },
    "resource": { "type": "agent_placement", "id": "aplace_0123456789abcdef0123456789abcdef" },
    "permission": "invoke"
  }'
```

Then issue the caller an `a2a` credential and hand it over once:

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl --request POST \
  https://api.checkfu.com/v1/principals/prin_fedcba9876543210fedcba9876543210/access-credentials \
  --header "Authorization: Bearer $CHECKFU_API_KEY" \
  --header "Checkfu-Version: 2026-08-31" \
  --header "Idempotency-Key: partner-a2a-credential" \
  --header "Content-Type: application/json" \
  --data '{"audience":"a2a"}'
```

## 2. Send a message

The caller creates a placement caller with that credential. It never uses an API key:

```ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
import { createPlacementCaller, PlacementCallRefused } from "@checkfu/sdk"

const placement = createPlacementCaller({
  workspace: "wrkspc_0123456789abcdef0123456789abcdef",
  placement: "aplace_0123456789abcdef0123456789abcdef",
  credential: process.env.CHECKFU_A2A_CREDENTIAL!,
})

const sent = await placement.send({
  messageId: "order-4821-review",
  text: "Check order 4821 against the refund policy and say whether to refund.",
})
```

Choose a `messageId` you can find again, such as your own record's ID. It is scoped to this caller and this placement.

## 3. Read the result

`send` waits until the task settles or stops to wait, for example on `TASK_STATE_INPUT_REQUIRED`. Check `task.status.state`:

```ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
const task = sent.task
if (task?.status.state === "TASK_STATE_REJECTED") {
  // The placement refused the send, for example because invoke was revoked.
} else if (task?.status.state === "TASK_STATE_COMPLETED") {
  for (const artifact of task.artifacts ?? []) {
    for (const part of artifact.parts) if (part.text !== undefined) console.log(part.text)
  }
}
```

To read the result again later, or after a lost response, send the same `messageId` with the same text. Checkfu answers with the original task and starts no new work. Do not pass `taskId` or a nonzero `historyLength`: those are task reads and need `observe`.

```ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
const again = await placement.send({
  messageId: "order-4821-review",
  text: "Check order 4821 against the refund policy and say whether to refund.",
})
```

`getTask` and `cancelTask` follow the task-read rules, so an `invoke`-only caller gets `PlacementCallRefused`.

## 4. Cancel your own message

`cancelOwn` withdraws a message that has not run, or stops a Run that holds only that message:

```ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
try {
  const { state } = await placement.cancelOwn("order-4821-review")
  // "withdrawn", "canceled", or the state of a message that had already settled.
} catch (error) {
  if (error instanceof PlacementCallRefused && error.reason === "not_cancelable") {
    // Its Run also holds other input. Nothing was changed.
  } else throw error
}
```

It never stops other callers' work. See [Cancel your own message](https://docs.checkfu.com/reference/a2a.md#cancel-own-message) for every answer.

## What the caller can and cannot do

| The caller can | The caller cannot |
| - | - |
| Send a message and read the answer to it | Read the task history, prompts, or tool output |
| Replay their own message by `messageId` | See another caller's messages or results, even in the same Run |
| Cancel their own message | Cancel the task, or another caller's message |

Every send, replay, and cancel checks the placement and the caller's `invoke` again. Revoke `invoke` or the credential to cut a caller off; their next call is refused.

Keep business limits, such as which customer's records the Agent may touch, in the tools and Connections the service Principal holds. A sentence in the message is not a control.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.