{"openapi":"3.1.0","info":{"title":"Euphoric sandbox API","version":"0.2.0","description":"Prepaid, agent-first hosting API. Not open for customers: euphoric-host.eu serves documentation only. Persistent local sandbox API plus private operator-admitted staging on real cloud servers in the EU, live-validated for curated images. Sandbox remains the development/test default; default production is disabled. Staging must not be exposed as anonymous hosting. Temporary acceptance infrastructure has been removed. Credit is simulated in both environments. Historical saved idempotency responses are preserved. Opt-in test-runtime-v1 adds metered test credit, funded authorization, suspension/resume and billing events. No real funding. Legacy fixed-reservation records remain separate. Funded host behavior, outage and recovery cases passed known-image live acceptance in private staging in September 2026. Closed production foundation deployments expose the website/documentation only; all customer API routes return HTTP 404 foundation_closed and cannot enqueue customer work. Use local development/test for these examples."},"servers":[{"url":"http://localhost:3000","description":"Local development"}],"security":[{"bearerAuth":[]}],"paths":{"/v1/bootstrap":{"post":{"operationId":"bootstrap","summary":"Register or recover an accountless principal","responses":{"201":{"description":"Register or recover an accountless principal","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Bootstrap"}}}},"default":{"description":"Actionable API error (400, 401, 402, 403, 404, 409, 413, 415, 422, or 503).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"parameters":[{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","pattern":"^[a-zA-Z0-9_-]{1,100}$"},"description":"Reuse the same key and body after a timeout. A different body under the same key returns 409."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"contact":{"type":"string","maxLength":254,"description":"Email or HTTPS callback. Stored as unverified; bootstrap sends nothing. Explicit scoped verification is available with operator-configured delivery, disabled by default."}},"required":["contact"]}}}},"description":"Available in the local sandbox or through the private staging operator endpoint. Bootstrap does not admit a staging principal or grant credit; an operator must do so separately. Contact remains unverified."}},"/v1/balance":{"get":{"operationId":"getBalance","summary":"Read test credit and reservations","responses":{"200":{"description":"Read test credit and reservations","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Balance"}}}},"default":{"description":"Actionable API error (400, 401, 402, 403, 404, 409, 413, 415, 422, or 503).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"description":"Requires scope: applications:read."}},"/v1/sandbox/credits":{"post":{"operationId":"grantTestCredit","summary":"Grant EUR 30 test credit once per principal","responses":{"200":{"description":"Grant EUR 30 test credit once per principal","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Balance"}}}},"default":{"description":"Actionable API error (400, 401, 402, 403, 404, 409, 413, 415, 422, or 503).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"description":"Requires scope: sandbox:credit. Available only in the development/test sandbox. Private staging credit is granted through an operator task.","parameters":[{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","pattern":"^[a-zA-Z0-9_-]{1,100}$"},"description":"Reuse the same key and body after a timeout. A different body under the same key returns 409."}]}},"/v1/applications":{"get":{"operationId":"listApplications","summary":"List the 50 most recent applications","responses":{"200":{"description":"List the 50 most recent applications","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApplicationList"}}}},"default":{"description":"Actionable API error (400, 401, 402, 403, 404, 409, 413, 415, 422, or 503).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"description":"Requires scope: applications:read. Returns an applications array, newest first, including deleted records. Recover a lost application_id by matching the name and reading id."},"post":{"operationId":"createApplication","summary":"Create a budgeted application and initial release","responses":{"202":{"description":"Create a budgeted application and initial release","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Accepted"}}}},"default":{"description":"Actionable API error (400, 401, 402, 403, 404, 409, 413, 415, 422, or 503).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"423":{"description":"principal_held: operator hold prevents new work or payment initiation. Inspect existing resources and contact the operator.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"description":"Requires applications:write. Local execution is simulated. Private staging additionally requires operator admission, allowlisted images, campaign capacity and provider spending reservation. Historical idempotency responses retain their original schema.","parameters":[{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","pattern":"^[a-zA-Z0-9_-]{1,100}$"},"description":"Reuse the same key and body after a timeout. A different body under the same key returns 409."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","pattern":"^[a-z][a-z0-9-]{2,39}$","description":"Optional: omission generates three readable words. Explicit null/empty is invalid. Display name is principal-unique; hostname slug remains stable after renaming."},"image":{"type":"string","maxLength":512,"pattern":"^[a-zA-Z0-9][a-zA-Z0-9._:/-]*@sha256:[a-f0-9]{64}$","example":"registry.example/euphoric/hello@sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"},"plan_id":{"const":"test-runtime-v1","description":"Select metered test billing. Omit to retain the legacy fixed EUR 1 reservation API."},"spend_limit_micro":{"type":"integer","minimum":3000,"maximum":100000000,"description":"Required with plan_id. Total application lifetime ceiling, including reservations."},"stop_at":{"type":"string","format":"date-time","description":"Optional explicit stop deadline with timezone, at least five minutes ahead at creation. Top-ups do not extend it."}},"required":["image"],"dependentRequired":{"plan_id":["spend_limit_micro"],"spend_limit_micro":["plan_id"],"stop_at":["plan_id"]}}}}}}},"/v1/applications/{id}":{"get":{"operationId":"getApplication","summary":"Read an application","responses":{"200":{"description":"Read an application","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Application"}}}},"default":{"description":"Actionable API error (400, 401, 402, 403, 404, 409, 413, 415, 422, or 503).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"description":"Requires scope: applications:read.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}]},"delete":{"operationId":"deleteApplication","summary":"Fence old operations and queue provider cleanup","responses":{"202":{"description":"Deletion accepted; poll the returned operation until cleanup completes.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Accepted"}}}},"default":{"description":"Actionable API error (400, 401, 402, 403, 404, 409, 413, 415, 422, or 503).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"description":"Requires applications:write and an idempotency key. Cleanup uses the application's recorded provider. Staging withdraws routing, removes tenant resources and invalidates management access; capacity and test-credit reservations are released only after confirmed cleanup. Failed cleanup retains reservations. The hostname remains reserved after deletion.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","pattern":"^[a-zA-Z0-9_-]{1,100}$"},"description":"Reuse the same key and body after a timeout. A different body under the same key returns 409."}]},"patch":{"operationId":"renameApplication","summary":"Rename the display label without changing UUID, slug or URL","responses":{"default":{"description":"Actionable API error (400, 401, 402, 403, 404, 409, 413, 415, 422, or 503).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"200":{"description":"Rename the display label without changing UUID, slug or URL","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Application"}}}}},"description":"Requires applications:write and an idempotency key. Only name may be changed. Deleted applications cannot be renamed.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","pattern":"^[a-zA-Z0-9_-]{1,100}$"},"description":"Reuse the same key and body after a timeout. A different body under the same key returns 409."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","pattern":"^[a-z][a-z0-9-]{2,39}$","description":"Optional: omission generates three readable words. Explicit null/empty is invalid. Display name is principal-unique; hostname slug remains stable after renaming."}},"required":["name"],"additionalProperties":false}}}}}},"/v1/applications/{id}/exports":{"post":{"operationId":"exportApplication","summary":"Export configuration only (in operation result)","responses":{"202":{"description":"Export configuration only (in operation result)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Accepted"}}}},"default":{"description":"Actionable API error (400, 401, 402, 403, 404, 409, 413, 415, 422, or 503).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"description":"Requires scope: applications:read. Metered applications may also export configuration while suspended during retention.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","pattern":"^[a-zA-Z0-9_-]{1,100}$"},"description":"Reuse the same key and body after a timeout. A different body under the same key returns 409."}]}},"/v1/applications/{id}/logs":{"get":{"operationId":"getLogs","summary":"Read bounded application logs for the recorded provider","responses":{"200":{"description":"Read bounded application logs for the recorded provider","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Logs"}}}},"default":{"description":"Actionable API error (400, 401, 402, 403, 404, 409, 413, 415, 422, or 503).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"description":"Requires applications:read. Sandbox source is operation_events. Staging source is container with release_id, stdout/stderr lines and cursor; at most 100 lines / 64 KiB. Cursor uses an inclusive timestamp (the boundary may repeat), expires in one hour, and is bound to this app/release. Retry without cursor on runtime_logs_unavailable (503). Operation events remain in GET /v1/operations/{id}.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"cursor","in":"query","schema":{"type":"string"},"description":"Opaque cursor returned by a staging logs response."}]}},"/v1/operations/{id}":{"get":{"operationId":"getOperation","summary":"Read durable operation progress and result","responses":{"200":{"description":"Read durable operation progress and result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Operation"}}}},"default":{"description":"Actionable API error (400, 401, 402, 403, 404, 409, 413, 415, 422, or 503).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"description":"Requires scope: operations:read.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}]}},"/v1/applications/{id}/releases":{"get":{"operationId":"listReleases","summary":"Read the latest 50 releases","responses":{"200":{"description":"Read an application","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReleaseList"}}}},"default":{"description":"Actionable API error (400, 401, 402, 403, 404, 409, 413, 415, 422, or 503).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"description":"Requires applications:read. Principal-scoped immutable image history with state and active marker; no idempotency key.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}]},"post":{"operationId":"replaceRelease","summary":"Replace an application release at its stable URL","responses":{"202":{"description":"Replace an application release at its stable URL","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Accepted"}}}},"default":{"description":"Actionable API error (400, 401, 402, 403, 404, 409, 413, 415, 422, or 503).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"423":{"description":"principal_held: operator hold prevents new work or payment initiation. Inspect existing resources and contact the operator.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"description":"Requires applications:write and an idempotency key. Wait for the current operation to finish. Staging allows only curated images; failed candidates preserve the previous active release. Sandbox replacement is simulated.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","pattern":"^[a-zA-Z0-9_-]{1,100}$"},"description":"Reuse the same key and body after a timeout. A different body under the same key returns 409."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"image":{"type":"string","maxLength":512,"pattern":"^[a-zA-Z0-9][a-zA-Z0-9._:/-]*@sha256:[a-f0-9]{64}$","example":"registry.example/euphoric/hello@sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"}},"required":["image"]}}}}}},"/v1/plans":{"get":{"operationId":"listPlans","summary":"List versioned test pricing and runtime policy. Requires applications:read.","description":"List versioned test pricing and runtime policy. Requires applications:read.","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlanList"}}}},"default":{"description":"Actionable API error (400, 401, 402, 403, 404, 409, 413, 415, 422, or 503).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"parameters":[]}},"/v1/billing/balance":{"get":{"operationId":"meteredBalance","summary":"Read separate metered test balance in exact EUR micro-units. Requires applications:read. Runway uses posted usage and current rates; inspect application metering/deadlines for freshness and policy limits. No idempotency key.","description":"Read separate metered test balance in exact EUR micro-units. Requires applications:read. Runway uses posted usage and current rates; inspect application metering/deadlines for freshness and policy limits. No idempotency key.","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MeteredBalance"}}}},"default":{"description":"Actionable API error (400, 401, 402, 403, 404, 409, 413, 415, 422, or 503).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"parameters":[]}},"/v1/billing/events":{"get":{"operationId":"billingEvents","summary":"Read durable principal-scoped billing events, newest first. Requires applications:read. Polling only; no outbound callbacks. Deduplicate by event id; warnings rearm after runway rises above the threshold.","description":"Read durable principal-scoped billing events, newest first. Requires applications:read. Polling only; no outbound callbacks. Deduplicate by event id; warnings rearm after runway rises above the threshold.","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BillingEventList"}}}},"default":{"description":"Actionable API error (400, 401, 402, 403, 404, 409, 413, 415, 422, or 503).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"parameters":[{"name":"before","in":"query","schema":{"type":"string","format":"uuid"},"description":"Use next_before to read older pages. Unknown or other-principal cursor returns 404."}]}},"/v1/sandbox/funding":{"post":{"operationId":"fundMeteredTestBalance","summary":"Add metered test credit in development/test. Requires sandbox:credit. Each grant is 1–3000 EUR cents, lifetime total EUR 100 per principal. No money moves. Duplicate keys recover the original grant; top-ups never automatically resume applications. Staging returns 503 and uses audited operator admission.","description":"Add metered test credit in development/test. Requires sandbox:credit. Each grant is 1–3000 EUR cents, lifetime total EUR 100 per principal. No money moves. Duplicate keys recover the original grant; top-ups never automatically resume applications. Staging returns 503 and uses audited operator admission.","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MeteredBalance"}}}},"default":{"description":"Actionable API error (400, 401, 402, 403, 404, 409, 413, 415, 422, or 503).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"parameters":[{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","pattern":"^[a-zA-Z0-9_-]{1,100}$"},"description":"Reuse the same key and body after a timeout. A different body under the same key returns 409."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"amount_minor":{"type":"integer","minimum":1,"maximum":3000}},"required":["amount_minor"],"additionalProperties":false}}}}}},"/v1/applications/{id}/suspend":{"post":{"operationId":"suspendApplication","summary":"Suspend a ready metered application after other operations finish. Confirmed stop releases unused runtime funds and starts 72-hour retention. Repeated suspension is a 409 except idempotent replay. Requires applications:write. Poll the returned operation state.","description":"Suspend a ready metered application after other operations finish. Confirmed stop releases unused runtime funds and starts 72-hour retention. Repeated suspension is a 409 except idempotent replay. Requires applications:write. Poll the returned operation state.","responses":{"202":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Accepted"}}}},"default":{"description":"Actionable API error (400, 401, 402, 403, 404, 409, 413, 415, 422, or 503).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","pattern":"^[a-zA-Z0-9_-]{1,100}$"},"description":"Reuse the same key and body after a timeout. A different body under the same key returns 409."}]}},"/v1/applications/{id}/resume":{"post":{"operationId":"resumeApplication","summary":"Explicitly resume a suspended metered application before retention expires. Requires at least five minutes of funds and unused lifetime budget, and a future/cleared stop deadline. 402 for insufficient funding or ceiling, 409 for expired retention/deadline or incompatible state. Requires applications:write. Poll the returned operation state.","description":"Explicitly resume a suspended metered application before retention expires. Requires at least five minutes of funds and unused lifetime budget, and a future/cleared stop deadline. 402 for insufficient funding or ceiling, 409 for expired retention/deadline or incompatible state. Requires applications:write. Poll the returned operation state.","responses":{"202":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Accepted"}}}},"default":{"description":"Actionable API error (400, 401, 402, 403, 404, 409, 413, 415, 422, or 503).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"423":{"description":"principal_held: operator hold prevents new work or payment initiation. Inspect existing resources and contact the operator.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","pattern":"^[a-zA-Z0-9_-]{1,100}$"},"description":"Reuse the same key and body after a timeout. A different body under the same key returns 409."}]}},"/v1/applications/{id}/billing":{"patch":{"operationId":"updateBillingPolicy","summary":"Update a metered application policy. Requires applications:write. Raise/lower the lifetime ceiling only above already charged plus committed runtime. An earlier stop than issued authorization requires confirmed suspension first (409). Set stop_at:null to remove a stop deadline. Changing policy never automatically resumes runtime.","description":"Update a metered application policy. Requires applications:write. Raise/lower the lifetime ceiling only above already charged plus committed runtime. An earlier stop than issued authorization requires confirmed suspension first (409). Set stop_at:null to remove a stop deadline. Changing policy never automatically resumes runtime.","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Application"}}}},"default":{"description":"Actionable API error (400, 401, 402, 403, 404, 409, 413, 415, 422, or 503).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","pattern":"^[a-zA-Z0-9_-]{1,100}$"},"description":"Reuse the same key and body after a timeout. A different body under the same key returns 409."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"spend_limit_micro":{"type":"integer","minimum":3000,"maximum":100000000},"stop_at":{"type":["string","null"],"format":"date-time"}},"minProperties":1,"additionalProperties":false}}}}}},"/v1/payment-orders":{"post":{"operationId":"createPaymentOrder","summary":"Requires payments:write. Opt-in test-only EUR funding before an app exists. One-hour immutable quote; 3 unresolved orders, 10 new/hour. Replays preserve response and quota. No provider call during this request. Optional immutable payment_method defaults to stripe_checkout; stripe_spt stores a test-only MPP challenge.","parameters":[{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","pattern":"^[a-zA-Z0-9_-]{1,100}$"},"description":"Reuse the same key and body after a timeout. A different body under the same key returns 409."}],"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaymentOrder"}}}},"default":{"description":"JSON errors: 400 malformed input, 401 inactive credential, 403 missing scope, 404 scoped absence, 409 conflict, 413 body limit, 415 content type, 422 validation, 429 quota (Retry-After), 503 payment_unavailable.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"423":{"description":"principal_held: operator hold prevents new work or payment initiation. Inspect existing resources and contact the operator.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["amount_minor","currency"],"properties":{"amount_minor":{"type":"integer","minimum":100,"maximum":3000},"currency":{"const":"EUR"},"payment_method":{"type":"string","enum":["stripe_checkout","stripe_spt"],"default":"stripe_checkout","description":"Immutable. SPT requires separate operator capability and protected credential encryption keys."}},"additionalProperties":false}}}}}},"/v1/payment-orders/{id}/pay":{"post":{"operationId":"initiatePayment","summary":"Requires payments:write and an empty JSON object. Checkout keeps its existing initiation flow. SPT discovery returns uncached 402; a validated credential atomically persists encrypted custody, replay identity and work, returning stable 202 pending. Only order inspection with credited and receipt confirms SPT credit.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","pattern":"^[a-zA-Z0-9_-]{1,100}$"},"description":"Reuse the same key and body after a timeout. A different body under the same key returns 409."},{"name":"Payment-Authorization","in":"header","required":false,"schema":{"type":"string","maxLength":8192},"description":"SPT only: Payment <base64url credential>, at most 8192 encoded header bytes and 6144 decoded JSON bytes. Keep Authorization: Bearer separately. Echo the stored challenge exactly. Duplicate/ambiguous headers, altered terms and malformed/expired credentials return 400. Changed accepted token returns 409 even with the same body/key; cross-order token reuse returns 409. Exact accepted retries recover after quote expiry, including header-free retries. Never log this header."}],"responses":{"202":{"description":"Durable acceptance, not payment completion. Replay returns this original body even after credit. SPT adds payment_status=pending and next_action=poll_order; no Payment-Receipt is emitted here.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaymentAccepted"}}},"headers":{"Location":{"schema":{"type":"string"},"description":"SPT order inspection path. Authenticated GET only; do not issue another spend request."}}},"default":{"description":"JSON errors: 400 malformed input, 401 inactive credential, 403 missing scope, 404 scoped absence, 409 conflict, 413 body limit, 415 content type, 422 validation, 429 quota (Retry-After), 503 payment_unavailable.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Owned, unsubmitted SPT order requires its stored MPP credential. This non-mutating prerequisite is not saved in the idempotency cache. Reuse the same key/body with Payment-Authorization. No provider effect. Disabled intake returns 503; unsubmitted expired orders return 409.","headers":{"WWW-Authenticate":{"schema":{"type":"string"},"description":"MPP stripe/charge, EUR minor units, card only, test profile, expiry and opaque principal/order/request binding; header=Payment-Authorization."},"Cache-Control":{"schema":{"const":"no-store"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"423":{"description":"principal_held: operator hold prevents new work or payment initiation. Inspect existing resources and contact the operator.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false}}}}}},"/v1/payment-orders/{id}":{"get":{"operationId":"getPaymentOrder","summary":"Requires payments:read. No idempotency header. Owner-only, no-store. Checkout capability appears only while payable. needs_review requires operator reconciliation. Top-up never resumes applications. SPT GET never submits or settles credentials. Receipt body/header appears only after committed credit; pending/review states have none. Quote expiry does not close in-flight SPT payments. Processing polls; unsupported action/declines require operator review without replacement.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaymentOrder"}}},"headers":{"Payment-Receipt":{"schema":{"type":"string"},"description":"SPT only, after state=credited: stable base64url MPP receipt corresponding to the receipt JSON body. Never present before the ledger commit."}}},"default":{"description":"JSON errors: 400 malformed input, 401 inactive credential, 403 missing scope, 404 scoped absence, 409 conflict, 413 body limit, 415 content type, 422 validation, 429 quota (Retry-After), 503 payment_unavailable.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/webhooks/stripe":{"post":{"operationId":"receiveStripeTestWebhook","security":[],"summary":"Dedicated signed test inbox. Raw body up to 256 KiB; Stripe-Signature required, 300-second tolerance. Configured account, test mode and pinned event API version required. Durable receipt before acknowledgement; never fulfills from event payload alone.","parameters":[{"name":"Stripe-Signature","in":"header","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object"}}}},"responses":{"200":{"description":"Durably received (including duplicate deliveries)."},"default":{"description":"JSON errors: 400 malformed input, 401 inactive credential, 403 missing scope, 404 scoped absence, 409 conflict, 413 body limit, 415 content type, 422 validation, 429 quota (Retry-After), 503 payment_unavailable.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/contact":{"get":{"operationId":"inspect_contact","summary":"inspect contact","description":"Required scope: contact:read. No token or full callback URL. Bootstrap sends nothing; existing contacts remain unverified.","responses":{"200":{"description":"Accepted result; read current state separately after replays.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContactStatus"}}}},"default":{"description":"JSON error. 400/401/403/404/409/413/415/422/423/429/503; rate limits include Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/contact/verifications":{"post":{"operationId":"request_contact_verification","summary":"request contact verification","description":"Required scope: contact:write. Explicit 30-minute challenge; resends supersede pending challenges. Disabled by default. Email link uses fragment and deliberate CSRF POST. Callback receipt never verifies. Limits: one/minute, five/hour/principal; ten/day/destination. Saved response contains no capability.","responses":{"202":{"description":"Accepted result; read current state separately after replays.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContactAccepted"}}}},"default":{"description":"JSON error. 400/401/403/404/409/413/415/422/423/429/503; rate limits include Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"parameters":[{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","pattern":"^[a-zA-Z0-9_-]{1,100}$"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"properties":{},"required":[]}}}}}},"/v1/contact/verifications/{id}/confirm":{"post":{"operationId":"confirm_contact","summary":"confirm contact","description":"Required scope: contact:write. Principal scoped single-use capability. Wrong, expired, superseded or recovery-cancelled capability returns generic 422. Valid consumed confirmation is harmless. Revoked credentials fail before replay.","responses":{"200":{"description":"Accepted result; read current state separately after replays.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContactConfirmed"}}}},"default":{"description":"JSON error. 400/401/403/404/409/413/415/422/423/429/503; rate limits include Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","pattern":"^[a-zA-Z0-9_-]{1,100}$"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"properties":{"token":{"type":"string","pattern":"^[a-f0-9]{64}$"}},"required":["token"]}}}}}},"/v1/notices":{"get":{"operationId":"list_notices","summary":"list notices","description":"Required scope: safety:read. Published customer content only. Remains readable while held or unadmitted; no reporter identity or evidence.","responses":{"200":{"description":"Accepted result; read current state separately after replays.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SafetyNoticePage"}}}},"default":{"description":"JSON error. 400/401/403/404/409/413/415/422/423/429/503; rate limits include Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"parameters":[{"name":"cursor","in":"query","schema":{"type":"string"},"description":"Opaque next_cursor from this endpoint. Maximum 50 results."}]}},"/v1/notices/{id}":{"get":{"operationId":"inspect_notice","summary":"inspect notice","description":"Required scope: safety:read. ","responses":{"200":{"description":"Accepted result; read current state separately after replays.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SafetyNotice"}}}},"default":{"description":"JSON error. 400/401/403/404/409/413/415/422/423/429/503; rate limits include Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}]}},"/v1/notices/{id}/appeals":{"post":{"operationId":"appeal_decision","summary":"appeal decision","description":"Required scope: safety:write. One appeal for the current restrictive notice, at most five/day/principal. Repeated key replays; another key conflicts. Held principals may appeal; successful appeal never resumes workloads.","responses":{"202":{"description":"Accepted result; read current state separately after replays.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AppealAccepted"}}}},"default":{"description":"JSON error. 400/401/403/404/409/413/415/422/423/429/503; rate limits include Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","pattern":"^[a-zA-Z0-9_-]{1,100}$"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"properties":{"message":{"type":"string","minLength":20,"maxLength":2000}},"required":["message"]}}}}}},"/v1/appeals/{id}":{"get":{"operationId":"inspect_appeal","summary":"inspect appeal","description":"Required scope: safety:read. ","responses":{"200":{"description":"Accepted result; read current state separately after replays.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AppealStatus"}}}},"default":{"description":"JSON error. 400/401/403/404/409/413/415/422/423/429/503; rate limits include Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}]}},"/v1/admission":{"get":{"operationId":"inspect_admission","summary":"inspect admission","description":"Required scope: contact:read. Verification and operator approval are independent. Cohort caps persist, grants no funds or infrastructure. Revocation preserves policy even if the feature flag is disabled. Workload mutations require verification and approval under this policy.","responses":{"200":{"description":"Accepted result; read current state separately after replays.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AlphaAdmission"}}}},"default":{"description":"JSON error. 400/401/403/404/409/413/415/422/423/429/503; rate limits include Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/abuse/reports":{"post":{"operationId":"report_application","summary":"report application","description":"Anonymous, independent of execution mode; recovery fenced. 16 KiB. JSON rejects Cookie/Origin, no permissive CORS. HTML form at /abuse requires CSRF. Client-generated 256-bit key is digest-stored; exact replay returns receipt, changed body 409. Unknown/deleted targets accepted identically. No target existence or case state disclosed; no public lookup. Never fetches evidence, emails reporter or creates holds. Limits five/hour/actual peer and 100/hour globally.","responses":{"202":{"description":"Accepted result; read current state separately after replays.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AbuseReceipt"}}}},"default":{"description":"JSON error. 400/401/403/404/409/413/415/422/423/429/503; rate limits include Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"parameters":[{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","pattern":"^[a-f0-9]{64}$"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"properties":{"application_id":{"type":"string","format":"uuid"},"application_url":{"type":"string","maxLength":2048},"reason_code":{"enum":["phishing","malware","spam","harmful_content","other"]},"description":{"type":"string","minLength":20,"maxLength":4000},"reporter_email":{"type":"string","maxLength":254,"format":"email"},"evidence_urls":{"type":"array","maxItems":3,"items":{"type":"string","minLength":1,"maxLength":2048}}},"required":["reason_code","description"],"oneOf":[{"required":["application_id"],"not":{"required":["application_url"]}},{"required":["application_url"],"not":{"required":["application_id"]}}]}}}},"security":[]}},"/.well-known/euphoric-notification-keys.json":{"get":{"operationId":"notification_public_keys","summary":"notification public keys","description":"Public active Ed25519 verification key only; no arbitrary key selection or private material.","responses":{"200":{"description":"Accepted result; read current state separately after replays.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationKeys"}}}},"default":{"description":"JSON error. 400/401/403/404/409/413/415/422/423/429/503; rate limits include Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"security":[]}}},"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"eph_ followed by 64 lowercase hexadecimal characters, generated using a CSPRNG. Bootstrap grants applications:read, applications:write, operations:read, sandbox:credit, payments:read, and payments:write automatically. No public scope-management API exists. HTTP 403 insufficient_scope applies to credentials restricted by an operator or test; re-bootstrapping does not reset scopes. Existing stored credentials retain their previous scopes; use a fresh test principal for payments."}},"schemas":{"Bootstrap":{"type":"object","properties":{"principal_id":{"type":"string","format":"uuid"},"contact_status":{"type":"string","enum":["unverified","verified"],"description":"Bootstrap creates unverified contact and sends nothing. An exact saved replay retains its original status; GET /v1/contact shows current verification."},"sandbox":{"type":"boolean","description":"True only for simulated execution."},"next_action":{"$ref":"#/components/schemas/NextAction"},"environment":{"enum":["sandbox","staging"]},"billing_mode":{"const":"test"}},"required":["principal_id","contact_status","sandbox","next_action"]},"NextAction":{"type":"object","properties":{"type":{"type":"string"},"href":{"type":"string"}},"required":["type"]},"Balance":{"type":"object","properties":{"currency":{"const":"EUR"},"credited_minor":{"type":"integer"},"reserved_minor":{"type":"integer"},"available_minor":{"type":"integer"},"sandbox":{"type":"boolean","description":"True only for simulated execution."},"environment":{"enum":["sandbox","staging"]},"billing_mode":{"const":"test"}},"required":["currency","credited_minor","reserved_minor","available_minor","sandbox"]},"Application":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"state":{"enum":["requested","provisioning","ready","deleting","deleted","suspending","suspended"],"description":"Resource lifecycle; ready after successful provisioning. This is distinct from operation state."},"desired_state":{"enum":["running","deleted","suspended"]},"image":{"type":"string"},"generation":{"type":"integer"},"provider":{"enum":["sandbox","hetzner"]},"url":{"type":["string","null"],"description":"Null in the sandbox. Private staging publishes a URL only after readiness, edge reconciliation and trusted HTTPS verification."},"created_at":{"type":"string","format":"date-time"},"sandbox":{"type":"boolean","description":"True only for simulated execution."},"environment":{"enum":["sandbox","staging"]},"billing_mode":{"const":"test"},"slug":{"type":"string","description":"Globally unique immutable hostname label, retained after deletion."},"active_release":{"anyOf":[{"$ref":"#/components/schemas/Release"},{"type":"null"}]},"billing":{"anyOf":[{"$ref":"#/components/schemas/RuntimeBilling"},{"type":"null"}],"description":"Null for legacy fixed-reservation applications."},"operator_hold":{"type":"boolean","description":"An active operator hold fences new workload activity. Reads, supported configuration export and deletion remain available. Funding cannot release the hold."}},"required":["id","name","state","desired_state","image","generation","provider","url","created_at","sandbox","environment","billing_mode","slug","active_release","billing","operator_hold"]},"Accepted":{"type":"object","properties":{"application_id":{"type":"string","format":"uuid"},"operation_id":{"type":"string","format":"uuid"},"status_url":{"type":"string"},"phase":{"const":"queued"},"sandbox":{"type":"boolean","description":"True only for simulated execution."},"environment":{"enum":["sandbox","staging"]},"billing_mode":{"const":"test"}},"required":["application_id","operation_id","status_url","phase","sandbox"],"description":"HTTP 202 acknowledgement with phase queued and no state field. Poll status_url for the operation state; replaying the mutation returns this original acknowledgement."},"Event":{"type":"object","properties":{"phase":{"type":"string"},"message":{"type":"string"},"at":{"type":"string"}},"required":["phase","message","at"]},"Operation":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"application_id":{"type":"string","format":"uuid"},"kind":{"enum":["provision","export","delete","release","suspend","resume"]},"state":{"enum":["queued","running","succeeded","cancelled","failed"],"description":"Completion indicator: poll until succeeded, failed, or cancelled. Only succeeded indicates success."},"phase":{"type":"string","description":"Current progress step, such as allocating, checking, or ready. Successful provisioning has state succeeded and phase ready. Use state for completion."},"result":{"type":"object"},"error":{"type":["object","null"]},"sandbox":{"type":"boolean","description":"True only for simulated execution."},"events":{"type":"array","items":{"$ref":"#/components/schemas/Event"}},"environment":{"enum":["sandbox","staging"]},"billing_mode":{"const":"test"},"provider":{"enum":["sandbox","hetzner"]}},"required":["id","application_id","kind","state","phase","result","error","sandbox","events","environment","billing_mode"]},"ApplicationList":{"type":"object","properties":{"applications":{"type":"array","items":{"$ref":"#/components/schemas/Application"},"maxItems":50},"sandbox":{"type":"boolean","description":"True only for simulated execution."},"environment":{"enum":["sandbox","staging"]},"billing_mode":{"const":"test"}},"required":["applications","sandbox","environment","billing_mode"]},"Logs":{"type":"object","properties":{"sandbox":{"type":"boolean","description":"True only for simulated execution."},"source":{"enum":["operation_events","container"]},"lines":{"type":"array","maxItems":100,"items":{"type":"object","properties":{"at":{"type":"string"},"message":{"type":"string"},"stream":{"enum":["stdout","stderr"]}},"required":["at","message"]}},"environment":{"enum":["sandbox","staging"]},"billing_mode":{"const":"test"},"release_id":{"type":"string","format":"uuid"},"cursor":{"type":["string","null"]},"cursor_semantics":{"type":"string"}},"required":["sandbox","source","lines","environment","billing_mode"]},"Error":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"retryable":{"const":false},"details":{"type":"object"},"next_action":{"anyOf":[{"$ref":"#/components/schemas/NextAction"},{"type":"null"}]}},"required":["code","message","retryable","details","next_action"]},"request_id":{"type":"string"}},"required":["error","request_id"]},"Release":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"application_id":{"type":"string","format":"uuid"},"operation_id":{"type":"string","format":"uuid"},"image":{"type":"string"},"state":{"enum":["pending","starting","checking","publishing","active","retired","failed","cancelled"]},"active":{"type":"boolean"},"error":{"type":["object","null"]},"created_at":{"type":"string","format":"date-time"}},"required":["id","application_id","operation_id","image","state","active","error","created_at"]},"ReleaseList":{"type":"object","properties":{"releases":{"type":"array","maxItems":50,"items":{"$ref":"#/components/schemas/Release"}}},"required":["releases"]},"MeteredBalance":{"type":"object","properties":{"currency":{"const":"EUR"},"billing_mode":{"const":"test"},"credited_micro":{"type":"integer","minimum":0},"charged_micro":{"type":"integer","minimum":0},"balance_micro":{"type":"integer","minimum":0},"reserved_micro":{"type":"integer","minimum":0},"available_micro":{"type":"integer","minimum":0},"current_rate_micro_per_second":{"type":"integer","minimum":0},"estimated_runway_seconds":{"type":["integer","null"],"minimum":0},"as_of":{"type":"string","format":"date-time"},"estimate_basis":{"type":"string"},"sandbox":{"type":"boolean","description":"True only for simulated execution."},"environment":{"enum":["sandbox","staging"]},"grant_credited_micro":{"type":"integer","minimum":0,"description":"Non-financial EUR micro-units from this source."},"payment_credited_micro":{"type":"integer","minimum":0,"description":"Non-financial EUR micro-units from this source."}},"required":["currency","billing_mode","credited_micro","charged_micro","balance_micro","reserved_micro","available_micro","current_rate_micro_per_second","estimated_runway_seconds","as_of","estimate_basis","sandbox","environment"]},"RuntimeBilling":{"type":"object","properties":{"plan_id":{"const":"test-runtime-v1"},"currency":{"const":"EUR"},"billing_mode":{"const":"test"},"rate_micro_per_second":{"type":"integer","minimum":0},"spend_limit_micro":{"type":"integer","minimum":0},"charged_micro":{"type":"integer","minimum":0},"reserved_micro":{"type":"integer","minimum":0},"stop_at":{"type":["string","null"],"format":"date-time"},"started_at":{"type":["string","null"],"format":"date-time"},"metered_through":{"type":["string","null"],"format":"date-time"},"authorized_until":{"type":["string","null"],"format":"date-time"},"acknowledged_until":{"type":["string","null"],"format":"date-time"},"stopped_at":{"type":["string","null"],"format":"date-time"},"delete_after":{"type":["string","null"],"format":"date-time"},"suspension_reason":{"type":["string","null"]},"last_error":{"type":["string","null"]},"observed_through":{"type":["string","null"],"format":"date-time","description":"Latest confirmed runtime observation. Staging usage is not posted beyond this timestamp."}},"required":["plan_id","currency","billing_mode","rate_micro_per_second","spend_limit_micro","charged_micro","reserved_micro","stop_at","started_at","metered_through","authorized_until","acknowledged_until","stopped_at","delete_after","suspension_reason","last_error","observed_through"],"description":"Exact EUR micro-units (1000000 = EUR 1). Lifetime spend ceiling includes charged and reserved runtime. acknowledged_until is the last confirmed host deadline; authorized_until may still await delivery. Consumption is for allocated ready-instance time, not CPU utilization. Stopped runtime is not charged."},"BillingEvent":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"type":{"enum":["payment.credited","balance.low","application.suspended","application.deletion_scheduled"]},"application_id":{"type":["string","null"],"format":"uuid"},"data":{"type":"object","description":"Event snapshot: test grant amount/currency/source, or RuntimeBilling fields and optional threshold_seconds/estimated_runway_seconds."},"created_at":{"type":"string","format":"date-time"}},"required":["id","type","application_id","data","created_at"]},"BillingEventList":{"type":"object","properties":{"events":{"type":"array","items":{"$ref":"#/components/schemas/BillingEvent"},"maxItems":100},"next_before":{"type":["string","null"],"format":"uuid"},"sandbox":{"type":"boolean","description":"True only for simulated execution."},"environment":{"enum":["sandbox","staging"]},"billing_mode":{"const":"test"}},"required":["events","next_before","sandbox","environment","billing_mode"]},"TestPlan":{"type":"object","properties":{"id":{"const":"test-runtime-v1"},"version":{"const":1},"currency":{"const":"EUR"},"billing_mode":{"const":"test"},"rate_micro_per_second":{"const":10},"hourly_micro":{"const":36000},"daily_micro":{"const":864000},"minimum_start_seconds":{"const":300},"authorization_window_seconds":{"const":86400},"renewal_interval_seconds":{"const":300},"retention_seconds":{"const":259200},"billing_starts":{"const":"instance_ready"},"included":{"type":"string"},"description":{"type":"string"}},"required":["id","version","currency","billing_mode","rate_micro_per_second","hourly_micro","daily_micro","minimum_start_seconds","authorization_window_seconds","renewal_interval_seconds","retention_seconds","billing_starts","included","description"]},"PlanList":{"type":"object","properties":{"plans":{"type":"array","items":{"$ref":"#/components/schemas/TestPlan"}},"sandbox":{"type":"boolean","description":"True only for simulated execution."},"environment":{"enum":["sandbox","staging"]},"billing_mode":{"const":"test"}},"required":["plans","sandbox","environment","billing_mode"]},"PaymentOrder":{"type":"object","required":["id","state","status_url","amount_minor","currency","credit_micro","billing_mode","adapter","livemode","expires_at","credited_transaction_id","review_reason","error","last_checked_at","next_attempt_at","consecutive_failures","next_action","payment_method"],"properties":{"id":{"type":"string","format":"uuid"},"state":{"type":"string","enum":["created","creating","requires_payment","reconciling","credited","expired","failed","needs_review"]},"status_url":{"type":"string"},"amount_minor":{"type":"integer","minimum":100,"maximum":3000},"currency":{"const":"EUR"},"credit_micro":{"type":"integer"},"billing_mode":{"const":"test"},"adapter":{"enum":["fake","stripe_test"]},"livemode":{"const":false},"expires_at":{"type":"string","format":"date-time"},"credited_transaction_id":{"type":["string","null"],"format":"uuid"},"review_reason":{"type":["string","null"]},"error":{"type":["string","null"]},"last_checked_at":{"type":["string","null"],"format":"date-time"},"next_attempt_at":{"type":["string","null"],"format":"date-time"},"consecutive_failures":{"type":"integer"},"next_action":{"type":["object","null"],"additionalProperties":true},"payment_method":{"enum":["stripe_checkout","stripe_spt"]},"receipt":{"$ref":"#/components/schemas/PaymentReceipt","description":"Only present on credited SPT orders. Remains historical credit evidence when a later refund/dispute review flag exists."}}},"PaymentAccepted":{"type":"object","required":["id","status_url","billing_mode"],"properties":{"id":{"type":"string","format":"uuid"},"status_url":{"type":"string"},"billing_mode":{"const":"test"},"payment_status":{"const":"pending","description":"SPT acceptance only; inspect the order for the current state."},"next_action":{"const":"poll_order","description":"SPT only. GET status_url with bearer authentication until credited and receipt, or retain identity for operator review."}}},"PaymentReceipt":{"type":"object","required":["method","reference","status","timestamp","externalId"],"properties":{"method":{"const":"stripe"},"reference":{"type":"string","description":"Canonical PaymentIntent ID"},"status":{"const":"success"},"timestamp":{"type":"string","format":"date-time"},"externalId":{"type":"string","format":"uuid","description":"Owned Euphoric payment order ID"}},"additionalProperties":false},"ContactDelivery":{"type":"object","additionalProperties":false,"properties":{"id":{"type":"string","format":"uuid"},"kind":{"type":"string"},"state":{"type":"string","enum":["pending","sending","accepted_by_transport","blocked","failed","cancelled"]},"attempts":{"type":"integer","minimum":0},"last_error":{"type":["string","null"]},"next_run_at":{"type":["string","null"],"format":"date-time"},"version":{"type":"integer"},"created_at":{"type":["string","null"],"format":"date-time"}},"required":["id","kind","state","attempts","last_error","next_run_at","version","created_at"]},"ContactStatus":{"type":"object","additionalProperties":false,"properties":{"channel":{"enum":["email","callback"]},"masked_destination":{"type":"string"},"status":{"enum":["unverified","verified"]},"verified_at":{"type":["string","null"],"format":"date-time"},"challenge_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}]},"expires_at":{"type":["string","null"],"format":"date-time"},"delivery":{"anyOf":[{"$ref":"#/components/schemas/ContactDelivery"},{"type":"null"}]},"next_action":{"type":"string"}},"required":["channel","masked_destination","status","verified_at","challenge_id","expires_at","delivery","next_action"]},"ContactAccepted":{"type":"object","additionalProperties":false,"properties":{"challenge_id":{"type":"string","format":"uuid"},"expires_at":{"type":["string","null"],"format":"date-time"},"delivery_state":{"type":"string"},"confirmation_path":{"type":"string"}},"required":["challenge_id","expires_at","delivery_state","confirmation_path"]},"ContactConfirmed":{"type":"object","additionalProperties":false,"properties":{"contact_status":{"const":"verified"},"verified_at":{"type":["string","null"],"format":"date-time"}},"required":["contact_status","verified_at"]},"SafetyNotice":{"type":"object","additionalProperties":false,"properties":{"id":{"type":"string","format":"uuid"},"case_id":{"type":"string","format":"uuid"},"reason_code":{"enum":["no_action","needs_information","quarantine","uphold","overturn"]},"created_at":{"type":["string","null"],"format":"date-time"},"content":{"type":"object","properties":{"summary":{"type":"string"},"unavailable":{"type":"string"}}},"delivery":{"$ref":"#/components/schemas/ContactDelivery"},"hold":{"anyOf":[{"type":"object","additionalProperties":false,"properties":{"id":{"type":"string","format":"uuid"},"state":{"type":"string"}},"required":["id","state"]},{"type":"null"}]},"next_action":{"type":"string"}},"required":["id","case_id","reason_code","created_at","content","delivery","hold","next_action"]},"SafetyNoticePage":{"type":"object","additionalProperties":false,"properties":{"notices":{"type":"array","items":{"$ref":"#/components/schemas/SafetyNotice"},"maxItems":50},"next_cursor":{"type":["string","null"]}},"required":["notices","next_cursor"]},"AppealAccepted":{"type":"object","additionalProperties":false,"properties":{"appeal_id":{"type":"string","format":"uuid"},"state":{"enum":["pending","resolved"]}},"required":["appeal_id","state"]},"AppealStatus":{"type":"object","additionalProperties":false,"properties":{"appeal_id":{"type":"string","format":"uuid"},"notice_id":{"type":"string","format":"uuid"},"state":{"enum":["pending","resolved"]},"outcome":{"anyOf":[{"$ref":"#/components/schemas/SafetyNotice"},{"type":"null"}]}},"required":["appeal_id","notice_id","state","outcome"]},"AlphaAdmission":{"type":"object","additionalProperties":false,"properties":{"required":{"type":"boolean"},"state":{"enum":["pending","approved","revoked"]},"admission_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}]},"version":{"type":"integer","minimum":0},"contact_status":{"type":"string"},"used":{"type":"integer"},"maximum":{"type":["integer","null"]},"cohort_used":{"type":["integer","null"]},"cohort_maximum":{"type":["integer","null"]},"next_action":{"type":"string"}},"required":["required","state","admission_id","version","contact_status","used","maximum","cohort_used","cohort_maximum","next_action"]},"AbuseReceipt":{"type":"object","additionalProperties":false,"properties":{"receipt":{"type":"string","pattern":"^[a-f0-9]{32}$"},"message":{"type":"string"}},"required":["receipt","message"]},"NotificationKeys":{"type":"object","additionalProperties":false,"properties":{"keys":{"type":"array","items":{"type":"object","additionalProperties":false,"properties":{"id":{"type":"string"},"algorithm":{"const":"Ed25519"},"public_key_pem":{"type":"string"}},"required":["id","algorithm","public_key_pem"]}}},"required":["keys"]}}}}