# m2-ledger API contract v1 S1 owns ledger semantics. Marketplace clients MUST use the `/v1/*` paths below; older `/tx/install`, `/tx/refund`, `/license/*`, `/licenses/check`, and `/balance/*` paths are not contractual for m2-market. All mutation requests require `Idempotency-Key` or an `idempotency_key` body field. If both are present, they must match. All amounts are integer `m2cr`. ## Identity `GET /v1/accounts/me` Returns the caller's resolved ledger identity: ```json { "account_id": "acct_op_chris", "operator_id": "op_chris", "tenant_id": "m2", "scopes": ["ledger:read", "ledger:install"] } ``` ## Balances `GET /v1/balances/{account_or_operator_id}` Returns a balance derived from the append-only transaction log. Store and Scout do not call this directly; they use `m2-market wallet`. ```json { "account_id": "acct_op_chris", "operator_id": "op_chris", "tenant_id": "m2", "balance": 100, "currency": "m2cr", "as_of": "2026-07-02T00:00:00Z" } ``` ## Install settlement `POST /v1/settlements/install` Fixed-price install settlement. Job-priced listings are refused by the CLI before this call and use the jobs API instead. ```json { "buyer_operator_id": "op_chris", "seller_operator_id": "op_m2core", "tenant_id": "m2", "listing_id": "lst_mm-pdf-report", "solution_id": "sol_mm-pdf-report", "solution_version": "1.0.0", "major_version": 1, "install_ref": "lst_mm-pdf-report-v1.0.0", "price": {"model": "fixed", "amount": 25, "currency": "m2cr"}, "revenue_split": {"platform_pct": 10, "seller_pct": 90} } ``` Success returns the transaction group and license grant. The CLI MUST persist `tx_group_id` in `~/.m2-market/state.json` before apply so refund can be addressed by group id. ```json { "tx_group_id": "txg_01j2install", "grant_id": "gr_01j2license", "balance": 75, "license": { "operator_id": "op_chris", "listing_id": "lst_mm-pdf-report", "major_version": 1, "status": "active" } } ``` `402 insufficient_funds` writes no transactions or grant. Repeated idempotency keys return the original settlement. ## Refund on apply failure `POST /v1/settlements/install/{tx_group_id}/refund` Refunds by `tx_group_id`, not by listing ref. Refunds are compensating append-only rows and mark the related license grant `refunded`. ```json { "reason": "apply_failed", "apply_error": "verify command failed", "listing_id": "lst_mm-pdf-report" } ``` ## Licenses `GET /v1/licenses/{operator_id}/{listing_id}?major_version=1` Returns the active/refunded/revoked grant for `(operator_id, listing_id, major_version)`, or `404` for not found or forbidden. ## Starter grants `POST /v1/grants/starter` Admin/service scoped. Default amount is `100 m2cr`. ## Jobs `POST /v1/jobs` Creates a funded job/escrow for job-priced listings. Job settlements use ledger `tx_type=job`. Additional job paths: - `POST /v1/jobs/{job_id}/start` - `POST /v1/jobs/{job_id}/milestones/{milestone_id}/submit` - `POST /v1/jobs/{job_id}/milestones/{milestone_id}/accept` - `POST /v1/jobs/{job_id}/cancel` - `POST /v1/jobs/{job_id}/dispute` ## Route/resource settlement `POST /v1/settlements/route` Records credit-denominated route/resource rows tied to m2-gpt metering references. It does not modify m2-gpt metering. ## Audit snapshots `POST /v1/admin/snapshots` Writes deterministic balance/hash-chain snapshots to Forgejo repo `m2/market-audit`, not to the registry repo `m2/m2-market`.