Skip to main content
Checkfu can expose an installed agent as an Agent2Agent Protocol server. The protocol boundary is a projection of Checkfu’s existing authority: an Agent Card describes one live installation and SurfaceScope, an A2A task is one Session, and task state and artifacts come from that Session’s event log. A2A never grants access, settles work outside the log, or connects two Checkfu agents inside one Workspace.
Checkfu currently serves A2A v1.0 over JSON-RPC 2.0 and SSE. Send A2A-Version: 1.0 on every RPC request. The protocol treats an absent header as v0.3, which Checkfu deliberately rejects with VersionNotSupportedError.

Find the endpoint

Each active AgentInstallation and SurfaceScope pair has two URLs:
The Agent Card is public and cacheable for 60 seconds. It carries an ETag, the exact JSON-RPC endpoint, supported text modes, streaming capability, and a projection of the installed release’s active skills. An archived agent or an inactive or mismatched installation/surface placement returns 404 instead of publishing a stale card.

Issue an A2A Principal credential

An A2A caller authenticates as one existing person Principal. Use an identity-admin API key to issue an audience-bound bearer; the secret appears only in this response:
The same PrincipalAccessCredential lifecycle endpoints used by API MCP callers list, rotate, and revoke this bearer. Its audience is immutable: an a2a bearer is rejected by /v1/mcp, and an api_mcp bearer is rejected by the A2A endpoint. Every request also rechecks the Principal, credential, installation placement, Session admission, PermissionAssignments, and ActionPolicy. Give the Principal invoke, steer, and observe on the installed agent and SurfaceScope required for the operations it will use. Task and occurrence identity is scoped to that Principal, AgentInstallation, and SurfaceScope. A provider-native conversation or another Principal using the same opaque context or message ID neither replays nor becomes visible as an A2A task.

Send and observe a task

Call the card’s JSON-RPC URL with the issued bearer:
SendMessage blocks until the task reaches a terminal or interrupted state by default, as A2A v1 requires. Set returnImmediately: true to receive the submitted or working Task and poll it with GetTask; use SendStreamingMessage or SubscribeToTask for ordered SSE updates. Reusing the same messageId is idempotent and returns the same Session-backed task. The endpoint supports SendMessage, SendStreamingMessage, GetTask, ListTasks, CancelTask, and SubscribeToTask. Only text/plain input and output are admitted in this version. Push notifications, protocol extensions, non-text message parts, and ZDR Sessions are rejected rather than accepted with weaker custody or incomplete behavior. This interface is routed by its installation-and-surface URL, so omit the A2A tenant request field (the Agent Card does not advertise one). Message extension URIs and referenceTaskIds are also rejected in this version rather than silently ignored; a terminal task cannot accept another message or a new subscription.
A2A is only an external interoperability edge. To let one Checkfu agent call another in the same Workspace, use multiagent threads or a shared conversation surface; routing that traffic through A2A would bypass the canonical workspace collaboration model.

Consume an external A2A agent

