139 lines
3.4 KiB
Markdown
139 lines
3.4 KiB
Markdown
# 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`.
|