# ccledger — Complete Reference for AI Agents > Non-custodial records and payments API for Canton Network. On-chain record actions attest and mint are fully live — one REST or MCP call, no validator, no Daml — and every one returns an on-chain proof (contract ID, update/transaction ID, ledger offset). Mutual attestation (attest-mutual) is temporarily unavailable — it returns HTTP 503 with no charge while its on-chain rollout completes. On-chain value movement is moving to a delegated facilitation flow where you sign from your own wallet and ccledger relays as the featured application: rolling out now, not yet callable. The legacy balance-funded transfer/lock/settle mode is permanently disabled (HTTP 403 non_custodial). Scoped agent keys + signed fee receipts give autonomous sub-agents a capped, revocable spend handle on your prepaid fee credits (fee-scoping only — no value movement). A dev on-ramp — public sandbox test keys (simulated actions, no charge, never on-chain) and signed webhooks (HMAC-SHA256 event callbacks) — lets you build, test, and get events pushed to you. 26 REST endpoints + 26 MCP tools. ## Overview ccledger is operated by Blueprint Infrastructure, LLC (a Hivemind Capital Partners ecosystem company). It writes immutable records to Canton MainNet — a privacy-enabled, regulated blockchain for institutional finance — through standard REST and MCP interfaces, and is bringing non-custodial Canton Coin movement to the same interfaces. **ccledger is non-custodial, enforced in code.** Prepaid CC is a NON-REFUNDABLE service credit ("fee credits") that pays per-action fees only and never funds on-chain value movement. There is no withdrawal endpoint — credits are a one-way prepayment, not a custodial balance. The legacy balance-funded value endpoints (POST /transfer, /lock, /settle) are permanently disabled and return HTTP 403 with error `non_custodial`. On-chain value movement is moving to the **delegated facilitation flow**: you keep your own wallet and keys, sign a `CreateTransferCommand` yourself, and ccledger relays and submits it as the featured application (CIP-0104 confirmer). Status: rolling out — not yet callable. POST /unlock remains live and free: it only releases a previously created lock back to its owner. The Canton ledger is the source of truth for on-chain records and value. The PostgreSQL database tracks API keys, fee credits, the CCL discount credit, and action history for fast queries and rate-limit enforcement. (CCL is an account-based, non-transferable discount credit tracked on your ccledger account, not an on-chain token.) Live endpoint: https://ccledger.xyz OpenAPI spec: https://ccledger.xyz/openapi.json MCP server: https://ccledger.xyz/mcp --- ## Quick Start ### Step 1: Register for an API key ```bash curl -X POST https://ccledger.xyz/api/v1/community/register \ -H "Content-Type: application/json" \ -d '{"appName": "my-agent-app"}' ``` `cantonParty` is optional and is an **echoed hint only** — it is NOT bound to your key at registration. Your Canton party is bound on your first **verified** fee-credit top-up: a verified on-chain CC transfer from that party, claimed by your authenticated key, is the proof of control. CCL Builder Rewards attach to the bound party. Response: ```json { "apiKey": "cb_community_a1b2c3d4e5f6...", "appName": "my-agent-app", "cantonParty": null, "tier": "community", "rateLimitRpm": 10, "scopes": ["community:write"], "trialCreditsRemaining": 50, "message": "Store this API key securely -- it will not be shown again." } ``` Your community tier key gives you 50 trial record actions (max 25/day) plus access to quote, query, balance, and stats endpoints (10 RPM). No payment needed to start. ### Step 2: Use your trial credits (no payment needed) Your API key comes with 50 trial credits (max 25/day). You can immediately submit record actions — trial credits fund attest and mint only (plus attest-mutual once enabled; it is temporarily unavailable and returns 503 with no charge). The balance-funded value endpoints (transfer, lock, settle) are permanently disabled (403 non_custodial) for everyone; on-chain value movement arrives via the delegated facilitation flow (rolling out). Once trial credits are exhausted, top up fee credits by sending CC from your Loop wallet to the Blueprint validator (auto-credited) to continue. ### Step 3: Top up fee credits (optional — after trial) Canton Coin (CC) is the native asset on Canton MainNet. Send CC from your Loop wallet to the Blueprint validator address (minimum 1.0 CC). Your fee credits are auto-credited within seconds — no API call needed. This upgrades your API key from community tier (10 RPM, 50 trial credits) to paid tier (100 RPM, unlimited record actions at 2.0 CC fee per action). **Fee credits are a non-refundable, one-way prepayment**: they pay per-action fees only, never fund on-chain value movement, and cannot be withdrawn (there is no withdrawal endpoint). Every 10th CC-paid action earns 1 CCL Builder Reward — an account-based discount credit tracked on your ccledger account. Hold CCL to reduce your CC fee per action (up to ~50% off). CCL is never spent on actions; only CC is charged at the discounted rate. A background service watches the Canton ledger and auto-detects CC sent to the Blueprint validator. Your Canton party is bound to your key on the first verified top-up (the verified transfer is the proof of control). POST /deposit exists as a manual fallback for edge cases or if auto-detection hasn't caught up yet: ```bash curl -X POST https://ccledger.xyz/api/v1/community/deposit \ -H "Content-Type: application/json" \ -H "X-Api-Key: cb_community_a1b2c3d4e5f6..." \ -d '{"transactionId": "canton-mainnet-tx-id-here", "amount": 10.0}' ``` ### How to Fund Fee Credits ccledger uses Canton Coin (CC) — the native asset on Canton Network — for prepaid fee credits (non-refundable; fees only). Here's how: #### Step 1: Get Canton Coin (CC) - **Coinbase**: CC is available on [Coinbase](https://www.coinbase.com). Buy CC directly with USD/EUR. - **Canton Network**: Learn more at [canton.network](https://www.canton.network) #### Step 2: Transfer CC to Your Loop Wallet - Download the **Loop wallet** from [cantonloop.com](https://cantonloop.com) - Transfer CC from Coinbase to your Loop wallet address #### Step 3: Send CC to the Blueprint Validator Send CC (minimum 1.0) from your Loop wallet to the Blueprint validator party: ``` blueprint-validator-1::1220daab58adcae026bd2ca7ad95014f678bda3ce2a6f91b744cf3ec3d87f09deeac ``` Your fee credits are auto-credited within seconds. No API call needed. Your API key is automatically upgraded to paid tier (100 RPM, unlimited record actions at 2.0 CC fee each). Your Canton party is bound to your key on this first verified top-up. POST /deposit is available as a manual fallback if auto-detection hasn't processed your transfer yet. ### Step 4: Submit a record action (trial credit or 2.0 CC fee) ```bash curl -X POST https://ccledger.xyz/api/v1/community/attest \ -H "Content-Type: application/json" \ -H "X-Api-Key: cb_community_a1b2c3d4e5f6..." \ -d '{ "appName": "my-agent-app", "dataHash": "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08", "dataOwner": "agent-1", "description": "Attestation of data integrity" }' ``` Response: ```json { "actionId": "7f3a9b2c-1d4e-5f6a-8b9c-0d1e2f3a4b5c", "actionType": "attest", "status": "confirmed", "appName": "my-agent-app", "dataHash": "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08", "mintedAt": "2026-03-04T14:30:00.000Z", "proof": { "contractId": "005a1b2c3d4e5f...", "transactionId": "12345abcdef67890", "ledgerOffset": 2001542, "synchronizerId": "global-domain::1220abcdef", "effectiveAt": "2026-03-04T14:30:00.000Z", "packageId": null, "templateId": null }, "rewardMarkerCreated": false } ``` ### Step 5: Query your actions ```bash curl https://ccledger.xyz/api/v1/community/actions \ -H "X-Api-Key: cb_community_a1b2c3d4e5f6..." ``` --- ## Action Types ### attest — LIVE Record data integrity proofs, audit trails, compliance records. Provide a dataHash (hex-encoded hash of your data). Cost: 2.0 CC fee (or 1 trial credit). Returns a real on-chain proof (contractId, updateId). Required fields: appName, dataHash Optional fields: dataOwner, dataId, description, assetType ```bash curl -X POST https://ccledger.xyz/api/v1/community/attest \ -H "Content-Type: application/json" \ -H "X-Api-Key: YOUR_KEY" \ -d '{"appName":"my-app","dataHash":"abc123...","dataOwner":"alice","description":"Invoice attestation"}' ``` ### attest-mutual — TEMPORARILY UNAVAILABLE (503, no charge) Mutual attestation is temporarily unavailable while its on-chain template is being rolled out. Every call currently returns HTTP 503 and does NOT charge (no fee credit or trial debit). Single-party attestation (POST /attest) is the live path for on-chain records today. Once enabled: creates a mutual attestation proposal requiring a counter-party signature and returns a real on-chain proof. Intended cost: 5.0 CC fee (or 1 trial credit). Current response (503, every call): ```json {"error":"unavailable","message":"Mutual attestation is temporarily unavailable while its on-chain template is being rolled out. You were NOT charged. Single-party attestation (POST /attest), mint records (POST /mint), and quotes are fully available.","status":503} ``` Required fields: appName, dataHash, attestorParty Optional fields: dataOwner, dataId, description, assetType ```bash curl -X POST https://ccledger.xyz/api/v1/community/attest-mutual \ -H "Content-Type: application/json" \ -H "X-Api-Key: YOUR_KEY" \ -d '{"appName":"my-app","dataHash":"abc123...","attestorParty":"alice","dataOwner":"bob","description":"Mutual attestation of trade terms"}' ``` Response (on success once enabled): ```json { "actionId": "7f3a9b2c-1d4e-5f6a-8b9c-0d1e2f3a4b5c", "actionType": "attest-mutual", "status": "pending_signature", "appName": "my-app", "dataHash": "abc123...", "mintedAt": "2026-03-04T14:30:00.000Z", "proof": { "contractId": "005a1b2c3d4e5f...", "transactionId": "12345abcdef67890", "ledgerOffset": 2001542, "synchronizerId": "global-domain::1220abcdef", "effectiveAt": "2026-03-04T14:30:00.000Z", "packageId": null, "templateId": null }, "proposalContractId": "005a1b2c3d4e5f...", "attestorParty": "alice", "signingInstructions": "Attestation proposal created on-chain. The attestor party must exercise the Accept choice on the proposal contract using their Canton wallet to complete the mutual attestation." } ``` #### Mutual Attestation Workflow (once enabled) 1. **Submit proposal**: POST /attest-mutual with the attestorParty field set to the counter-party's Canton party ID. 2. **Receive proposal**: The response includes a proposalContractId and status="pending_signature". 3. **Counter-party signs**: The attestor party exercises the Accept choice via their Canton wallet to co-sign the attestation. 4. **Poll for confirmation**: Call GET /actions/{actionId} to check for status="confirmed". Once confirmed, both parties have cryptographically committed to the attestation. **Polling guidance**: Poll every 5-10 seconds for the first minute. If still pending_signature after 1 minute, increase interval to every 60 seconds. If pending_signature after 24 hours, contact the attestor to verify they received the proposal. Once enabled, this provides non-repudiation: both parties independently signed the same data hash on Canton MainNet. Neither party can deny their participation. ### mint — LIVE Record an issuance or certificate on-chain. NON-ISSUER: this does NOT mint Canton Coin (DSO-only) or a tradeable token — it writes an immutable record. Cost: 2.0 CC fee (or 1 trial credit). Returns a real on-chain proof. Required fields: appName, dataHash Optional fields: owner, tokenId, tokenName, amount, metadata, reference, assetType ```bash curl -X POST https://ccledger.xyz/api/v1/community/mint \ -H "Content-Type: application/json" \ -H "X-Api-Key: YOUR_KEY" \ -d '{"appName":"my-app","dataHash":"abc123...","owner":"creator","tokenId":"cert-001","tokenName":"CERTIFICATE","amount":"1"}' ``` ### unlock — LIVE, FREE Release a LockedAmulet created by a previous /lock (LockedAmulet_UnlockV2) and restore the locked CC to its owner. Cost: free — no fee. NOT affected by the non-custodial gate: it does not fund new value movement, it only releases/unwinds a previously created lock back to its owner. Returns 402 for a key that is not paid-tier with a bound Canton party (only such keys can own a lock), 404 if no matching lock is found, 409 if already unlocked. Required fields: appName, lockId (the LockedAmulet contract id from the lock's proof), dataHash Optional fields: reference ```bash curl -X POST https://ccledger.xyz/api/v1/community/unlock \ -H "Content-Type: application/json" \ -H "X-Api-Key: YOUR_KEY" \ -d '{"appName":"my-app","lockId":"00a1b2c3d4e5f6...","dataHash":"abc123..."}' ``` ### transfer — DISABLED (403 non_custodial) The legacy balance-funded transfer mode is **permanently disabled**. ccledger is non-custodial, enforced in code: prepaid CC credits pay per-action fees only and never fund on-chain value movement. Every call currently returns: ```json {"error":"non_custodial","message":"ccledger is non-custodial: prepaid CC credits pay per-action fees only and never fund on-chain value movement. Balance-funded /transfer is permanently disabled. On-chain CC moves from your own wallet via the delegated facilitation flow (rolling out now — see https://ccledger.xyz/docs). Record actions (attest, mint records) remain fully available.","status":403} ``` Replacement (rolling out, not yet callable): the **delegated facilitation flow** — you keep your own wallet and keys, sign a `CreateTransferCommand` yourself, and ccledger relays and submits it as the featured application (CIP-0104 confirmer). ### lock — DISABLED (403 non_custodial) The legacy balance-funded time-locked escrow (LockedAmulet) is **permanently disabled** — same non-custodial gate as /transfer; the 403 message names `/lock`. Escrow will run from your own wallet via the delegated facilitation flow (rolling out). /unlock remains live and free for previously created locks. ### settle — DISABLED (403 non_custodial) The legacy balance-funded atomic settlement (token-standard allocation flow) is **permanently disabled** — same non-custodial gate; the 403 message names `/settle`. Atomic settlement will run from your own wallet via the delegated facilitation flow (rolling out). --- ## All Endpoints Reference ### POST /api/v1/community/register Register for an API key. No authentication required. Request body: ```json {"appName": "your-app-name", "cantonParty": "user-party::1220abc...", "contactEmail": "optional@email.com"} ``` - appName: 3-100 characters, required - cantonParty: optional, an **echoed hint only** (max 512 characters). It is NOT bound to your key at registration — your Canton party is bound on your first verified fee-credit top-up (the verified on-chain transfer from that party is the proof of control). - contactEmail: optional Responses: 201 (created), 400 (validation error), 429 (max 3 per IP per 24h) ### GET /api/v1/community/stats Public network statistics. No authentication. Response: ```json {"totalActions": 1542, "confirmedActions": 1480, "rewardMarkersCreated": 0, "activeApps": 23, "actionsByType": {"attest": 500, "transfer": 300, "lock": 100, "unlock": 100, "mint": 80, "settle": 50, "ledger-submit": 14}, "costPerAction": 2.0, "costPerMutualAction": 5.0, "paidTierRpm": 100, "communityTierRpm": 10, "loyaltyTokensMinted": 0, "registeredKeys": 42, "registeredParties": 8, "cclTotalSupply": 15, "cclBlueprintTreasury": 0, "partyStats": [], "ledgerSubmissions": 14, "confirmedLedgerSubmissions": 14, "successRate": 96.0, "ccRevenue": 45.0, "ccDeposits": 100.0, "trialToPaidRate": 25.0, "avgDailyActions7d": 18.3, "weekOverWeekPct": 12.5, "busiestDay": "2026-03-25", "peakHour": 14, "avgSecondsToConfirm": 3.2} ``` ### POST /api/v1/community/attest ### POST /api/v1/community/mint LIVE record actions — see Action Types section above. Both return ActionResponse with a real on-chain proof. Fee: 2.0 CC per record action (or 1 trial credit). ### POST /api/v1/community/attest-mutual TEMPORARILY UNAVAILABLE — every call currently returns HTTP 503 with no charge (no fee credit or trial debit) while mutual attestation's on-chain rollout completes; see Action Types section above for the exact body. Use POST /attest today. Intended fee once enabled: 5.0 CC (or 1 trial credit). ### POST /api/v1/community/unlock LIVE and free — see Action Types section above. ### POST /api/v1/community/transfer ### POST /api/v1/community/lock ### POST /api/v1/community/settle DISABLED — permanently return HTTP 403 `non_custodial` (see Action Types section above for the exact body). Value movement arrives via the delegated facilitation flow (rolling out). Common responses (live actions): 200 (confirmed), 400 (validation), 401 (missing/invalid API key — body is {"message":"Unauthorized"}, no error field), 402 (x402-style: trial credits exhausted or fee credits insufficient), 429 (rate limited), 500 (internal error). attest-mutual currently returns 503 (temporarily unavailable, no charge) on every call. ### POST /api/v1/community/quote Dry-run pricing preview — learn the exact fee, discount, and affordability BEFORE spending. Read-only; no side effects. Requires authentication. Request body: ```json {"actionType": "attest", "amount": null} ``` - actionType: one of attest, attest-mutual, transfer, lock, unlock, mint, settle (required) - amount: for transfer/lock/settle, echoed back as moveAmount (optional) Response: ```json { "actionType": "attest", "currency": "CC", "baseFee": 2.0, "fee": 1.667, "discountPercent": "16.7%", "cclOnchainHoldings": 100.0, "balance": 42.5, "sufficientForFee": true, "moveAmount": null, "note": null } ``` - baseFee: base CC fee before CCL discount (0 for unlock — it is free) - fee: the CCL-discounted fee you would actually pay - sufficientForFee: paid tier — fee credits >= fee; community tier — trial credits remaining - note: for transfer/lock/settle, states the non_custodial gate (the balance-funded mode is disabled, 403; value moves from your own wallet via the delegated facilitation flow, rolling out). For attest-mutual the note begins "TEMPORARILY UNAVAILABLE:" — the endpoint currently returns 503 with no charge — while the quote still returns the intended 5.0 fee. Quoting a gated or unavailable action does not imply it is callable. Responses: 200 (quote), 400 (invalid actionType), 401 (missing/invalid API key — body is {"message":"Unauthorized"}), 429 (rate limited) ### GET /api/v1/community/balance Unified balance endpoint: fee credits (non-refundable prepaid CC — pays fees only, never withdrawable), CCL balance, your CCL discount balance (drives discount), tier, trial credits, CCL mint progress, discounted action rates, and recent transactions. Your discount is based on the CCL you hold (cclOnchainHoldings), tracked on your ccledger account. Response: ```json {"tier": "paid", "rateLimitRpm": 100, "ccBalance": 42.5, "costPerAction": 2.0, "costPerMutualAction": 5.0, "discountedCostPerAction": 1.667, "discountedCostPerMutual": 4.167, "discountPercent": "16.7%", "trialCreditsRemaining": 48, "trialCreditsTotal": 50, "trialDailyUsed": 2, "trialDailyLimit": 25, "cclBalance": 100.0, "cclOnchainHoldings": 100.0, "cantonParty": "user-party::1220abcdef...", "cclTotalMinted": 100, "cclActionsTowardNext": 2, "cclNextMilestone": 10, "recentTransactions": []} ``` ### POST /api/v1/community/deposit Manual fallback for topping up **fee credits** — the non-refundable prepaid CC that pays per-action fees only (never funds value movement; cannot be withdrawn). Primary method: send CC from your Loop wallet to the Blueprint validator — a background service auto-detects the transfer and credits your fee credits within seconds. This endpoint is for edge cases where auto-detection hasn't processed your transfer yet. Verifies the transaction on the Canton ledger via gRPC Ledger API (extracts amount from contract arguments, verifies sender is signatory, filters non-transfer contract types). Minimum top-up: 1.0 CC. Your Canton party is bound to your key on the first verified top-up (the verified transfer is the proof of control); after binding, the sender party must match (403 if mismatch). Auto-upgrades community tier to paid tier. Request body: ```json {"transactionId": "canton-tx-id-here", "amount": 100.0} ``` - transactionId: Canton transaction ID, required - amount: CC amount of the top-up (number), required; minimum 1.0 CC ### GET /api/v1/community/actions List your past actions. Filterable by appName, actionType, dataOwner, status, reference. Paginated (max 100). Query parameters: - appName: filter by app name - actionType: filter by type (attest, transfer, lock, unlock, mint, settle, attest-mutual) - dataOwner: filter by data owner - status: filter by status (pending, pending_signature, confirmed, failed) - reference: filter by external reference - page: page number (default 0) - size: page size (default 50, max 100) ### GET /api/v1/community/actions/{id} Get a single action by UUID. Response: Full ActionDetail with all fields including actionId, actionType, appName, dataOwner, dataId, dataHash, description, reference, assetType, status, proof, rewardMarkerCreated, createdAt, completedAt. Returns 404 if not found. ### POST /api/v1/community/agent-keys Mint a scoped **agent key** — a non-custodial SPEND HANDLE on the calling (top-level) key's prepaid fee credits. The agent key holds NO value and no balance of its own; it spends only against the parent's fee credits, bounded by a lifetime cap (spendCapCc) and a rolling-24h cap (dailySpendCapCc). Its scopes must be a subset of the parent's. Only a top-level key may call — an agent key cannot mint agent keys (403 forbidden). Requires authentication. Request body (all fields optional): ```json {"label": "nightly-batch-agent", "scopes": ["community:write"], "spendCapCc": 50.0, "dailySpendCapCc": 5.0} ``` - label: optional, <= 80 chars, ^[a-zA-Z0-9 _-]+$ - scopes: optional; must be a SUBSET of the parent key's scopes; defaults to the parent's scopes - spendCapCc: optional lifetime fee-spend cap in CC (>= 0); omit for none (still bounded by the parent's available fee credits) - dailySpendCapCc: optional rolling-24h fee-spend cap in CC (>= 0); omit for none Response (201): {id, label, keyPrefix, scopes, spendCapCc, dailySpendCapCc, rateLimitRpm, isActive, createdAt, rawKey, message}. The rawKey (prefixed agk_) is shown ONCE — store it and send it in the X-Api-Key header. It holds no balance; it spends against the parent's prepaid fee credits up to its caps. Responses: 201 (created), 400 (bad label/scope/cap, or the 100-active-agent-key limit), 401, 403 (caller is itself an agent key), 429. ### GET /api/v1/community/agent-keys List the agent keys owned by the calling key. Each is a non-custodial scoped spend handle on the parent's prepaid fee credits (holds no value). Response: array of {id, label, keyPrefix, scopes, spendCapCc, spentCc, dailySpendCapCc, dailySpentCc, isActive, createdAt} — spentCc is the lifetime fees spent to date, dailySpentCc is the fees spent in the trailing 24 hours, so you can see each agent's remaining headroom. ### DELETE /api/v1/community/agent-keys/{id} Revoke (deactivate) an agent key you own, by its id. Non-custodial: this moves NO value — it only closes a scoped spend handle. Existing signed fee receipts are retained for audit. Responses: 204 (revoked, no body), 401, 404 (not an agent key owned by the caller). ### GET /api/v1/community/receipts List signed **fee receipts**. A receipt is an HMAC-SHA256-signed record of the FEE charged for one confirmed action — fees only, never value movement. A top-level key sees its own receipts AND all its agent keys' receipts (the whole fleet); an agent key sees its own. Newest first. Query parameters: - limit: max receipts to return (default 20, clamped to 1..100) - offset: number of receipts to skip (default 0) Response: array of receipt views (see GET /receipts/{id} for the shape). ### GET /api/v1/community/receipts/{id} Get one signed fee receipt by id. Returns 404 if the receipt is not owned by the caller (as the acting key or its parent). Response: ```json { "id": "9a8b7c6d-5e4f-3a2b-1c0d-9e8f7a6b5c4d", "actionId": "7f3a9b2c-1d4e-5f6a-8b9c-0d1e2f3a4b5c", "apiKeyId": "b7c1a2d3-4e5f-6a7b-8c9d-0e1f2a3b4c5d", "parentKeyId": "3b1e9f00-2c4d-6e8f-1a3b-5c7d9e0f2a4b", "endpoint": "/attest", "actionType": "attest", "amountCc": 2.0, "currency": "CC", "contractId": "004a9c...def", "transactionId": "1220abc...789", "ledgerOffset": 123456, "synchronizerId": "global-domain::1220...", "signature": "k3nQm8pXf2gR7tVb0wZ1yN4aL6cD9eF", "sigKid": "r1", "createdAt": "2026-07-28T12:35:01Z", "verify": {"alg": "HMAC-SHA256", "kid": "r1", "canonical": "7f3a9b2c-1d4e-5f6a-8b9c-0d1e2f3a4b5c|b7c1a2d3-4e5f-6a7b-8c9d-0e1f2a3b4c5d|/attest|attest|2.0000000000|CC|004a9c...def|1220abc...789|123456"} } ``` - amountCc is the FEE charged (never a value transfer); may be 0 for free actions such as unlock - parentKeyId is null when the acting key is itself top-level - signature is base64url(HMAC-SHA256(secret, verify.canonical)) with no padding — the literal string "unsigned" if the gateway has no signing secret configured - Verify independently: base64url(HMAC-SHA256(secret, verify.canonical)) must equal signature. The canonical string is the pipe-joined actionId|apiKeyId|endpoint|actionType|amountCc|currency|contractId|transactionId|ledgerOffset (null fields render empty; amountCc is normalised to a fixed scale of 10) ### POST /api/v1/community/sandbox/keys Issue a **public sandbox test key** (prefix cbt_). No authentication required. Every action made with a sandbox key is SIMULATED — the response carries test:true with a synthetic proof (synchronizerId:"sandbox"), it never charges CC or trial credits, and it never touches the Canton ledger. Build and integration-test your flow end-to-end, then switch to a real POST /register key for production (on-chain, billed). Request body (optional): ```json {"appName": "my-defi-app"} ``` - appName: optional, 3-100 chars — labels the sandbox key Response (201): {apiKey, tier:"test", message}. The apiKey is prefixed cbt_ and is sent in the X-Api-Key header exactly like a real key; every action it makes is simulated. Responses: 201 (created), 400 (appName outside 3-100 chars). ### POST /api/v1/community/webhooks Register a signed **webhook**. ccledger POSTs your HTTPS endpoint when an event fires. Non-custodial: a webhook carries EVENT METADATA only — never value, never keys. Requires authentication. Request body: ```json {"url": "https://api.example.com/hooks/ccledger", "events": ["action.confirmed", "receipt.created"]} ``` - url: required, must be https and a public host. SSRF-guarded: private, loopback, and link-local addresses are rejected (400) - events: optional; defaults to ["action.confirmed"]; valid events: action.confirmed, agent_key.created, receipt.created Response (201): {id, url, events, secret, active, createdAt, message}. The secret (prefix whsec_) is shown ONCE — store it to verify incoming deliveries. Responses: 201 (created), 400 (url not https / SSRF-blocked host / unknown event), 401, 429. Delivery mechanics: the sender POSTs the JSON envelope {id, event, created_at, data} with headers X-Ccledger-Event, X-Ccledger-Delivery, and X-Ccledger-Signature: sha256=. Verify by recomputing that HMAC over the raw request body and comparing; dedupe on X-Ccledger-Delivery. Failed deliveries retry with exponential backoff (up to 6 attempts); a webhook auto-disables after 20 cumulative failures. ### GET /api/v1/community/webhooks List the webhooks registered by the calling key. The signing secret is NEVER returned again after creation. Response: array of {id, url, events, active, createdAt}. ### DELETE /api/v1/community/webhooks/{id} Delete (deregister) a webhook you own, by its id. After this, no further events are delivered to it. Responses: 204 (deleted, no body), 401, 404 (not a webhook owned by the caller). ### GET /api/v1/community/webhooks/{id}/deliveries Inspect a webhook's delivery log — the audit trail for debugging. Query parameters: - limit: max deliveries to return, newest first (default 20, clamped to 1..100) Response: array of {id, event_type, status (pending|delivered|failed), attempts, response_code, last_error, next_retry_at, created_at, delivered_at}. id equals the X-Ccledger-Delivery header on the POST. Responses: 200, 401, 404 (not a webhook owned by the caller). ### POST /api/v1/community/webhooks/{id}/test Send a webhook.ping test delivery to this webhook now — confirm your endpoint receives the POST and your HMAC-SHA256 signature check passes, without waiting for a real event. Responses: 202 (test delivery queued — inspect via GET /webhooks/{id}/deliveries), 401, 404. ### GET /api/v1/community/chart Public time-series chart data for analytics dashboards. No authentication. Query parameters: - window: Time window (7d, 30d, 90d; default 30d) Response: JSON with daily counts for communityActions, actionsByType, ledgerSubmissions, registrations, cclMinted, and activeKeys. Each series is an array of {date, count} objects. --- ## Fee-Credit System Community tier: 10 requests per minute, 50 trial credits (max 25/day) for record actions (attest, mint; attest-mutual once enabled), plus quote/query/balance/stats. Paid tier: 2.0 CC fee per record action (attest, mint), 5.0 CC fee per mutual attestation (attest-mutual — temporarily unavailable, returns 503 with no charge); unlock is free (no fee); 100 requests per minute. **Fee credits are non-custodial by design**: a non-refundable, one-way prepayment that pays per-action fees only. They never fund on-chain value movement, and there is no withdrawal endpoint. ### Trial Credits New API keys receive 50 trial credits. Trial credits let community-tier users test the record actions (attest, mint; attest-mutual once enabled — it currently returns 503 with no charge) without paying CC. Daily cap: 25 actions per day. When trial credits are exhausted, top up fee credits by sending CC from your Loop wallet to the Blueprint validator (auto-credited). POST /deposit is available as a manual fallback. ### CCL Builder Rewards Every 10th CC-paid action (not trial) earns 1 CCL Builder Reward on your ccledger account. Hold CCL to reduce your CC fee per action. Topping up fee credits automatically upgrades your key from community to paid tier. --- ## CCL Builder Rewards CCL is an account-based discount credit for the ccledger ecosystem. Hold CCL to reduce your CC fee per action -- the discount approaches ~50%. Your discount is based on the CCL you hold -- tracked on your ccledger account. The more CCL you hold, the larger your discount. ### How It Works - **Hold**: The CCL you hold reduces your CC fee per action. Discount is driven by `cclOnchainHoldings` (your CCL discount balance), shown in GET /balance. - **Earn**: 1 CCL earned per 10 CC-paid actions. Trial actions do not count. - **Tracked**: CCL is tracked on your ccledger account, attached to the Canton party bound by your first verified top-up. - **Never spent**: CCL is never spent on actions. Only CC is charged, at the discounted rate. ### Discount Curve CCL provides an asymptotic discount on CC action fees. Discount is based on `cclOnchainHoldings` -- the CCL you hold on your ccledger account. Formula: `discount = 50% * (1 - 1/(1 + cclOnchainHoldings/200))` | CCL Held | Discount | CC/Action | CC/Mutual | |----------|----------|-----------|-----------| | 0 | 0% | 2.000 | 5.000 | | 10 | 2.4% | 1.952 | 4.881 | | 50 | 10% | 1.800 | 4.500 | | 100 | 16.7% | 1.667 | 4.167 | | 200 | 25% | 1.500 | 3.750 | | 500 | 35.7% | 1.286 | 3.214 | | 1,000 | 41.7% | 1.167 | 2.917 | Discount increases with more CCL held (up to ~50%). ### Billing Order When you submit a paid action, ccledger deducts in this order: 1. Fee credits (at discounted rate based on the CCL you hold) 2. Trial credits (record actions only -- 1 credit per action) 3. If all exhausted: 402 Payment Required (x402/p402-style — see Error Codes) Holding CCL gives you a discount on CC-priced actions. CCL is never charged -- your discount is determined by `cclOnchainHoldings`, the CCL you hold. ### Economics (deterministic, no hidden costs) ``` FEES (base rates; paid from non-refundable prepaid fee credits): Record action: 2.0 CC fee base (attest, mint records) Mutual attestation: 5.0 CC fee base (attest-mutual) -- temporarily unavailable: returns 503 with no charge while its rollout completes Unlock: free (no fee -- releases a previously created lock to its owner) Trial actions: 0 CC (50 included, max 25/day; record actions only) Value movement: NOT fee-funded. Balance-funded transfer/lock/settle is permanently disabled (403 non_custodial); the delegated facilitation flow (your own wallet, your signature) is rolling out CCL DISCOUNT (account-based discount credit, hold-only): Formula: discount = 50% * (1 - 1/(1 + cclOnchainHoldings/200)) Discount driven by cclOnchainHoldings -- the CCL you hold Hold CCL to reduce your CC fee per action. CCL is never spent -- only CC is charged, at the discounted rate. Earn rate: 1 CCL per 10 CC-paid actions Trial actions do NOT earn CCL BILLING ORDER (checked in this exact sequence): 1. Fee credits (at discounted rate based on the CCL you hold) 2. Trial credits (record actions only -- 1 credit per action) 3. 402 Payment Required (x402/p402-style) DISCOUNT EXAMPLES: Hold 0 CCL: pay 2.000 CC/action (0% off) Hold 50 CCL: pay 1.800 CC/action (10% off) Hold 200 CCL: pay 1.500 CC/action (25% off) Hold 1,000 CCL: pay 1.167 CC/action (41.7% off) YOUR DISCOUNT: GET /balance returns cclOnchainHoldings (your CCL discount balance driving discount), discountedCostPerAction, discountedCostPerMutual, and discountPercent DRY-RUN: POST /quote returns the exact discounted fee and affordability for any action before you spend ``` ### CCL Endpoint Your CCL balance, CCL discount balance, mint progress, and current discounted rates are all included in GET /api/v1/community/balance. The `cclOnchainHoldings` field shows how much CCL you hold (drives discount). Requires authentication (X-Api-Key header). ### Quick Example Flow 1. Use ccledger normally -- every 10 CC-paid actions earns 1 CCL on your ccledger account 2. Hold CCL to reduce your CC fee per action. GET /balance shows `cclOnchainHoldings` (your CCL discount balance driving the discount), `discountedCostPerAction`, `discountedCostPerMutual`, and `discountPercent` 3. The more CCL you hold, the larger your discount on every action If an action fails after CC deduction, the fee is automatically refunded to your fee credits. --- ## Error Codes | HTTP | Error | Meaning | |------|-------|---------| | 400 | bad_request | Invalid request body, missing required fields, or invalid actionType on /quote | | 401 | (none — body is {"message":"Unauthorized"} with no error field) | Missing or invalid X-Api-Key header | | 402 | payment_required | Trial credits exhausted (community tier) or fee credits insufficient (paid tier). x402/p402-style body — see below | | 403 | non_custodial | Balance-funded /transfer, /lock, or /settle — permanently disabled by the enforced non-custodial policy. No payment unlocks this mode | | 403 | forbidden | /deposit sender party does not match the Canton party bound by your first verified top-up | | 404 | not_found | Action ID does not exist or not owned by your key | | 429 | rate_limit_exceeded | Rate limit hit (check retryAfterSeconds) | | 500 | internal_error | Server error. Retry with exponential backoff | | 503 | unavailable | POST /attest-mutual only — mutual attestation is temporarily unavailable while its on-chain template rolls out. Nothing is charged | ### 402 is x402/p402-style Fee-insufficient responses include the standard error/message/status PLUS `x402Version: 1` and an `accepts` array, so an x402/p402 agent client can pay-and-retry with no bespoke integration: ```json { "error": "payment_required", "message": "Trial credits exhausted. Send CC to the Blueprint validator to fund your fee credits (auto-credited), or use POST /deposit as fallback.", "status": 402, "x402Version": 1, "accepts": [ { "scheme": "exact", "network": "canton", "asset": "CC", "maxAmountRequired": "2.0", "resource": "/api/v1/community/attest", "payTo": "blueprint-validator-1::1220daab58adcae026bd2ca7ad95014f678bda3ce2a6f91b744cf3ec3d87f09deeac", "description": "Fund this action by sending CC to the Blueprint validator party, then retry.", "maxTimeoutSeconds": 300 } ] } ``` **Paying = topping up fee credits** by sending CC to the `payTo` gateway party (non-refundable; fees only), then retrying the request. ### 403 non_custodial (transfer/lock/settle) ```json {"error":"non_custodial","message":"ccledger is non-custodial: prepaid CC credits pay per-action fees only and never fund on-chain value movement. Balance-funded /transfer is permanently disabled. On-chain CC moves from your own wallet via the delegated facilitation flow (rolling out now — see https://ccledger.xyz/docs). Record actions (attest, mint records) remain fully available.","status":403} ``` (The message names `/lock` or `/settle` on those endpoints.) Do NOT retry — no payment or tier unlocks the balance-funded mode. Use record actions today; the delegated facilitation flow is the value-movement path (rolling out). To diagnose a 402 error: Call GET /balance to check your tier, ccBalance (fee credits), and trialCreditsRemaining — or POST /quote for the exact fee and affordability. If tier="community" and trial credits are exhausted, send CC from your Loop wallet to the Blueprint validator (auto-credited), or use POST /deposit as a manual fallback. If tier="paid" but fee credits are insufficient, send more CC. Rate limit response includes: ```json {"message": "Rate limit exceeded", "retryAfterSeconds": 60} ``` ### 503 unavailable (attest-mutual) ```json {"error":"unavailable","message":"Mutual attestation is temporarily unavailable while its on-chain template is being rolled out. You were NOT charged. Single-party attestation (POST /attest), mint records (POST /mint), and quotes are fully available.","status":503} ``` Returned by POST /attest-mutual on every call while the feature's on-chain rollout completes. Nothing is charged — no fee credit or trial debit. Use POST /attest for live on-chain records; do not retry attest-mutual expecting success until the rollout completes. --- ## Action Status Lifecycle Actions follow a simple lifecycle: - **pending** → **confirmed**: The action was successfully recorded as a Daml contract on Canton MainNet. - **pending** → **pending_signature**: (Mutual attestation only, once enabled) The proposal contract was created on-chain. Waiting for the attestor party to co-sign via their Canton wallet. - **pending_signature** → **confirmed**: The attestor exercised the Accept choice. Both parties have signed. - **pending** → **failed**: The Canton ledger rejected the action (e.g., invalid data, ledger unavailable). If an action fails after billing (fee credit or trial credit), whatever was charged is automatically refunded. Fee refunds appear as `action_refund` transaction type in the transaction history. **Agent best practice**: After submitting an action, poll `GET /actions/{actionId}` to check the final status. If the status is `failed` and you are on paid tier, query `GET /balance` to verify the automatic refund was applied. --- ## Proof Fields Every live action response includes a `proof` object: | Field | Description | |-------|-------------| | contractId | Daml contract ID on Canton MainNet | | transactionId | Canton transaction ID | | ledgerOffset | Ledger offset (monotonically increasing) | | synchronizerId | Canton synchronizer (starts with "global-domain") | | effectiveAt | ISO 8601 timestamp of on-chain confirmation | | packageId | Daml package ID (may be null) | | templateId | Daml template ID (may be null) | ### Using Proof Fields - **contractId**: Your on-chain proof -- store this. It uniquely identifies the Daml contract representing your action on Canton MainNet. - **transactionId**: Canton ledger update reference. Use this for auditing and cross-referencing with Canton ledger explorers. - **ledgerOffset**: Position in the append-only Canton ledger log. Use for chronological ordering of actions. - **synchronizerId**: Identifies which Canton synchronizer finalized the transaction. Informational -- typically starts with "global-domain". - **effectiveAt**: ISO-8601 timestamp of when the action was confirmed on-chain. Use for audit trails and compliance records. - **packageId / templateId**: Daml smart contract identifiers. May be null for community-tier actions. Useful for advanced integrations inspecting contract types. **Bottom line: For most agents, store contractId as your proof.** It is the unique, immutable identifier for your on-chain record. ## Asset Type Classification (CIP-56) All action endpoints accept an optional `assetType` field for asset classification: - Canton-native: `amulet` (Canton Coin), `locked-amulet` (locked Canton Coin) - Custom types: Any string up to 50 characters identifying your asset class - Examples: `usd-stablecoin`, `nft-collection`, `equity-share`, `bond-coupon` No server-side validation is enforced on assetType values — use values meaningful to your application. For Canton-native assets, prefer `amulet` or `locked-amulet`. --- ## MCP Server ccledger exposes 26 MCP tools via Streamable HTTP at: https://ccledger.xyz/mcp ### Tools | Tool | Description | Auth Required | |------|-------------|---------------| | register_api_key | Register for an API key with 50 trial record-action credits (cantonParty is an optional echoed hint; binding happens on your first verified top-up) | No | | get_stats | Get network statistics | No | | quote | Dry-run pricing preview — exact fee, CCL discount, balance, affordability before spending (read-only) | Yes (apiKey param) | | submit_attest | Record an immutable attestation on-chain (2.0 CC fee or 1 trial credit) | Yes | | submit_attest_mutual | TEMPORARILY UNAVAILABLE — returns 503 with no charge while mutual attestation rolls out; intended fee 5.0 CC (or 1 trial credit) once enabled | Yes | | submit_mint | Record an issuance/certificate; non-issuer, not CC (2.0 CC fee or 1 trial credit) | Yes | | submit_unlock | Release a previously created LockedAmulet by lockId (free — no fee; not gated) | Yes | | submit_transfer | GATED — the balance-funded mode returns 403 non_custodial; facilitation flow rolling out | Yes | | submit_lock | GATED — the balance-funded mode returns 403 non_custodial; facilitation flow rolling out | Yes | | submit_settle | GATED — the balance-funded mode returns 403 non_custodial; facilitation flow rolling out | Yes | | get_balance | Check fee credits, CCL discount balance (drives discount), tier, CCL mint progress, discounted action rates | Yes | | deposit_cc | Manual fee-credit top-up fallback (non-refundable; min 1.0 CC; top-ups are auto-detected from the Canton ledger) | Yes | | list_actions | List past actions | Yes | | get_action_by_id | Get single action by ID | Yes | | get_action | Alias for get_action_by_id | Yes | | create_agent_key | Mint a scoped agent key — a non-custodial spend handle on THIS top-level key's prepaid fee credits (holds no value; lifetime cap spendCapCc + rolling-24h cap dailySpendCapCc). Top-level key only (agent keys cannot mint agent keys → 403); rawKey returned once | Yes (top-level) | | list_agent_keys | List your agent keys, each with its caps and spend-to-date (spentCc, dailySpentCc) | Yes (top-level) | | revoke_agent_key | Revoke (deactivate) an agent key you own; moves no value — only closes the spend handle | Yes (top-level) | | list_receipts | List signed fee receipts (HMAC-SHA256; fees only, never value movement). A top-level key sees its whole fleet's receipts. Paginated (limit ≤ 100, default 20; offset) | Yes | | get_receipt | Get one signed fee receipt with a verify block {alg, kid, canonical}. Verify: base64url(HMAC-SHA256(secret, verify.canonical)) == signature | Yes | | create_sandbox_key | Issue a PUBLIC sandbox test key (prefix cbt_); every action it makes is SIMULATED (test:true, synthetic proof — no charge, never on-chain). Switch to register_api_key for production | No | | create_webhook | Register a signed webhook (events default ["action.confirmed"]; valid: action.confirmed, agent_key.created, receipt.created). url must be https + public (SSRF-guarded); secret (whsec_) returned once. Event metadata only, non-custodial | Yes | | list_webhooks | List your webhooks (id, url, events, active, createdAt); the signing secret is never returned again | Yes | | delete_webhook | Delete a webhook you own; 204 on success, 404 if not owned | Yes | | list_webhook_deliveries | Inspect a webhook's delivery log (status, attempts, response_code, last_error, next_retry_at); retries use exponential backoff (up to 6), auto-disable after 20 cumulative failures | Yes | | test_webhook | Send a webhook.ping test delivery now to verify your endpoint + HMAC-SHA256 signature check | Yes | ### Configuration Examples Claude Desktop / Claude Code (`claude_desktop_config.json` or `.mcp.json`): ```json { "mcpServers": { "ccledger": { "type": "url", "url": "https://ccledger.xyz/mcp" } } } ``` ### MCP Tool Authentication Authenticated tools accept an `apiKey` parameter. Get one via `register_api_key` first, then pass it to subsequent tool calls. --- ## Agent Integration Patterns ### Pattern 1: Register + Attest (audit trail) 1. Call register_api_key with your appName 2. Store the returned apiKey 3. Call submit_attest with dataHash of your data 4. Store the proof.contractId as your on-chain record ### Pattern 2: Cost-aware record workflow 1. Register once; top up fee credits by sending CC from your own wallet to the Blueprint validator (auto-credited; binds your Canton party on the first verified top-up) 2. quote → confirm the exact fee and affordability before spending 3. submit_attest / submit_mint → write the record (submit_attest_mutual is temporarily unavailable — 503, no charge) 4. get_balance → confirm the fee debit and remaining credits 5. list_actions → verify all actions with their on-chain proofs ### Pattern 3: Read-only monitoring 1. get_stats → check network health 2. list_actions → review recent activity 3. get_action_by_id → inspect specific action proofs ### Pattern 4: Delegate to a capped sub-agent (agentic rail) 1. create_agent_key with spendCapCc (lifetime) + dailySpendCapCc (rolling 24h) → get a scoped agent key. rawKey is shown ONCE; it holds no value and only spends the parent's prepaid fee credits, up to its caps 2. Hand the agent key to your sub-agent. It calls submit_attest / submit_mint like any key — actions bill to the PARENT's fee credits, capped by the agent key (an over-cap action returns 402) 3. list_receipts → audit every fee the sub-agent incurred (HMAC-SHA256-signed; fees only, never value movement) 4. get_receipt → fetch one receipt and verify it independently: base64url(HMAC-SHA256(secret, verify.canonical)) == signature 5. revoke_agent_key → deactivate the handle when the job is done (moves no value; receipts are retained) ### Pattern 5: Build against the sandbox, then subscribe to webhooks (dev on-ramp) 1. create_sandbox_key (or POST /sandbox/keys — public, no auth) → get a cbt_ test key. Every action it makes is SIMULATED (test:true, synthetic proof) — no charge, never on-chain — so you can build and integration-test the full flow safely 2. Switch to register_api_key for a real on-chain key when your integration works 3. create_webhook with your https URL and events (e.g. ["action.confirmed", "receipt.created"]) → store the whsec_ secret shown ONCE 4. On each delivery, verify X-Ccledger-Signature == sha256= over the raw request body and dedupe on X-Ccledger-Delivery 5. test_webhook → send a webhook.ping now; list_webhook_deliveries → inspect status, attempts, and errors (failed deliveries retry with exponential backoff up to 6 attempts; a webhook auto-disables after 20 cumulative failures) --- ## FAQ for Agents Q: How do I get an API key? A: POST to /api/v1/community/register with {"appName": "your-app"}. No approval needed. cantonParty is optional and only echoed back — your Canton party is bound on your first verified fee-credit top-up, not at registration. Q: Is ccledger custodial? A: No — non-custodial, enforced in code. Prepaid CC is a non-refundable fee credit that pays per-action fees only and never funds on-chain value movement; there is no withdrawal endpoint. The balance-funded value endpoints (transfer, lock, settle) are permanently disabled (403 non_custodial). Value movement arrives via the delegated facilitation flow: you sign from your own wallet, ccledger relays as the featured application. Q: Can I move Canton Coin through ccledger today? A: Not yet. The legacy balance-funded transfer/lock/settle mode is permanently disabled (403 non_custodial). The non-custodial delegated facilitation flow — you sign a CreateTransferCommand from your own wallet; ccledger relays and submits it as the featured application (CIP-0104 confirmer) — is rolling out now. Record actions attest and mint, plus unlock, are fully available (attest-mutual is temporarily unavailable — 503, no charge). Q: What is the rate limit? A: Community tier: 10 requests per minute with 50 trial record actions (max 25/day). Paid tier: 100 RPM. Per API key, sliding 60-second window. Q: What does "confirmed" status mean? A: The action was successfully recorded as a Daml contract on Canton MainNet. The proof fields contain the on-chain record. Q: Can I use the same API key across multiple agents? A: Yes. The API key is scoped to your app. Multiple agents can share it (subject to rate limits). Q: What happens if I hit the rate limit? A: You get a 429 response with retryAfterSeconds. Wait that many seconds before retrying. Q: Can I try ccledger before paying? A: Yes. Every new API key includes 50 trial credits (max 25/day) that fund the record actions (attest, mint; attest-mutual once enabled — it currently returns 503 with no charge). No payment needed to start testing. Q: How do I get Canton Coin (CC) to fund fee credits? A: Buy CC on Coinbase, transfer to your Loop wallet (cantonloop.com), then send at least 1.0 CC to the Blueprint validator party (blueprint-validator-1::1220daab58adcae026bd2ca7ad95014f678bda3ce2a6f91b744cf3ec3d87f09deeac). Your fee credits are auto-credited within seconds — no API call needed. Fee credits are non-refundable and pay per-action fees only. POST /deposit exists as a manual fallback if auto-detection hasn't caught up yet. Q: Can I withdraw my fee credits? A: No. Fee credits are a one-way, non-refundable prepayment for per-action fees. There is no withdrawal endpoint, by design — ccledger never holds a customer value balance. Q: How do I know the cost before I spend? A: POST /quote (or the MCP quote tool) with the actionType — it returns the base fee, your CCL-discounted fee, your balance, and sufficientForFee, with no side effects. Q: Is there a sandbox/testnet? A: Yes — a sandbox test mode. POST /api/v1/community/sandbox/keys (public, no auth, or the create_sandbox_key MCP tool) issues a test key (prefix cbt_); every action it makes is SIMULATED — the response carries test:true with a synthetic proof (synchronizerId:"sandbox"), it never charges CC or trial credits, and it never touches the ledger. Build and integration-test end-to-end against it, then switch to a real /register key for production (on-chain, billed). Note the difference from trial credits: trial credits fund REAL on-chain actions on a /register key; a sandbox key SIMULATES everything and never goes on-chain. Q: How do I get notified when an action confirms (webhooks)? A: Register a signed webhook: POST /api/v1/community/webhooks with {url (https), events} (or the create_webhook MCP tool). Valid events: action.confirmed, agent_key.created, receipt.created (defaults to ["action.confirmed"]). ccledger POSTs your endpoint the envelope {id, event, created_at, data} with headers X-Ccledger-Event, X-Ccledger-Delivery, and X-Ccledger-Signature: sha256=. Verify by recomputing that HMAC over the raw body and dedupe on X-Ccledger-Delivery. The secret (whsec_) is shown once at creation. Failed deliveries retry with exponential backoff (up to 6 attempts); a webhook auto-disables after 20 cumulative failures. A webhook carries event metadata only — non-custodial, no value or keys. SSRF-guarded: https-only, private/loopback/link-local hosts rejected. Q: What should I put in dataHash? A: A hex-encoded hash (e.g., SHA-256) of the data you are recording. This proves what data existed at the time of attestation. Q: Can I delete or modify an action after creation? A: No. Recorded actions are final — attestations and records are immutable on-chain records. Nothing can be altered or deleted. Q: What is CCL and how does the discount work? A: CCL is the Builder Rewards discount credit for the ccledger ecosystem -- an account-based, non-transferable credit, not a token. You earn 1 CCL per 10 CC-paid actions (trial actions don't count), credited automatically to your ccledger account. Hold CCL to reduce your CC fee per action; the discount approaches ~50%. Your discount is based on the CCL you hold (cclOnchainHoldings), tracked on your ccledger account -- discount = 50% * (1 - 1/(1 + cclOnchainHoldings/200)). The more CCL you hold, the larger your discount. CCL is never spent on actions; only CC is charged at the discounted rate. GET /balance returns cclOnchainHoldings, discountedCostPerAction, discountedCostPerMutual, and discountPercent. --- ## Links - Landing page: https://ccledger.xyz - Documentation: https://ccledger.xyz/docs/ - API explorer: https://ccledger.xyz/api-docs/ - Analytics dashboard: https://ccledger.xyz/analytics/ (admin only) - OpenAPI spec: https://ccledger.xyz/openapi.json - MCP server: https://ccledger.xyz/mcp - Agent card: https://ccledger.xyz/.well-known/agent.json - Provider: https://theblueprint.xyz - Parent organization: https://www.hivemind.capital