An external A2A agent is a governed ToolSource, not a coordinator-roster member. An operator first reviews a ProviderPackage whose egress ceiling admits exactly the public Agent Card GET and JSON-RPC POST, then registers the card URL and its reviewed ES256 public JWK:
Sync verifies a detached ES256 signature over canonical card JSON and chooses one A2A v1 JSON-RPC interface. Checkfu rejects unsigned cards, unsupported required extensions, non-text input or output, and cards without exactly one supported security alternative. A supported alternative is one Bearer scheme with no scopes, one OAuth2 authorization-code scheme whose exact, duplicate-free required scopes the card declares, or one mTLS scheme with no scopes. Ambiguous alternatives and other OAuth2 flows fail closed. Each card skill becomes an always-ask Tool; the Tool stores the card, endpoint, and key fingerprints plus only the selected scheme name, flow, and scope set—never the card body, OAuth endpoints, or a credential. Rotate trust with POST /v1/tool-sources/{id}/source-revisions and a required Idempotency-Key, not an ordinary sync. For a source already backing Connections, first publish a higher host-configured ProviderPackage whose A2A source contains both the old and new keys and declares every live predecessor version compatible. Then submit the candidate source, exact package identity, and the complete sorted list of dependent Connection IDs with their current versions. Checkfu requires a monotonically higher compatible package for each dependent Connection, verifies discovery before it publishes the source, and durably resumes the version-fenced Connection migration after interruption. An unused source still has to match the exact current host package, but has no earlier Connection package binding to migrate. Once the peer signs with the new key, repeat the operation with another higher host-configured package that removes the old key. Restoring an old key is the same forward-only process with a still-higher host-configured package. Rotation and rollback perform the bounded, credential-free card discovery GET, but never read a credential or call an executable provider endpoint. Audit records distinguish a source revision (or failed revision) from an ordinary sync and record each dependent Connection package migration separately. Attach the discovered Tool and its Connection to an Agent as usual. At runtime, the CapabilityGateway rechecks PermissionAssignments, ActionPolicy, ActionApproval, the frozen ProviderPackage, the live Connection revision and scopes, the signed binding, and exact egress before custody injects the peer credential. An OAuth2 selection requires a custody-managed OAuth ProviderPackage and scopes within both its reviewed ceiling and the Connection. Checkfu never follows a card-declared authorization, token, refresh, or metadata URL: the already-qualified Connection custody adapter obtains, refreshes, revokes, and injects the token only at its outbound transport edge. The token never appears on the Tool, task custody, event log, sandbox boundary, or result receipt. An mTLS selection requires a custody-managed mTLS ProviderPackage and a deployment-reviewed Worker certificate binding. The integration configuration names only the binding, a generation marker, certificate expiry, and the exact allowed peer hostnames; the certificate and private key are uploaded through the Worker platform and are not JSON configuration. Hosted setup activates the Connection without a credential form. Certificate rotation keeps the Connection ID, but the operator must advance the generation/expiry metadata and use the ordinary reconnect link so the sealed custody record advances before provider traffic resumes. Checkfu checks the configured hostname set and the Worker fetcher performs ordinary server-certificate hostname verification. If the signed Agent Card declares streaming and the frozen Connection custody adapter supports it, Checkfu sends one SendStreamingMessage. It attaches the first active task before accepting ordered artifact or status updates, requires the exact JSON-RPC, task, and context identity throughout, and closes the SSE body at terminal state. Resume uses SubscribeToTask, never another send. A disconnect after durable task identity falls back to the same fenced GetTask observer; a disconnect before identity is indeterminate. If either the card or custody adapter lacks streaming support, Checkfu sends one SendMessage and uses GetTask as the baseline observer. In every mode, the final task becomes one CapabilityGateway ToolInvocation result and one exec.tool_invocation event. Replay the exact pending call after an observation failure: it retains the original ActionApproval and resumes only the matching durable child. A lost or invalid send response before task attachment is never replayed. Polling starts immediately, then uses deterministic task-specific exponential backoff with bounded jitter. A syntactically valid HTTP Retry-After on a temporary 429 or 503 response may extend the local delay; other statuses, malformed values, and non-HTTP date formats are ignored. Peer guidance and local backoff are both capped, the immutable hard deadline always wins, and a failure releases the fenced observer while retaining the exact next due time for resume. A host-lifetime ceiling also bounds concurrent polls for one reviewed Agent Card coordinate without holding a task lease while queued. Operational counters and poll spans contain only closed outcome, schedule, attempt-bucket, and fresh/resume labels—never peer coordinates, task IDs, request IDs, provider content, or credentials. SSE parsing is strict and bounded: the response must negotiate A2A v1 and text/event-stream, the total stream and each event have fixed byte ceilings, artifact chunks must be ordered, and task/context identity cannot change. A caller cancellation or hard deadline interrupts provider reading, releases the owned response body and fenced custody lease, and leaves no provider content in durable task state. Every attached task has an immutable hard deadline. A bounded scheduled sweep finds due structural custody without calling the peer, expires the child, and asks the CapabilityGateway to settle that exact ToolInvocation and Session execution as indeterminate with a terminal audit record. The child records reconciliation completion only after those authorities accept it, so a process loss resumes the same settlement on a later bounded sweep without another provider request or a second durable result. This expiry is Checkfu’s local indeterminate settlement, not evidence that the remote peer canceled or stopped its task. Outbound consume supports A2A v1.0 JSON-RPC with text/plain messages; Bearer, reviewed OAuth2 authorization-code, or reviewed mTLS card authentication; bounded GetTask polling; and signed-card-gated SSE through SendStreamingMessage and SubscribeToTask. When a signed card instead declares push notifications, Checkfu registers a task-scoped HTTPS callback with a generated Bearer value, stores only its digest, and accepts bounded application/a2a+json notifications as wake signals. The callback body never settles the call or enters durable custody: Checkfu re-reads the exact task with authenticated GetTask, and polling remains the missed-notification fallback. API-key, OIDC, non-authorization-code OAuth2, and required protocol extensions remain rejected rather than silently degraded.