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:
# TypeScript / JavaScript
npm i @identiqube/provenant-sdk
# Python (imports as `provenant_sdk`)
pip install provenant-sdkOn 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:
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
}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:
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:
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 agentSafety
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.
import { governTool } from '@identiqube/provenant-sdk';
const governedPay = governTool(provenant, payVendor, {
type: 'payment.send',
resource: (a) => `vendor:${a.vendor}`,
valueCents: (a) => a.amountCents,
});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 fnOn 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
| Response | Meaning | Caller action |
|---|---|---|
| 200 | Authorization, execution or credential issuance succeeded, depending on the endpoint | Inspect status; authorized is not the same as completed. |
| 202 pending_approval | No execution or credential issuance yet | Persist the action ID and resume using the approval lifecycle. |
| 403 denied | A policy decision blocked the action | Inspect decision.checks; do not retry unchanged intent with fresh keys. |
| 400 / 401 / 404 / 409 | Invalid input, authentication, missing resource or conflict | Inspect the error body and correct the cause. A 403 error body can also be access control, not a decision. |
| 429 | HTTP request rate limit | Back off; this differs from a mandate rate-limit decision. |
| 502 failed / connection timeout | Gateway failure or uncertain transport outcome | Read 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 })withoutconnectorId; 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:
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.