Connect the agent

Wire the SDK into your agent. Cooperative mode asks first; gateway mode executes protected calls with server-held credentials.

Install the SDK

Official clients for TypeScript/JavaScript and Python - both Apache-2.0 with zero runtime dependencies:

Install
# TypeScript / JavaScript
npm i @identiqube/provenant-sdk

# Python (imports as `provenant_sdk`)
pip install provenant-sdk

On the registries: @identiqube/provenant-sdk (npm) · provenant-sdk (PyPI). The examples below are TypeScript; the Python client mirrors the same surface (from provenant_sdk import ProvenantClient).

Cooperative mode

Set PROVENANT_API to the application origin (hosted: https://app.provenant.identiqube.com), without a trailing /v1. Use the agent's key as PROVENANT_KEY; the SDK sends it in x-provenant-key. Keep it in your server or agent runtime, never browser code. Dashboard sessions and downstream connector credentials are different credentials and cannot replace the agent key.

Your code holds the credential and asks first:

TypeScript
import { ProvenantClient } from '@identiqube/provenant-sdk';
const provenant = new ProvenantClient({ baseUrl: process.env.PROVENANT_API!, apiKey: process.env.PROVENANT_KEY! });

const d = await provenant.authorize({ type: 'payment.send', resource: 'vendor:acme', valueCents: 2500,
  idempotencyKey: 'invoice-9001-payment' });
if (d.status === 'authorized') {
  const ref = await payVendor({ vendor: 'acme', amountCents: 2500 });
  await provenant.complete(d.id, { success: true, externalRef: ref, warrant: d.authorizationToken! });
} else if (d.status === 'pending_approval') {
  // poll provenant.getAction(d.id) until authorized, then execute
} else {
  console.warn('denied:', d.decision.reason); // full trail in d.decision.checks
}
Python - read-only preflight
import os
from provenant_sdk import ProvenantClient

provenant = ProvenantClient(
    base_url=os.environ["PROVENANT_API"],
    api_key=os.environ["PROVENANT_KEY"],
)
preview = provenant.simulate({
    "type": "payment.send", "resource": "vendor:acme", "valueCents": 2500,
})
print(preview["decision"])

Simulation neither executes nor reserves spend. It previews current rules; authorization evaluates again when you submit.

Enforced (brokered) mode

Give the agent no independent downstream credential or route. In Govern → Connectors add a connector (the downstream target; its credential is stored server-side, never handed to the agent), then invoke through it:

TypeScript
const r = await provenant.invoke({ connectorId: 'con_…', type: 'payment.send', resource: 'vendor:acme', valueCents: 2500,
  args: { invoiceId: '9001' }, idempotencyKey: 'invoice-9001-gateway' });
// Provenant performs the call ONLY after an allow; denied/held never reach the resource.

Without request, invoke sends a fixed JSON envelope containing type, resource, valueCents and args to the connector endpoint. The target must understand that envelope. For an existing vendor API with its own payload schema, use a pass-through request instead.

If r.status is pending_approval, save r.action.id and pause this operation. Approval triggers server-side execution; fetch its state with getAction(r.action.id) to check completion. Follow the approval and agent-resumption lifecycle for retries and process restarts.

Gateway values inherit the mandate's unit. The public request schema has no explicit currency field. A currency inside a forwarded HTTP body does not change the governance denomination: ensure the downstream amount and currency agree with the declared value and mandate. See mandate value units.

Pass-through requests (call any API)

A connector stores the base URL + credential + policy scope; the agent supplies the actual request. type/resource/valueCents are caller-declared policy descriptors; request is the HTTP call to forward. Provenant does not infer those descriptors from an arbitrary vendor body. Use a trusted adapter to derive them and keep the connector's credential and scope narrow:

TypeScript
const r = await provenant.invoke({
  connectorId: 'con_…',
  idempotencyKey: 'invoice-9001-forward',
  type: 'payment.send', resource: 'vendor:acme', valueCents: 2500,  // ← evaluated by policy
  request: {                                                        // ← forwarded verbatim
    method: 'POST',
    path: '/v1/charges',           // resolved against the connector base URL, CONFINED to its host
    headers: { 'content-type': 'application/json' },
    body: JSON.stringify({ amount: 2500, currency: 'usd', source: 'tok_x' }),
  },
});
// r.output = { status, headers, body }  ← the downstream response, returned to the agent

Safety

The path is confined to the connector's host and base path (sibling-prefix and encoded-traversal escapes are rejected). The server-held credential overrides any auth header the agent sets, and credential-bearing response headers (set-cookie, authorization, …) are stripped before the response reaches the agent.

MCP gateway

Configure an MCP client that supports JSON-RPC over HTTP at POST /v1/mcp, with the agent key inx-provenant-key. This endpoint advertises protocol version 2024-11-05 and tool capabilities; it is not a stdio command. Your connectors appear as tools and every tools/call is policy-gated.

Framework tool wrappers

Already using an agent framework? Wrap any tool's executor with governTool (TypeScript) or govern_tool (Python): every call is authorized, executed, and completed through Provenant, with no change to how your framework invokes the tool.

TypeScript - framework-independent wrapper
import { governTool } from '@identiqube/provenant-sdk';
const governedPay = governTool(provenant, payVendor, {
    type: 'payment.send',
    resource: (a) => `vendor:${a.vendor}`,
    valueCents: (a) => a.amountCents,
});
Python - LangChain / CrewAI
from provenant_sdk import govern_tool

governed_pay = govern_tool(
    provenant, pay_vendor,
    type="payment.send",
    resource=lambda a: f"vendor:{a['vendor']}",
    value_cents=lambda a: a["amount_cents"],
)  # hand governed_pay to LangChain / CrewAI / LangGraph like any tool fn

On allow the tool runs and the outcome is reported for you. On deny or hold-for-approval the tool never runs and the call returns a { provenant: "blocked", status, reason, … } object your model reads as the tool result - so the agent explains the refusal instead of acting.

These wrappers use cooperative authorization: your process still holds the downstream credential. They do not automatically resume a held tool after approval. Register the wrapped function using your framework's tool API and persist any held action ID in your workflow; see approval recovery.

Responses, retries and recovery

ResponseMeaningCaller action
200Authorization, execution or credential issuance succeeded, depending on the endpointInspect status; authorized is not the same as completed.
202 pending_approvalNo execution or credential issuance yetPersist the action ID and resume using the approval lifecycle.
403 deniedA policy decision blocked the actionInspect decision.checks; do not retry unchanged intent with fresh keys.
400 / 401 / 404 / 409Invalid input, authentication, missing resource or conflictInspect the error body and correct the cause. A 403 error body can also be access control, not a decision.
429HTTP request rate limitBack off; this differs from a mandate rate-limit decision.
502 failed / connection timeoutGateway failure or uncertain transport outcomeRead the existing action and reconcile downstream before any new operation.

Authorize returns an action directly (id, status, decision); invoke and credential issuance wrap it under action. Invoke returns output on execution; subsequent HTTP action reads expose an executionResult summary (success, detail, external reference), not the original downstream body. The current TypeScript action type does not declare this summary field. Persist immediate response data your workflow needs, or retrieve the business result from the provider after approval. Policy denial and approval holds are normal SDK results; validation, authentication and other request errors can throw. Handle transport and non-JSON proxy errors too. Browser challenges must not gate machine API paths on your reverse proxy.

The deployment also serves /openapi.json at the application origin. Agent endpoints usex-provenant-key; dashboard administration endpoints require a user session and the appropriate role. To locate a connector ID without the dashboard, call connectors() orGET /v1/connectors/available with the agent key and select by endpoint and scope.

Assign one durable idempotency key per logical operation, reuse the same payload on retries, and use a new key only for a new operation. A changed payload or operation with an existing key conflicts. Do not assume this provides exactly-once execution at an external provider: a timeout or crash can leave an unknown outcome. Use provider idempotency where supported and reconcile before resubmitting. Idempotency is tied to stored action history, not a permanent deduplication service.

Credentials are returned on successful issuance only and are not recoverable by polling the action. A replay after issuance conflicts rather than minting again. If that response is lost, investigate the provider-side credential before creating another request. Never put a returned credential in logs, a model prompt or an audit export.

Deeper automation (agent-driven)

  • Discovery - provenant.connectors() returns the org's enabled connectors (id, name, scope, base host, auth summary - never secrets), so ids needn't be hard-coded.
  • Capability routing - call invoke({ type, resource, request }) without connectorId; Provenant routes to the connector whose scope matches. One match → used; none or multiple → conflict (HTTP 409; pass an explicit id to disambiguate multiple matches).
  • Self-registration - an agent can spawn an attenuated child at runtime:
TypeScript
const { key } = await provenant.spawn({
  name: 'invoice-worker',
  mandate: { name: 'narrowed', allowedActions: ['payment.send'], allowedResources: ['vendor:acme'],
             maxActionValueCents: 50_00, requireApprovalOverCents: 0, rateLimitPerMinute: 30 },
});

The requested child mandate must be no broader than its parent's; requests that widen authority are rejected. Children inherit the parent's environment, value unit and tags, retaining tag-based policy and budget coverage. Children are linked to the parent in the ledger (the agent.created entry records the parent and the delegation), bounded by a depth limit shown on the agent's lineage card, and cascade-revoked with the parent. An agent's detail page shows its parent and delegated children.