跳到內容

Managed Space commerce

本頁內容尚未翻譯。

Managed Space admission remains either free or a one-time purchase. Consumable, durable, and subscription products are in-app catalog items; subscriptions do not grant Space admission.

Creator-operated game-session escrow is a separate accounting contract. See Managed Space wager sessions; catalog purchases and wager buy-ins must not share endpoints or authority.

An opaque Space iframe sends arinova:purchase-request with its fragment-bound bridgeToken and a catalog productKey. The first-party parent loads the authoritative catalog, shows a native confirmation, and performs the session-authenticated purchase with expectedPricePoints and an idempotency key. The iframe receives arinova:purchase-result. It cannot submit a price or call a debit endpoint directly.

The protocol-v1 request shape is:

{
"type": "arinova:purchase-request",
"bridgeToken": "fragment-bound-token",
"payload": { "protocolVersion": 1, "productKey": "coins.small" }
}

The result uses status: "purchased", "cancelled", or "error"; a successful result includes the server grantId or subscriptionId. The parent ignores messages from any source other than the active opaque iframe, and ignores a missing or mismatched bridge token.

There is no daily spend cap. Native confirmation is required for every charge; authenticated rate limiting remains the capacity control. Creators receive 70% of paid-funded points. Bonus-funded points do not create creator earnings.

space_item_grants, space_inventory_ledger, and space_subscriptions are the only authoritative item and subscription state. Never store balances, entitlements, inventory quantities, or subscription unlock state in space_storage: the same player OAuth token can write that key/value storage, so a player can modify it. Space storage is suitable only for non-authoritative preferences and save data.

Runtime inventory consumes require a visible-ASCII idempotency key and are atomic. Durable products cannot be purchased twice; consumables use a server counter. Subscription state is returned separately from item grants.

Runtime endpoints (Space OAuth Bearer token):

  • GET /api/v1/spaces/{spaceId}/products
  • GET /api/v1/spaces/{spaceId}/inventory
  • POST /api/v1/spaces/{spaceId}/inventory/{productKey}/consume with { "quantity": 1, "idempotencyKey": "stable-retry-key" }

First-party parent/creator endpoints (browser session only):

  • GET /api/spaces/{spaceId}/products
  • POST /api/spaces/{spaceId}/products/{productKey}/purchase
  • GET|POST /api/creator/spaces/{spaceId}/products[...] for owner CRUD
  • GET /api/space-subscriptions and subscription cancel, resume, retry, and first-period refund actions
  • Admission purchases may be refunded within one hour. Refunding permanently blocks another admission purchase for that user and Space.
  • A subscription’s first period may be refunded within one hour. This ends the subscription but does not write the admission repurchase ban.
  • Subscription renewals are not refundable. Users cancel at period end, resume a pending cancellation, or retry a past-due payment from the Space detail or wallet UI.
  • Consumable or durable purchases are refunded only by an admin and only while the grant has not been consumed or otherwise reduced.

Bearer-authenticated runtime reads and writes under /api/v1/spaces/{id} use a dedicated Access-Control-Allow-Origin: * policy without credentials, which is valid for opaque Origin: null iframes. The Space OAuth profile, Agent chat, and read-only economy routes use the same isolated policy. Session purchase endpoints remain on the credentialed first-party CORS policy and are reachable only through the parent bridge.

The automated local probe uploads and publishes a minimal opaque-iframe bundle, then verifies storage, catalog, and inventory preflights return Access-Control-Allow-Origin: * without credentials. It also verifies the session purchase preflight does not return a wildcard, the retired free-amount endpoint returns 410, and a malicious JavaScript bundle is blocked on publish. Manifest declaredApiOrigins remain valid CSP configuration and are not mistaken for user-facing exfiltration links; all executable JavaScript and other manifest fields remain scanned.

Build a7f47a5ca54ddcf7806cd48b81ce1b9827042766