API REFERENCE
Stripe Connect sandbox
V2 host onboarding, platform products and destination-charge Checkout.
Open the sample
Go to the host marketplace sandbox and use your existing ComputerUse account. Its onboarding, product form and storefront share the site's normal sign-in session. This is a sandbox: purchases record a test order and never reserve a physical host, create a rental, issue desktop access or add live prepaid credit.
SDK and source
The commented implementation is in computeruse/connect_sample.py; the HTML and browser code are in public/connect-demo/. The sample uses StripeClient for every API request. The verified latest stable stripe-python release is 15.6.1. It automatically selects 2026-08-26.dahlia; no version override is set. V2 requests use stripeClient.v2.core; platform products and Checkout use stripeClient.v1.
Install the application dependencies before running the backend:
python3 -m venv .venv
.venv/bin/pip install -r deploy/requirements.txt
The existing HTTPS WSGI deployment is the supported way to try this with browser sessions. The Sites copy publishes static pages; payment APIs run on computeruse.space.
Required server settings
Use the private server runtime environment at /etc/computeruse-space/runtime.env. Never put a secret key or signing secret in HTML, Git, an API request from the browser, or a product description.
# PLACEHOLDER: secret API key from the intended Stripe sandbox (sk_test_...).
COMPUTERUSE_CONNECT_SANDBOX_KEY=
# PLACEHOLDER: signing secret for the connected-account THIN event destination.
COMPUTERUSE_CONNECT_SANDBOX_THIN_SECRET=
# PLACEHOLDER: signing secret for the platform Checkout SNAPSHOT event destination.
COMPUTERUSE_CONNECT_SANDBOX_PAYMENT_SECRET=
After saving, recreate only the web application container to load the environment. A missing key produces a named configuration error. Live keys are rejected by the sample. Onboarding can run once the sandbox key is set; Checkout requires both event signing secrets. Stripe-hosted Checkout does not need a publishable key in the browser.
Use one Stripe sandbox consistently. Changing to another sandbox without migrating its stored account/product/order mappings causes identity checks to fail. A signing secret from a CLI listener is different from a Dashboard destination's signing secret; use the value belonging to the receiver you are actually testing.
1. Create and onboard a connected host
The signed-in user enters a public display name. The server uses their account email and creates an Accounts V2 account with exactly these settings:
account = stripeClient.v2.core.accounts.create({
'display_name': display_name, # From the signed-in host's form.
'contact_email': user_email, # From the authenticated user record.
'identity': {'country': 'us'}, # This sample demonstrates US hosts.
'dashboard': 'express',
'defaults': {'responsibilities': {
'fees_collector': 'application',
'losses_collector': 'application',
}},
'configuration': {'recipient': {'capabilities': {
'stripe_balance': {'stripe_transfers': {'requested': True}},
}}},
}, options={'idempotency_key': persisted_operation_id})
There is no top-level type. The database stores the mapping from ComputerUse user ID to Stripe account ID and the persisted request identity. A browser cannot nominate someone else's connected account. The sample does not collect bank details itself.
The Onboard to collect payments button uses V2 Account Links with the account_onboarding use case and recipient configuration. Stripe returns to the sample page. An expired link also returns there; press the button again to obtain a fresh link for the same account. A return URL never proves onboarding succeeded.
2. Read status directly from Stripe
Every status refresh retrieves the mapped account using include=['configuration.recipient', 'requirements']. Transfers are ready when configuration.recipient.capabilities.stripe_balance.stripe_transfers.status is active. Onboarding is complete when returned requirements are neither currently_due nor past_due. Unknown or missing included requirements cannot enable purchases. The application does not persist an onboarding-complete flag or requirements snapshot.
US is the sample country, not a promise of worldwide payout eligibility. Hosts in Vietnam and other countries require a supported Connect arrangement before a live rollout.
3. Configure thin account events
In the sandbox Stripe Dashboard, open Developers → Webhooks → Add destination. Choose Your account, show advanced options, and select Thin payloads. Accounts V2 objects representing hosts belong to the platform, so their thin events use events_from=["@self"]. The Connected accounts scope is for events from resources inside connected accounts and legacy snapshot account updates; it does not deliver these Accounts V2 thin events. Subscribe to the exact event names:
v2.core.account[requirements].updated
v2.core.account[configuration.recipient].capability_status_updated
Use this HTTPS receiver:
https://computeruse.space/api/v1/connect-demo/thin-webhook
Save its signing secret in COMPUTERUSE_CONNECT_SANDBOX_THIN_SECRET. Python's current SDK method stripeClient.parse_event_notification(raw_body, signature, secret) is the equivalent of the JavaScript thin-event parser. It verifies the unmodified request body, then the application retrieves the full event with stripeClient.v2.core.events.retrieve. The handlers fetch current requirements/capabilities for the known mapped account and record the event receipt. Account status itself is not saved in the database. Duplicate deliveries are safe; invalid signatures and live events are rejected.
For a separate local test receiver, log Stripe CLI into the intended sandbox and run:
stripe listen --thin-events 'v2.core.account[requirements].updated,v2.core.account[configuration.recipient].capability_status_updated' --forward-thin-to http://localhost:8080/api/v1/connect-demo/thin-webhook
Use an appropriately configured local receiver; the stock production WSGI host guard expects its configured HTTPS host. The exact recipient event name includes configuration.recipient.
4. Create products and browse all hosts
The product form creates a platform-level Stripe Product with a default one-time USD Price. There is no connected-account request header. Both product metadata and SQLite map the product to its connected host. The storefront displays every host and product created in this sample, including hosts still onboarding. Contact emails, bank details and unrelated Stripe products/accounts are not exposed.
Prices are entered in USD and converted to integer cents. Product creation and checkout require a unique Idempotency-Key; reuse the same key when retrying a lost response. Persisted parameters prevent a retry from creating another account, product or Checkout Session. An unresolved operation older than 23 hours requires provider reconciliation before retrying.
5. Charge the customer and split 50/50
The customer selects a product and quantity. The server retrieves the current Stripe Price, verifies the product-to-host mapping and active transfer capability, and computes the fee. Neither a client-submitted amount nor a destination ID controls the charge.
session = stripeClient.v1.checkout.sessions.create({
'line_items': [{'price': verified_price_id, 'quantity': quantity}],
'mode': 'payment',
'payment_intent_data': {
'application_fee_amount': total_in_cents // 2,
'transfer_data': {'destination': mapped_connected_account_id},
},
'success_url': site_origin + '/connect-demo/?session_id={CHECKOUT_SESSION_ID}',
}, options={'idempotency_key': persisted_order_id})
A $40 order gives the host $20 and ComputerUse a $20 application fee, before Stripe processing fees. With destination charges, those fees reduce the platform share. For an odd-cent order, the extra cent goes to the host. A transfer into a host's Stripe balance and a payout to their bank are separate stages with Stripe's applicable availability and payout schedule.
One destination-charge Checkout Session has one host recipient. Multiple products or computers from the same host can share a checkout. Mixed-host carts are rejected with an explanation to check out separately for each host. The current UI buys one product with a quantity; the API also accepts several products from one host.
6. Verify payment through the payment webhook
Create a second sandbox platform destination using Snapshot payloads for:
checkout.session.completed
checkout.session.async_payment_succeeded
checkout.session.async_payment_failed
checkout.session.expired
Use https://computeruse.space/api/v1/connect-demo/payment-webhook and save its signing secret as COMPUTERUSE_CONNECT_SANDBOX_PAYMENT_SECRET. For a local receiver:
stripe listen --events checkout.session.completed,checkout.session.async_payment_succeeded,checkout.session.async_payment_failed,checkout.session.expired --forward-to http://localhost:8080/api/v1/connect-demo/payment-webhook
The receiver verifies the signature, retrieves the current Checkout Session and PaymentIntent through StripeClient, and checks sandbox mode, ownership, amount, currency, destination and fee. Only a verified paid result marks the sample order paid. Duplicate or delayed events do not create a second order or reverse a paid status. Visiting the success page only reads status; it cannot fulfill an order. The sample accepts card payments; the asynchronous handlers are present for future method expansion.
API routes
All customer/host routes below require an authenticated ComputerUse browser session. Browser requests use the site's existing CSRF protections. Ordinary agent API keys cannot manage this sample.
| Method | Route | Purpose |
|---|---|---|
| GET | /api/v1/connect-demo/status | Configuration and current host onboarding status |
| POST | /api/v1/connect-demo/onboard | Create/reuse own V2 account and create an Account Link |
| POST | /api/v1/connect-demo/products | Create an own-host platform product |
| GET | /api/v1/connect-demo/storefront | All sample products and connected hosts |
| POST | /api/v1/connect-demo/checkout | Hosted Checkout; items have product_id and quantity |
| POST | /api/v1/connect-demo/order | Read own returned session_id and verified order state |
| POST | /api/v1/connect-demo/thin-webhook | Signed Accounts V2 thin events |
| POST | /api/v1/connect-demo/payment-webhook | Signed platform Checkout snapshot events |
Verification and live launch boundary
Automated tests cover the installed SDK's V2 JSON and V1 encoding, mapping ownership, direct status reads, durable idempotency, integer price/fee calculations, signed thin/snapshot events, duplicate payments, wrong destinations, invalid signatures and unchanged real rental/credit tables. Run .venv/bin/python -m unittest discover -s tests -v after installing dependencies.
The sandbox API key and both event destinations are now configured on the server. Actual application requests created a V2 test host, an Account Link and the 8 GB/16 GB sample products. The test host still needs to finish Stripe-hosted onboarding before its products can be purchased. Stripe restricts API writes to identity fields after Account Link onboarding starts; complete those fields through the hosted form. A completed hosted Checkout and its destination transfer have not yet been verified. Use Stripe's test payment details in sandbox only. Before adapting this to live rentals, implement a capacity hold, verified fresh-desktop fulfillment, failure refunds, cancellation handling, transfer/application-fee reversals, disputes and host-country eligibility. Keep the sandbox/live mappings separate. The pre-existing prepaid ledger does not automatically become a destination-charge order system.
References: Accounts V2 object, thin webhook scope, destination charges, Stripe CLI listen.