{"service":"Klima Retirement Aggregator","apiVersion":"1.0.0","versionedHosts":{"latest":"x402.klimalabs.com","current":"v1.x402.klimalabs.com","note":"The bare host serves the latest release. Pin v1.x402.klimalabs.com to stay on this major across future releases. Prior majors keep answering at their own v<major>.x402.klimalabs.com host."},"releases":[{"version":"1.0.0","releaseDate":"2026-07-27","breaking":true,"changes":[{"kind":"breaking","action":"prepare-auth, actions/retire","summary":"A relayed retirement must now name its beneficiary unless beneficiaryIsPayer is set to true. Previously an omitted details.beneficiaryAddress silently defaulted to the payer (`from`); it now returns 400 attribution_required."},{"kind":"added","action":"prepare-auth, actions/retire","summary":"New optional boolean `beneficiaryIsPayer`. Set it to true to credit the paying wallet deliberately; this is the explicit form of the old default behavior. Accepts a JSON boolean or the string \"true\"/\"false\" (GET aliases pass query values as strings)."},{"kind":"changed","action":"prepare-auth, actions/retire","summary":"On the USDC path the EIP-3009 authorization nonce is now keccak256 of the retirement being authorized (credit, tokenId, amount, the full attribution struct) plus a per-authorization salt, instead of a random value. Since nonce is a signed field, the signature now binds what is retired and who is credited, not just the spend value. actions/retire rebuilds the retirement, re-hashes it with the submitted salt, and returns 400 params_mismatch on a mismatch. No client change if you post `actionsRetireRequest` as returned. The kVCM (EIP-2612) path is unchanged. Permit's nonce is the token's own counter, so it cannot carry a commitment."},{"kind":"added","action":"prepare-auth, actions/retire","summary":"New top-level `salt` (bytes32). prepare-auth mints a fresh one per authorization and returns it inside `actionsRetireRequest`; actions/retire requires it alongside a USDC authPayload and returns 400 invalid_auth_payload without it. It is the second input to the authorization nonce. It is not a secret: the nonce is fixed by the payer's signature, so no attacker-chosen salt can make a different retirement hash to it. Its purpose is to keep the commitment verifiable without being deterministic. USDC burns each (from, nonce) pair permanently, so an unsalted commitment would make two identical retirements by the same payer collide and the second revert inside the token. Absent on the kVCM path."},{"kind":"added","action":"*","summary":"This changelog, at /.well-known/x402-changelog.json (GET alias /api/changelog)."},{"kind":"added","action":"*","summary":"A machine-readable error-code registry at /.well-known/x402-errors.json (GET alias /api/errors): every `error` value the API can return, with its HTTP status, group, retryable flag, emitting actions, meaning, and remedy. The discovery manifest links it and now lists per-action `errorCodes`. No response shape changed — this documents codes that already existed."},{"kind":"added","action":"*","summary":"Unknown routes and GET /api now return a machine-readable action index instead of a bare not_found body."},{"kind":"added","action":"certificate, actions/retire","summary":"Each entry in `retirements[]` now carries `beneficiaryAddress`, the address credited on-chain. It is the field to check when verifying attribution: `retiringAddress` is the aggregator's settlement address, not the party the retirement was made for. Additive — existing fields are unchanged."},{"kind":"changed","action":"prepare/retire","summary":"Unaffected by the attribution requirement. On the self-submit path the payer is msg.sender, so defaulting attribution to the payer stays correct."}],"migration":"On prepare-auth and actions/retire, send details.beneficiaryAddress set to the party the retirement is for. If you are retiring for yourself and want the paying wallet credited, send beneficiaryIsPayer: true instead. If you build the actions/retire body yourself instead of posting the returned `actionsRetireRequest`, note that on USDC the authorization nonce now commits to the retirement — you must forward the top-level `salt` from prepare-auth, and altering creditToken, tokenId, amount, or details after signing returns 400 params_mismatch. A salt is single-use; reusing one from an earlier authorization will not reproduce the nonce. The previous major version stays available at the v0 host (see `versionedHosts` in this document) if you need time to migrate."},{"version":"0.2.1","releaseDate":"2026-07-10","breaking":true,"changes":[{"kind":"breaking","action":"prepare/retire, prepare-auth, actions/retire","summary":"The request body became strict at the top level. Unknown top-level keys previously passed validation and were silently discarded; they now return 400 schema_validation with the offending key in `issues`. This shipped without a changelog entry at the time and is recorded here retroactively."}],"migration":"Attribution fields belong inside the `details` object, not at the top level: send { details: { beneficiaryAddress, beneficiaryString, ... } }. A top-level beneficiaryAddress was never read and before this release it was dropped silently, so retirements sent that way were attributed to the payer default rather than to the intended party."},{"version":"0.1.0","releaseDate":"2026-05-18","breaking":false,"changes":[{"kind":"added","action":"*","summary":"First tagged release. Changes before this point are not tracked here."}]}]}