API Reference
The lakefrontai REST API lets you ingest AI agent events, generate Visa CE 3.0 chargeback packets, manage disputes, and run behavioral fingerprinting and cryptographic attestation. All endpoints return JSON. All requests must include an API key.
Quickstart
Get from zero to your first evidence event in under 5 minutes.
1. Get an API key
Create a key in the dashboard under Admin → API Keys. Keys are prefixed lf_.
2. Send your first event
curl -X POST https://api.lakefrontai.com/events \
-H "Authorization: Bearer lf_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"event_id": "evt_001",
"session_id": "ses_abc123",
"mandate_id": "man_xyz789",
"agent_id": "agent_checkout_v2",
"sequence_number": 1,
"category": "payment",
"method": "stripe.charge",
"status": "success",
"initiated_at": 1718000000000,
"data": {
"amount": 4999,
"currency": "usd",
"customer": "cus_abc"
}
}'bashResponse
{
"ok": true,
"event_id": "evt_001",
"chain_hash": "sha256:a3f9e1c2..."
}json3. Export a Visa CE 3.0 packet
curl -X POST https://api.lakefrontai.com/disputes/dsp_001/packet \
-H "Authorization: Bearer lf_your_api_key"bashResponse
{
"case_reference": "dsp_001",
"status": "open",
"prior_undisputed_transactions": [...],
"evidence_events": [...],
"chain_valid": true,
"generated_at": "2026-06-20T10:00:00.000Z"
}jsonAuthentication
Every request (except GET /health and POST /auth/login) requires a Bearer API key in the Authorization header.
Authorization: Bearer lf_your_api_keybash/auth/loginExchange email + password for a session token (for dashboard use). Not needed for API key auth.
emailstringrequiredEmail address of the dashboard user.
passwordstringrequiredAccount password.
curl -X POST https://api.lakefrontai.com/auth/login \
-H "Content-Type: application/json" \
-d '{ "email": "you@example.com", "password": "s3cret" }'bashResponse
{
"token": "eyJhbGc...",
"user": {
"id": "usr_001",
"email": "you@example.com",
"role": "admin"
}
}jsonEvent ingestion
Events are the core primitive. Each event represents a single AI agent action and is linked into a SHA-256 hash chain. Any post-hoc modification breaks the chain.
/eventsAPI keyIngest a single evidence event.
event_idstringrequiredGlobally unique ID for this event. Use UUID v4 or a deterministic hash.
session_idstringrequiredGroups events from the same user session.
mandate_idstringrequiredThe agent mandate / task ID this event belongs to.
agent_idstringrequiredIdentifier of the AI agent that performed the action.
sequence_numbernumberrequiredMonotonically increasing integer within a session. Gaps are flagged.
categorystringrequiredEvent category: payment | auth | data | tool | decision.
methodstringrequiredThe specific API or action called, e.g. stripe.charge.
statusstringrequiredsuccess | failure | pending.
initiated_atnumberrequiredUnix millisecond timestamp when the agent initiated the action.
dataobjectrequiredArbitrary JSON payload — the evidence body. PII is automatically redacted.
x-attestation-tokenheaderoptionalRequired if the agent has Layer 3 credentials registered. Pass the token returned by POST /attestation/verify.
curl -X POST https://api.lakefrontai.com/events \
-H "Authorization: Bearer lf_your_api_key" \
-H "Content-Type: application/json" \
-H "x-attestation-token: at_abc..." \
-d '{
"event_id": "evt_stripe_charge_001",
"session_id": "ses_user_42_checkout",
"mandate_id": "man_purchase_flow_v3",
"agent_id": "agent_checkout_v2",
"sequence_number": 3,
"category": "payment",
"method": "stripe.charge",
"status": "success",
"initiated_at": 1718000000000,
"data": {
"amount": 4999,
"currency": "usd",
"customer_id": "cus_abc",
"description": "Pro plan subscription"
}
}'bashResponse
{
"ok": true,
"event_id": "evt_stripe_charge_001",
"chain_hash": "sha256:d4e5f6a7b8..."
}json/events/batchAPI keyIngest up to 100 events in a single request. More efficient than individual calls.
curl -X POST https://api.lakefrontai.com/events/batch \
-H "Authorization: Bearer lf_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"events": [
{
"event_id": "evt_001", "session_id": "ses_abc",
"mandate_id": "man_xyz", "agent_id": "agent_v2",
"sequence_number": 1, "category": "auth",
"method": "stripe.customer.retrieve", "status": "success",
"initiated_at": 1718000000000, "data": { "customer": "cus_abc" }
},
{
"event_id": "evt_002", "session_id": "ses_abc",
"mandate_id": "man_xyz", "agent_id": "agent_v2",
"sequence_number": 2, "category": "payment",
"method": "stripe.charge", "status": "success",
"initiated_at": 1718000001000, "data": { "amount": 4999 }
}
]
}'bashResponse
{
"ok": true,
"accepted": 2,
"rejected": 0
}json/eventsAPI keyList evidence events with optional filters.
session_idquery stringoptionalFilter by session.
agent_idquery stringoptionalFilter by agent.
limitquery numberoptionalMax results (default 50, max 500).
curl "https://api.lakefrontai.com/events?session_id=ses_abc&limit=20" \
-H "Authorization: Bearer lf_your_api_key"bash/events/streamAPI keyServer-Sent Events stream — real-time event feed. Auth via Bearer token in Authorization header.
const es = new EventSource(
"https://api.lakefrontai.com/events/stream",
{ headers: { Authorization: "Bearer lf_your_api_key" } }
);
es.onmessage = (e) => {
const event = JSON.parse(e.data);
console.log(event.method, event.status);
};js/events/exportAPI keyExport events as a CSV download. Accepts the same query params as GET /events.
curl "https://api.lakefrontai.com/events/export?session_id=ses_abc" \
-H "Authorization: Bearer lf_your_api_key" \
-o events.csvbashMandates
A mandate is the authorization contract between a human and an AI agent. Every evidence event must reference a mandate. Mandates carry optional spending limits, per-scope constraints, velocity limits, and an expiry. Once revoked, new events under that mandate are rejected.
/mandatesAPI keyCreate a new agent mandate.
agent_idstringrequiredThe agent this mandate authorizes.
display_namestringrequiredHuman-readable name, e.g. "Monthly subscription renewal bot".
authorized_scopesstring[]requiredList of permitted action scopes: payment, refund, data_read, data_write, auth, tool, decision.
expires_atstringrequiredISO 8601 expiry. Must be a future date. Events after expiry are rejected.
issued_bystringrequiredEmail or ID of the human who authorized this mandate.
spending_limitnumberoptionalMax cumulative spend in cents (e.g. 100000 = $1,000). Enforced by the budget API.
currencystringoptionalISO 4217 currency code. Default USD.
constraintsobjectoptionalPer-scope limits — see Budget constraints below.
notesstringoptionalInternal notes.
curl -X POST https://api.lakefrontai.com/mandates \
-H "Authorization: Bearer lf_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"agent_id": "agent_checkout_v2",
"display_name": "Monthly subscription renewal bot",
"authorized_scopes": ["payment", "data_read"],
"spending_limit": 100000,
"currency": "USD",
"expires_at": "2027-01-01T00:00:00.000Z",
"issued_by": "admin@company.com",
"notes": "Authorized in board meeting 2026-06-01",
"constraints": {
"payment": {
"max_amount_per_tx": 4999,
"max_tx_per_day": 10,
"allowed_currencies": ["USD", "EUR"],
"require_mfa": false
}
}
}'bashResponse
{
"id": "man_7f3a9c",
"agent_id": "agent_checkout_v2",
"display_name": "Monthly subscription renewal bot",
"authorized_scopes": ["payment", "data_read"],
"spending_limit": 100000,
"currency": "USD",
"state": "active",
"expires_at": "2027-01-01T00:00:00.000Z",
"issued_by": "admin@company.com",
"created_at": "2026-06-22T10:00:00.000Z"
}json/mandatesAPI keyList all mandates. Pass ?state=active|revoked|expired to filter.
curl "https://api.lakefrontai.com/mandates?state=active" \
-H "Authorization: Bearer lf_your_api_key"bash/mandates/:idAPI keyGet a single mandate with its full constraints and budget state.
curl https://api.lakefrontai.com/mandates/man_7f3a9c \
-H "Authorization: Bearer lf_your_api_key"bash/mandates/:idAPI keyUpdate a mandate's limits, scopes, or expiry. Cannot update a revoked mandate.
spending_limitnumberoptionalNew cumulative spending cap in cents.
expires_atstringoptionalNew expiry — must be in the future.
authorized_scopesstring[]optionalReplace the authorized scope list.
constraintsobjectoptionalReplace per-scope constraints.
notesstringoptionalUpdate notes.
curl -X PATCH https://api.lakefrontai.com/mandates/man_7f3a9c \
-H "Authorization: Bearer lf_your_api_key" \
-H "Content-Type: application/json" \
-d '{ "spending_limit": 200000, "expires_at": "2027-06-01T00:00:00.000Z" }'bash/mandates/:id/revokeAPI keyPermanently revoke a mandate. Subsequent events referencing it will be rejected.
revoked_bystringrequiredEmail or ID of the person revoking.
reasonstringoptionalReason stored in the audit log.
curl -X POST https://api.lakefrontai.com/mandates/man_7f3a9c/revoke \
-H "Authorization: Bearer lf_your_api_key" \
-H "Content-Type: application/json" \
-d '{ "revoked_by": "admin@company.com", "reason": "Agent decommissioned" }'bashBudget constraints
The constraints object maps each authorized scope to a set of limits. All limits are optional — omit a field to leave it unconstrained.
{
"payment": {
"max_amount_per_tx": 4999, // max single-tx amount in cents
"max_tx_per_day": 10, // velocity: transactions per day
"max_tx_per_month": 50, // velocity: transactions per month
"cumulative_limit": 100000, // lifetime cap in cents
"allowed_currencies": ["USD"], // whitelist; omit for any
"allowed_merchants": ["stripe"], // whitelist of method prefixes
"require_mfa": false // block tx until consent confirmed
},
"refund": {
"max_amount_per_tx": 4999,
"max_tx_per_day": 5
}
}json/mandates/:id/budgetAPI keyGet live budget state — how much has been spent and how many transactions used.
curl https://api.lakefrontai.com/mandates/man_7f3a9c/budget \
-H "Authorization: Bearer lf_your_api_key"bashResponse
{
"mandate_id": "man_7f3a9c",
"spending_limit": 100000,
"amount_used": 23400,
"amount_remaining": 76600,
"currency": "USD",
"tx_today": 3,
"tx_this_month": 11
}json/mandates/:id/budget/reserveAPI keyAtomically check and reserve budget for an upcoming transaction. Returns 409 if the mandate would be exceeded.
amountnumberrequiredAmount in cents to reserve.
scopestringrequiredThe scope being exercised, e.g. payment.
currencystringoptionalISO 4217 currency. Defaults to the mandate's currency.
curl -X POST https://api.lakefrontai.com/mandates/man_7f3a9c/budget/reserve \
-H "Authorization: Bearer lf_your_api_key" \
-H "Content-Type: application/json" \
-d '{ "amount": 4999, "scope": "payment", "currency": "USD" }'bashResponse
{
"ok": true,
"reservation_id": "res_001",
"amount_reserved": 4999,
"amount_remaining": 71601
}jsonConsent artifacts
Consent artifacts cryptographically bind a human's explicit authorization to a mandate. The artifact includes a hash of the mandate terms so any post-hoc modification is detectable. Visa CE 3.0 packets automatically include consent verification.
/mandates/:id/consentAPI keyRecord a consent artifact for a mandate. The terms_hash is derived from the mandate body — pass the returned value to the customer for display.
consented_bystringrequiredEmail or customer ID of the person consenting.
consent_methodstringrequiredexplicit_click | voice | biometric | api_token.
ip_addressstringoptionalIP of the consenting party (stored in audit log).
user_agentstringoptionalBrowser / client user-agent string.
terms_presentedstringoptionalThe exact terms text shown to the user. Hashed and stored.
curl -X POST https://api.lakefrontai.com/mandates/man_7f3a9c/consent \
-H "Authorization: Bearer lf_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"consented_by": "customer@example.com",
"consent_method": "explicit_click",
"ip_address": "203.0.113.42",
"user_agent": "Mozilla/5.0 ...",
"terms_presented": "I authorize lakefrontai agent to charge up to $1,000 per month..."
}'bashResponse
{
"id": "con_001",
"mandate_id": "man_7f3a9c",
"consented_by": "customer@example.com",
"consent_method": "explicit_click",
"mandate_terms_hash":"sha256:f3a9c2b1...",
"recorded_at": "2026-06-22T10:00:00.000Z"
}json/mandates/:id/consentAPI keyGet the active consent record for a mandate, including tamper detection status.
curl https://api.lakefrontai.com/mandates/man_7f3a9c/consent \
-H "Authorization: Bearer lf_your_api_key"bashResponse
{
"consent": { "id": "con_001", "consented_by": "customer@example.com", ... },
"matches": true,
"mandate_terms_hash": "sha256:f3a9c2b1..."
}json/mandates/:id/consent/revokeAPI keyRevoke consent. The mandate itself remains active but the CE 3.0 packet will flag missing consent.
revoked_bystringrequiredWho is revoking consent.
reasonstringoptionalOptional reason.
curl -X POST https://api.lakefrontai.com/mandates/man_7f3a9c/consent/revoke \
-H "Authorization: Bearer lf_your_api_key" \
-H "Content-Type: application/json" \
-d '{ "revoked_by": "customer@example.com", "reason": "Customer request" }'bashDisputes & Visa CE 3.0 packets
A dispute links a chargeback case to one or more evidence sessions. Once linked, you can export a Visa CE 3.0-compliant evidence packet in one call.
/disputesAPI keyOpen a new dispute case.
session_idstringrequiredThe session whose events support this dispute.
case_referencestringrequiredYour internal case reference or the chargeback ID from your payment processor.
reason_codestringoptionalVisa/Mastercard reason code, e.g. 10.4.
notesstringoptionalInternal notes for your team.
curl -X POST https://api.lakefrontai.com/disputes \
-H "Authorization: Bearer lf_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"session_id": "ses_user_42_checkout",
"case_reference": "CB-2026-00441",
"reason_code": "10.4",
"notes": "Customer claims they did not authorise the $49.99 charge"
}'bashResponse
{
"id": "dsp_7f3a9c",
"session_id": "ses_user_42_checkout",
"case_reference": "CB-2026-00441",
"status": "open",
"created_at": "2026-06-20T10:00:00.000Z"
}json/disputesAPI keyList all disputes for your org.
curl https://api.lakefrontai.com/disputes \
-H "Authorization: Bearer lf_your_api_key"bash/disputes/:idAPI keyUpdate a dispute's status or notes.
statusstringoptionalopen | won | lost | closed.
notesstringoptionalUpdated notes.
curl -X PATCH https://api.lakefrontai.com/disputes/dsp_7f3a9c \
-H "Authorization: Bearer lf_your_api_key" \
-H "Content-Type: application/json" \
-d '{ "status": "won", "notes": "Visa accepted our CE 3.0 packet" }'bash/disputes/:id/packetAPI keyGenerate a Visa CE 3.0-compliant evidence packet for this dispute. Returns a JSON structure ready to attach to your chargeback response.
curl -X POST https://api.lakefrontai.com/disputes/dsp_7f3a9c/packet \
-H "Authorization: Bearer lf_your_api_key"bashResponse
{
"case_reference": "CB-2026-00441",
"status": "open",
"prior_undisputed_transactions": [
{
"transaction_id": "ch_prev1",
"amount": 4999,
"currency": "usd",
"date": "2026-05-01T00:00:00.000Z",
"description": "Pro plan - May"
}
],
"evidence_events": [
{
"event_id": "evt_stripe_charge_001",
"method": "stripe.charge",
"status": "success",
"initiated_at": 1718000000000,
"chain_hash": "sha256:d4e5f6..."
}
],
"chain_valid": true,
"generated_at": "2026-06-20T10:01:00.000Z"
}jsonDispute scoring
The scoring engine evaluates each dispute and returns a recommendation — fight or refund — with an evidence score (0–100) and a deflection strategy. It weighs consent presence, chain integrity, prior transaction history, mandate validity, and chargeback ratio governance.
Scoring signals
/disputes/:id/scoreAPI keyCompute the fight-vs-refund score for a dispute. Cached for 5 minutes.
curl https://api.lakefrontai.com/disputes/dsp_7f3a9c/score \
-H "Authorization: Bearer lf_your_api_key"bashResponse
{
"dispute_id": "dsp_7f3a9c",
"recommendation": "fight",
"evidence_score": 82,
"deflection_strategy": "submit_ce30_packet",
"signals": {
"consent_present": true,
"chain_valid": true,
"prior_tx_count": 3,
"mandate_valid": true,
"fingerprint_enrolled": true,
"attestation_verified": false,
"ratio_ok": true
},
"fight_threshold": 60,
"computed_at": "2026-06-22T10:00:00.000Z"
}jsonDeflection strategies
| Strategy | When used | Action |
|---|---|---|
submit_ce30_packet | Score ≥ 60 | Export CE 3.0 packet and respond to chargeback |
proactive_refund | Score < 60 | Issue refund before chargeback escalates |
request_more_evidence | Score 50–59 | Gather additional session evidence before deciding |
escalate_to_human | Consent mismatch | Flag for manual review due to consent anomaly |
/disputes/ratioAPI keyYour org's current chargeback ratio and governance thresholds (Visa: warn at 0.65%, block at 1.0%).
curl https://api.lakefrontai.com/disputes/ratio \
-H "Authorization: Bearer lf_your_api_key"bashResponse
{
"ratio": 0.0042,
"dispute_count": 12,
"transaction_count": 2857,
"warn_threshold": 0.0065,
"block_threshold": 0.01,
"status": "ok"
}jsonReason-code taxonomy
Traditional card disputes ask “did the cardholder make this purchase?” Agentic disputes decompose into a chain of authorization questions. lakefrontai maps every dispute onto a proprietary taxonomy with 5 families and 13 codes — each attacks a specific link in the mandate/evidence chain and is defended by a specific slice of evidence. Standard Visa and Mastercard codes are automatically normalized to internal codes on ingest.
AAAuthority absent / invalidNo mandate existed, or it had expired or been revoked when the agent acted.
ASScope / constraint breachAgent acted outside its granted scopes, over the spending limit, or exceeded velocity.
AIAgent identity / evidence integrityImpersonation, tampered evidence log, or replay of a valid historical action.
ACPrincipal / consumer claimCardholder repudiates authorization, claims malfunction, or merchandise not received.
ADDelegation chainA sub-agent acted without its own delegated mandate.
All reason codes
| Code | Family | Claim | Key evidence fields |
|---|---|---|---|
AA-01 | AA | No mandate ever existed for this agent | mandate.issued_by, consent.terms_hash, mandate.created_at |
AA-02 | AA | Mandate had expired when it acted | mandate.expires_at, event.initiated_at |
AA-03 | AA | Mandate was revoked before this action | mandate.revoked_at, chain.sequence |
AS-01 | AS | Agent acted outside its granted scope | mandate.authorized_scopes, event.category |
AS-02 | AS | Over amount / wrong merchant / wrong currency | mandate.constraints, event.toolArgs |
AS-03 | AS | Agent transacted more than permitted (velocity) | mandate.constraints.velocityMax, budget.ledger |
AI-01 | AI | That was not our agent (impersonation) | mandate.agent_id, attestation |
AI-02 | AI | The evidence log was altered after the fact | chain.previousHash, chain.integrity |
AI-03 | AI | A valid old action was replayed | event.event_id, chain.sequence |
AC-01 | AC | I never authorized this agent at all | consent.signature, consent.auth_method, consent.principal_email |
AC-02 | AC | The agent malfunctioned / hallucinated the order | event.preAction.context, constraint.conformance |
AC-03 | AC | Not received / not as described | event.postAction.result, fulfillment |
AD-01 | AD | A sub-agent acted without a delegated mandate | mandate.consent_id, delegation.chain |
Network code mapping
When you pass a standard Visa or Mastercard reason_code to POST /disputes, it is automatically normalized to the internal taxonomy. Unknown codes are stored as-is without classification.
| Network code | Network description | Maps to |
|---|---|---|
10.4 | Visa — Fraud, card-absent environment | AC-01 |
13.1 | Visa — Merchandise / services not received | AC-03 |
13.3 | Visa — Not as described / defective merchandise | AC-03 |
12.5 | Visa — Incorrect amount | AS-02 |
11.3 | Visa — No authorization | AA-01 |
4837 | Mastercard — No cardholder authorization | AC-01 |
4853 | Mastercard — Cardholder dispute, not as described | AC-03 |
4834 | Mastercard — Point-of-interaction error | AS-02 |
Agent fingerprinting
Behavioral fingerprinting builds a baseline profile of each agent across three layers: Layer 1 (timing, error rate, API diversity), Layer 2 (coefficient of variation, retry rate, burst coefficient, payload size, session rhythm), and Layer 3 (cryptographic attestation). Drift from baseline is scored 0–100.
/fingerprintsAPI keyList all agent fingerprint profiles for your org.
curl https://api.lakefrontai.com/fingerprints \
-H "Authorization: Bearer lf_your_api_key"bashResponse
[
{
"agent_id": "agent_checkout_v2",
"status": "enrolled",
"drift_score": 12.4,
"timing_p50": 142.3,
"timing_p95": 890.1,
"error_rate": 0.02,
"scope_utilization": 0.68,
"cv_timing": 0.31,
"retry_rate": 0.04,
"burst_coefficient": 1.12,
"registry_status": "approved",
"attestation_status": "verified",
"last_attested_at": "2026-06-20T09:00:00.000Z",
"enrolled_at": "2026-06-01T00:00:00.000Z"
}
]json/fingerprints/:agentIdAPI keyGet the full fingerprint profile for a specific agent, including similar agents and the API transition matrix.
curl https://api.lakefrontai.com/fingerprints/agent_checkout_v2 \
-H "Authorization: Bearer lf_your_api_key"bash/fingerprints/:agentId/resetAPI keyReset an agent's fingerprint back to the enrolling state. Useful after a legitimate agent update.
curl -X POST https://api.lakefrontai.com/fingerprints/agent_checkout_v2/reset \
-H "Authorization: Bearer lf_your_api_key"bash/fingerprints/backfillAPI keyTrigger fingerprint computation for all agents that have evidence events but haven't completed enrollment.
curl -X POST https://api.lakefrontai.com/fingerprints/backfill \
-H "Authorization: Bearer lf_your_api_key"bashResponse
{
"triggered": 3,
"agent_ids": ["agent_checkout_v2", "agent_refund_bot", "agent_kyc"]
}jsonFingerprint registry
The registry is agent-native MFA: once an agent enrolls, an admin approves its behavioral profile as the canonical identity. Future events are checked against the approved profile. Violations set registry_status = "challenged" even if the API key is valid.
/registryAPI keyList all fingerprint registry entries (pending, approved, revoked).
curl https://api.lakefrontai.com/registry \
-H "Authorization: Bearer lf_your_api_key"bashResponse
[
{
"id": "reg_001",
"agent_id": "agent_checkout_v2",
"status": "approved",
"profile_hash": "sha256:a1b2c3...",
"version": 2,
"reviewed_by": "admin@company.com",
"reviewed_at": "2026-06-10T09:00:00.000Z"
}
]json/registry/:id/approveAPI keyApprove a pending registry entry. The agent's current behavioral profile becomes the canonical baseline.
notesstringoptionalOptional reviewer notes.
curl -X POST https://api.lakefrontai.com/registry/reg_001/approve \
-H "Authorization: Bearer lf_your_api_key" \
-H "Content-Type: application/json" \
-d '{ "notes": "Verified with eng team — legitimate v2 deployment" }'bash/registry/:id/revokeAPI keyRevoke an approved registry entry. The agent will be marked challenged on next event.
reasonstringoptionalReason for revocation (stored in audit log).
curl -X POST https://api.lakefrontai.com/registry/reg_001/revoke \
-H "Authorization: Bearer lf_your_api_key" \
-H "Content-Type: application/json" \
-d '{ "reason": "Suspected compromise — pending investigation" }'bashLayer 3 — Cryptographic attestation
Layer 3 uses Ed25519 challenge-response to cryptographically prove an agent's identity at startup. A verified agent receives a 1-hour token which it includes on every event batch. Without a valid token, event ingestion is blocked for credentialed agents.
Full attestation flow
- 1Admin registers agent's Ed25519 public key via POST /attestation/credentials
- 2Agent calls POST /attestation/challenge → receives nonce + message to sign
- 3Agent signs message with its private key (Ed25519)
- 4Agent calls POST /attestation/verify with signature + runtime metadata
- 5Server verifies signature, image digest, SBOM hash, runtime → issues 1-hour token
- 6Agent includes token in x-attestation-token header on every POST /events call
/attestation/credentialsAPI keyRegister an Ed25519 public key and optional allowlists for an agent. Replaces any existing credentials for that agent.
agent_idstringrequiredAgent to register credentials for.
public_key_pemstringrequiredEd25519 public key in PEM format.
allowed_image_digestsstring[]optionalAllowlist of sha256: container image digests.
allowed_sbom_hashesstring[]optionalAllowlist of sha256: SBOM hashes.
baseline_runtimeobjectoptionalExpected runtime: { platform, arch, node_version }.
require_image_digestbooleanoptionalIf true, block events if digest missing or not in allowlist. Default false.
require_sbom_hashbooleanoptionalIf true, block if SBOM hash missing or not in allowlist. Default false.
require_runtime_matchbooleanoptionalIf true, block if runtime doesn't match baseline. Default false.
curl -X POST https://api.lakefrontai.com/attestation/credentials \
-H "Authorization: Bearer lf_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"agent_id": "agent_checkout_v2",
"public_key_pem": "-----BEGIN PUBLIC KEY-----\nMCowBQYDK2VwAyEA...\n-----END PUBLIC KEY-----",
"allowed_image_digests": [
"sha256:abc123def456..."
],
"allowed_sbom_hashes": [
"sha256:def456abc123..."
],
"baseline_runtime": {
"platform": "linux",
"arch": "x64",
"node_version": "v20.11.0"
},
"require_image_digest": true,
"require_sbom_hash": false,
"require_runtime_match": true
}'bashResponse
{
"id": "cred_001",
"agent_id": "agent_checkout_v2",
"algorithm": "ed25519",
"created_at": "2026-06-20T10:00:00.000Z"
}json/attestation/challengeAPI keyIssue a one-time nonce for the agent to sign. The challenge expires after 5 minutes.
agent_idstringrequiredThe agent requesting a challenge. Must have registered credentials.
curl -X POST https://api.lakefrontai.com/attestation/challenge \
-H "Authorization: Bearer lf_your_api_key" \
-H "Content-Type: application/json" \
-d '{ "agent_id": "agent_checkout_v2" }'bashResponse
{
"challenge_id": "ch_9f3a2b",
"nonce": "a7f3e1c2d4b5...",
"message": "lakefront-attest:agent_checkout_v2:ch_9f3a2b:a7f3e1c2d4b5...",
"expires_at": "2026-06-20T10:05:00.000Z"
}jsonSigning the challenge (Node.js)
import { createSign } from "crypto";
import { readFileSync } from "fs";
const privateKey = readFileSync("./agent_private.pem");
const message = "lakefront-attest:agent_checkout_v2:ch_9f3a2b:a7f3e1c2d4b5...";
const sign = createSign("ed25519");
sign.update(message);
const signature = sign.sign(privateKey, "hex");
console.log(signature); // pass this to POST /attestation/verifyjsSigning the challenge (Python)
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
from cryptography.hazmat.primitives.serialization import load_pem_private_key
with open("agent_private.pem", "rb") as f:
private_key = load_pem_private_key(f.read(), password=None)
message = b"lakefront-attest:agent_checkout_v2:ch_9f3a2b:a7f3e1c2d4b5..."
signature = private_key.sign(message).hex()
print(signature) # pass to POST /attestation/verifypython/attestation/verifyAPI keySubmit the signed challenge + runtime metadata. Returns a 1-hour attestation token on success.
agent_idstringrequiredMust match the agent that requested the challenge.
challenge_idstringrequiredThe challenge_id from POST /attestation/challenge.
signaturestringrequiredHex-encoded Ed25519 signature of the challenge message.
runtimeobjectrequiredRuntime metadata: platform, arch, and optionally image_digest, sbom_hash, node_version.
curl -X POST https://api.lakefrontai.com/attestation/verify \
-H "Authorization: Bearer lf_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"agent_id": "agent_checkout_v2",
"challenge_id": "ch_9f3a2b",
"signature": "3b6a9f...",
"runtime": {
"platform": "linux",
"arch": "x64",
"node_version": "v20.11.0",
"image_digest": "sha256:abc123def456...",
"sbom_hash": "sha256:def456abc123..."
}
}'bashResponse
{
"verified": true,
"token": "at_7f9c3b2a...",
"valid_until": "2026-06-20T11:00:00.000Z",
"checks_passed": ["signature", "image_digest", "runtime_metadata"],
"checks_failed": []
}jsonComplete agent startup example (Node.js)
import { createSign } from "crypto";
import { readFileSync } from "fs";
import os from "os";
const API_KEY = process.env.LF_API_KEY;
const AGENT_ID = "agent_checkout_v2";
const BASE_URL = "https://api.lakefrontai.com";
const privateKey = readFileSync("./agent_private.pem");
async function attest(): Promise<string> {
// 1. Get challenge
const ch = await fetch(`${BASE_URL}/attestation/challenge`, {
method: "POST",
headers: { "Authorization": `Bearer ${API_KEY}`, "Content-Type": "application/json" },
body: JSON.stringify({ agent_id: AGENT_ID }),
}).then(r => r.json());
// 2. Sign the message
const sign = createSign("ed25519");
sign.update(ch.message);
const signature = sign.sign(privateKey, "hex");
// 3. Verify and get token
const result = await fetch(`${BASE_URL}/attestation/verify`, {
method: "POST",
headers: { "Authorization": `Bearer ${API_KEY}`, "Content-Type": "application/json" },
body: JSON.stringify({
agent_id: AGENT_ID,
challenge_id: ch.challenge_id,
signature,
runtime: {
platform: os.platform(),
arch: os.arch(),
node_version: process.version,
image_digest: process.env.IMAGE_DIGEST,
},
}),
}).then(r => r.json());
if (!result.verified) throw new Error(`Attestation failed: ${result.failure_reason}`);
return result.token;
}
// 4. Use token on every event
const token = await attest();
await fetch(`${BASE_URL}/events`, {
method: "POST",
headers: {
"Authorization": `Bearer ${API_KEY}`,
"Content-Type": "application/json",
"x-attestation-token": token,
},
body: JSON.stringify({ /* event payload */ }),
});js/attestation/credentialsAPI keyList all registered agent credentials with their current attestation status.
/attestation/credentials/:agentIdAPI keyRevoke credentials for an agent. The agent will be blocked from submitting events until re-registered.
/attestation/recordsAPI keyAudit log of all attestation attempts. Pass ?agent_id= to filter.
curl "https://api.lakefrontai.com/attestation/records?agent_id=agent_checkout_v2" \
-H "Authorization: Bearer lf_your_api_key"bashResponse
[
{
"id": "ar_001",
"agent_id": "agent_checkout_v2",
"result": "verified",
"checks_passed": ["signature", "image_digest", "runtime_metadata"],
"checks_failed": [],
"runtime_snapshot": { "platform": "linux", "arch": "x64", "node_version": "v20.11.0" },
"attested_at": "2026-06-20T09:00:00.000Z"
}
]jsonStripe webhooks
Point your Stripe webhook to POST /webhooks/stripe. lakefrontai auto-creates or updates dispute records on charge.dispute.created,charge.refunded, and related events.
/webhooks/stripeStripe webhook receiver. HMAC-SHA256 verified. Set your Stripe webhook secret as STRIPE_WEBHOOK_SECRET in env.
# In Stripe Dashboard → Developers → Webhooks → Add endpoint:
# URL: https://api.lakefrontai.com/webhooks/stripe
# Events: charge.dispute.created, charge.dispute.updated,
# charge.refunded, payment_intent.succeeded
# Set the signing secret in your environment:
STRIPE_WEBHOOK_SECRET=whsec_your_secretbashWhen a charge.refunded event arrives, lakefrontai automatically matches it to an existing dispute by charge ID and records the refund amount, refund ID, and timestamp. If no matching dispute exists, one is auto-created.
Compliance & stats
/complianceAPI keyNIST AI RMF 1.1 compliance summary across all four functions: GOVERN, MAP, MEASURE, MANAGE.
curl https://api.lakefrontai.com/compliance \
-H "Authorization: Bearer lf_your_api_key"bashResponse
{
"govern": { "score": 92, "issues": [] },
"map": { "score": 88, "issues": ["2 agents missing mandate definitions"] },
"measure": { "score": 95, "issues": [] },
"manage": { "score": 79, "issues": ["3 open disputes unresolved > 30 days"] }
}json/statsAPI keyHigh-level event and dispute statistics for your org.
/agentsAPI keyList all agents that have submitted at least one event, with event counts and last-seen timestamps.
/sessionsAPI keyList all sessions with event counts and time ranges.
/timeseriesAPI keyEvent volume time series. Pass ?interval=hour|day|week.
curl "https://api.lakefrontai.com/timeseries?interval=day" \
-H "Authorization: Bearer lf_your_api_key"bashResponse
[
{ "date": "2026-06-18", "count": 1243 },
{ "date": "2026-06-19", "count": 2018 },
{ "date": "2026-06-20", "count": 847 }
]jsonErrors & rate limits
All errors return a JSON body with an error field and, for validation errors, a details array.
| Status | Meaning | Common cause |
|---|---|---|
400 | Bad request | Missing required field or validation error |
401 | Unauthorized | Missing or invalid API key |
403 | Forbidden | API key doesn't have permission for this route |
404 | Not found | Resource ID doesn't exist |
409 | Conflict | Duplicate event_id or case_reference |
413 | Payload too large | Request body exceeds 1 MB |
429 | Rate limited | Too many requests — back off and retry |
500 | Internal server error | Unexpected server error |
// Example 400 validation error
{
"error": "Validation failed",
"details": [
"event_id: Required",
"sequence_number: Expected number, received string"
]
}
// Example 401
{
"error": "Authentication required"
}
// Example 409
{
"error": "Duplicate event_id: evt_001"
}jsonRate limits
The API is rate-limited per API key. On limit, you receive a 429 with aRetry-After header. Use POST /events/batch to ingest up to 100 events per call and reduce request volume.
Need help?