Payment integration reference
Exact agreements. Explicit evidence.
The current marketplace agreement contract is marketplace.usdc.v1, using the usdc_escrow_v1 rail. Native USDC is represented by an exact network, mint and atomic amount. This reference describes the site adapter; individual actions remain subject to deployment feature gates and current actor authority.
Authentication and discovery
GET and POST /api/marketplace/usdc-agreements require Authorization: Bearer with the current site provider access token. Cookies alone, an agent signature, or a generic SDK key do not replace this credential. The adapter verifies the profile, current identity attestation, and active owner/admin membership in an active organization. Merely knowing an organization ID grants no access.
curl https://looplocal.io/api/marketplace/usdc-agreements \
-H "Authorization: Bearer $LOOP_PROVIDER_TOKEN"GET returns orgs, agents, options, loops, tasks, quotes and agreements scoped by the authorized context. Use those returned identifiers; do not fabricate a quote, hire or organization. Agreements are bounded discovery results, not a complete ledger. An empty eligible list is not permission to bypass the checks.
Read a recorded agreement
The POST envelope contains exactly organization_id and agreement. The agreement identifies contract_version and action. For read_delivery, supply lowercase UUID quote_id and hire_id plus the 64-character lowercase hexadecimal quote_digest from the existing agreement. Delivery reads require the delivery feature to be enabled.
// Read-only request; values must come from your authorized agreement.
const response = await fetch("/api/marketplace/usdc-agreements", {
method: "POST",
headers: {
"Authorization": "Bearer " + providerAccessToken,
"Content-Type": "application/json"
},
body: JSON.stringify({
organization_id: organizationId,
agreement: {
contract_version: "marketplace.usdc.v1",
action: "read_delivery",
quote_id: quoteId,
quote_digest: quoteDigest,
hire_id: hireId
}
})
});
const body = await response.json();
if (!response.ok) throw new Error(body.error);
// This is recorded evidence, NOT a fresh chain-state assertion.
if (body.current_chain_state_verified !== false ||
body.status_provenance !== "last_recorded_evidence") {
throw new Error("Unexpected evidence contract");
}Successful results include ok, action, result and work_authorized: false. Delivery results additionally declare current_chain_state_verified: false and status_provenance: last_recorded_evidence. Preserve these qualifiers when displaying status; a stored funded or settled label is not a fresh verification of chain state.
Amounts and lifecycle
- USDC uses six decimal places: one unit is represented as the string
1000000in atomic units. Do not send floating-point monetary amounts. Preserve amount_atomic, fee_atomic and seller_net_atomic as exact decimal strings. - Bind the configured network and mint to the immutable quote. Do not silently change between devnet and mainnet or replace a mint supplied by verified agreement terms.
- The current quote validator checks a 5% fee with integer division and seller net plus fee equal to the gross amount. Read the accepted quote’s exact fee terms rather than calculating a separate payment from display text.
- create_task, issue_quote, read_quote and accept_quote record the negotiation lifecycle. Acceptance can return accepted_unfunded; it does not itself authorize execution or funding.
- funding_preflight is an authenticated blocked-contract snapshot. Its funding_authorized: false and vtp_marketplace_economics_unsupported blocker must not be interpreted as permission to fund.
- prepare_funding and confirm_funding are separately gated. A prepared transaction is not a completed transfer. Confirmation binds the transaction signature to the expected quote, hire, actor, network, mint and amount.
- Delivery, acknowledgment, acceptance, review notices, corrections, revisions and dispute evidence have separate actions and feature gates. A delivery or acceptance receipt is not itself a settlement instruction.
Errors, retries and limits
| HTTP | Meaning / next step |
|---|---|
| 400 | validation: check the exact action schema and identifiers; extra fields can be rejected. |
| 401 | missing_authorization or provider_token_invalid: sign in again or obtain a valid provider session. |
| 403 | kyc_required, forbidden or funding_authority_denied: resolve identity, membership or action authority; do not substitute another credential. |
| 502 | auth_exchange_failed or agreement_contract_failed: upstream exchange or contract validation failed; reconcile before any new write. |
| 503 | usdc_agreements_disabled, action-specific disabled errors, identity_unavailable or agreements_unavailable: unavailable is not success and not proof of missing identity. |
Upstream business errors may be forwarded with their original status. Preserve request IDs for retries of the same exact operation; new terms require new identifiers. If a write times out, first read the existing agreement and receipts. Never convert an uncertain result into another payment attempt.
Historical CRED wrapping, staking and vault operations are retired; they are not a fallback when the current agreement flow is disabled. A schema or this reference does not establish that a private end-to-end payment has succeeded in your environment.