3.4 KiB
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:
{
"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.
{
"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.
{
"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.
{
"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.
{
"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}/startPOST /v1/jobs/{job_id}/milestones/{milestone_id}/submitPOST /v1/jobs/{job_id}/milestones/{milestone_id}/acceptPOST /v1/jobs/{job_id}/cancelPOST /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.