Evidence
Documentation

Version Latest

Push receivers

Receive OpenTelemetry events from Claude Code, Gemini CLI and OpenAI Codex, and JSON audit records from any service, with revocable ingest tokens and content withheld unless you choose to store it.

Some tools send events instead of being polled. Govern has two receivers, served by the Govern server before session authentication and authenticated by ingest tokens:

ConnectorReceiverWhat sends
claude-codePOST /api/v1/vendor-audit/otlp/v1/logsClaude Code's OpenTelemetry log events
gemini-clithe sameGemini CLI's OpenTelemetry log events
codexthe sameOpenAI Codex's OpenTelemetry log events
webhookPOST /api/v1/vendor-audit/webhookJSON audit records from any service: Notion, Perplexity Enterprise, an internal gateway, a SIEM forwarder

Ingest tokens

POST /api/v1/vendor-audit/connectors/claude-code/tokens
{"name": "engineering laptops"}
  • Needs vendoraudit.connectors:manage. The answer is 201 with the token (kvat_...), shown once, and setup: the endpoint, the file the settings go in, its format and the settings with the token filled in.
  • Govern keeps only the token's SHA-256. At most 20 active tokens per connector.
  • The token decides the organisation and the connector. A token of one agent's connector never files records under another's, and OTLP and webhook tokens are not interchangeable (401).
  • GET .../tokens lists tokens (id, name, prefix, created_at, last_used_at, revoked_at, active); DELETE .../tokens/{tokenID} revokes one. Revoking the last active token turns the connector off.
  • Turning a push connector on needs an active token (409 ingest_token_required).

Claude Code

  1. Create a claude-code token. The setup carries the managed settings to deploy: CLAUDE_CODE_ENABLE_TELEMETRY=1, OTEL_LOGS_EXPORTER=otlp, OTEL_EXPORTER_OTLP_LOGS_PROTOCOL=http/protobuf, OTEL_EXPORTER_OTLP_LOGS_ENDPOINT=<your API URL>/api/v1/vendor-audit/otlp/v1/logs and the token in OTEL_EXPORTER_OTLP_LOGS_HEADERS. Only the logs signal is configured.
  2. Deploy them as Claude Code managed settings, which developers and repositories cannot override.
  3. Turn the connector on.

Each record becomes one event of type claude_code.<event name> (user_prompt, tool_result, tool_decision, api_request, api_error and others), with the actor from the user's email and account id and the session as the resource.

SettingDefaultEffect
store_promptsoffStore prompt and response text, raw API bodies and the system prompt; the setup also asks Claude Code to send them
store_tool_detailsoffStore tool parameters, inputs, output and error text
anthropic_organization_idemptyRefuse events from any other Anthropic organisation, for example a developer's personal account

Withheld attribute names are listed in the stored payload.

Gemini CLI

The token comes with the telemetry block of Gemini CLI's system settings (/etc/gemini-cli/settings.json on Linux, /Library/Application Support/GeminiCli/settings.json on macOS, C:\ProgramData\gemini-cli\settings.json on Windows, which override user settings). The endpoint is <your API URL>/api/v1/vendor-audit/otlp; Gemini CLI appends /v1/logs. Events are gemini_cli.<name>. store_prompts and store_tool_details work as for Claude Code.

OpenAI Codex

The token comes with the [otel] table for Codex's config.toml, exporting to .../otlp/v1/logs over binary protobuf with the token in an Authorization header. otel keys in a project's .codex/config.toml are ignored by Codex, so place it in the user or managed configuration. Events are codex.<name>. Of the per-chunk sse_event records, only response.completed, response.failed and errored ones are stored.

The audit webhook

POST /api/v1/vendor-audit/webhook
Authorization: Bearer kvat_...
Content-Type: application/json

{"events": [{"id": "evt_123", "timestamp": "2026-10-16T12:00:00Z", "type": "page.exported",
             "actor": {"email": "alice@example.com"}}]}
  • The body is one object, an array of objects, or an object whose events, records, data, logs or entries member is an array: up to 5,000 records, 4 MiB (16 MiB after gzip).
  • Identity from id, event_id, eventId, uuid, log_id or audit_log_id, else the record's content; with the organisation and the token's name it makes the event id, so a retried delivery stores nothing twice.
  • Time from timestamp, time, created_at, createdAt, event_time, eventTime, occurred_at, date or date_create (RFC 3339, Unix seconds or milliseconds); without one, the arrival time.
  • Type from event_type, eventType, type, action, event, name or operation (default event). Actor from actor_email, user_email, email, or email or login of an actor or user object.
  • The token's name is the events' source. The record is stored as sent: the sender's own settings decide what content reaches Govern.

The answer is 200 {"accepted", "stored", "rejected", "reason"}.

Limits and answers

OTLPWebhook
Content typesapplication/x-protobuf, application/jsonapplication/json
Body8 MiB, 32 MiB after gzip4 MiB, 16 MiB after gzip
Records per request10,0005,000
  • Content-Encoding other than gzip is 415.
  • A record over 256 KiB, timed before 1970 or more than a day ahead is rejected on its own and counted (OTLP partial success; webhook rejected and reason): one bad record never fails a batch.
  • 401 for a missing, unknown or revoked token; 403 when the connector is off; 503 on a store failure (retry).
  • Each token is rate limited on its own: 20,000 requests a minute, burst 2,000.
  • A push connector reports pending until its first event and healthy afterwards. It cannot tell a quiet day from a broken sender.

Reading payloads of pushed events needs audit.vendor_content:view, as for pulled events. See Vendor AI audit connectors.

Last reviewed 17 October 2026View as Markdown

Push receivers · Docs · Neural Inverse