| name | zoneless-marketplace |
| description | Adds Zoneless Cloud as an optional USDC marketplace payout method while preserving existing checkout and payout providers. Use when integrating seller onboarding, connected accounts, transfers, payouts, or migrating payout infrastructure to Zoneless. |
Add Zoneless marketplace payouts
Add Zoneless as a separate payout provider. Do not replace checkout or remove an
existing Stripe, PayPal, Payoneer, wire-transfer, or custom payout path unless
the human explicitly asks for that additional work.
Safety requirements
- Never request, read, print, export, transmit, or commit an API key, wallet
private key, seed phrase, or secret-manager value.
wallet backup is a human-run command. At handoff, tell the human to run it
in an interactive terminal and keep the resulting file somewhere private.
- Work in the test profile. Do not create live-mode application data, fund a
wallet, submit a transaction, broadcast a payout, or switch production
traffic.
- Keep all secret-key handling server-side. Never add it to browser code,
public environment files, logs, fixtures, or test snapshots.
- Preserve existing checkout, payout providers, credentials, routes, jobs,
webhooks, seller preferences, and historical provider IDs.
- Stop before a destructive schema change or an ambiguous money movement.
Ask the human rather than guessing.
Assume no crypto knowledge
Use plain language whenever the human must act. Briefly explain that USDC is a
digital dollar, Solana is the network carrying it, SOL pays the small network
fee, a wallet address is safe to share, and a wallet secret key authorizes
spending and must remain private. Explain that test mode uses fake USDC so they
can onboard sellers and run payouts without a wallet, a faucet, or the live
Solana network. Live mode is when real USDC moves on Solana. Do not use terms
such as gas, mint, token account, cluster, or airdrop without explaining them.
Give concrete instructions: distinguish test funds from real funds. Never
assume prior wallet or blockchain experience.
Read documentation just in time
Start with https://zoneless.com/docs/api-quickstart.md. Use
https://zoneless.com/llms.txt as an index and read a resource page only when
implementing that resource or when blocked. Do not fetch the entire docs set
upfront.
For most integrations, the additional pages needed are connected accounts,
account links, transfers, payouts, and webhooks. Read build and broadcast only
when using the explicit payout-ID workflow described below.
Confirm the local setup
Run:
npx @zoneless/cli@latest doctor --json
If no profile exists, run the setup command with a platform name inferred from
the project:
npx @zoneless/cli@latest agent setup \
--platform-name "<marketplace name>" \
--skill marketplace \
--json
If setup reports that profiles already exist for a different platform, rerun
the same command with --new-platform. Reuse profiles that already belong to
this marketplace; do not create duplicates.
Show the returned verification_url and user_code, then wait. Do not approve
the request for the human. Setup stores test and live credentials in the
operating-system credential store without printing them and binds this
repository to those profiles in .zoneless/project.json. Continue with the
bound test profile after approval.
Setup validates stored keys before reusing them. If it reports
credentials_invalid, run:
npx @zoneless/cli@latest auth reconnect --json
Show the new authorization prompt to the human, then retry setup after
reconnection.
For local test execution, inject the bound test credentials into the project's
local env file without displaying or reading them:
npx @zoneless/cli@latest env sync --include-wallet --json
If the command reports multiple environment files, infer the server's actual
env file from its scripts and framework, then rerun once with
--target <relative-path>. Do not print the file or return its values. The
command preserves unrelated variables, ignores the target in Git, and writes
owner-only permissions. For deployment, add only environment variable names
and secret-manager references; the human supplies live values during handoff.
Configure test webhook delivery when used
If the integration implements a Zoneless webhook route, determine its public
HTTPS URL. For localhost, explain that Zoneless cannot reach localhost; the
human must run a tunnel such as ngrok http <port> or Cloudflare Tunnel and
provide its public URL. Do not silently install or leave a tunnel running.
Before handoff, ask for that URL so you can complete webhook sync. If the human
cannot provide one, distinguish application code complete from webhook
delivery pending and include the exact command they must run later.
For the standard marketplace flow, sync the onboarding, transfer, and payout
events without displaying the signing secret:
npx @zoneless/cli@latest webhook sync \
--url "https://<public-host>/<server-webhook-route>" \
--events "account.updated,transfer.created,payout.paid,payout.failed" \
--json
Add --target <relative-path> when the server uses a non-default env file.
webhook sync replaces the managed endpoint's event list, so if the application
already handles other Zoneless events, pass the union of its existing events
and the marketplace events it needs. Restart the application afterward so it
loads ZONELESS_WEBHOOK_SECRET.
If the implementation intentionally retrieves account and payout status instead
of using webhooks, do not create an unused endpoint or require
ZONELESS_WEBHOOK_SECRET.
Use test mode, then hand off live promotion
Setup provisions both test and live profiles and makes test the current CLI
profile. Implement and verify against https://api-test.zoneless.com; do not
ask the human to choose live mode during the migration.
Keep mode environment-driven rather than hardcoded. At handoff, explain that
going live means configuring the separately provisioned live API key and
https://api.zoneless.com in the deployment secret manager, configuring the
live webhook secret, funding the live platform wallet, and completing one
human-supervised payout before enabling live traffic.
Classify before editing
Inspect checkout separately from payouts, then choose the matching path:
- Existing payout ledger: seller earnings already accrue in a balance and
an existing job or withdrawal flow pays them. Stripe separate charges and
transfers usually belong here when the platform charges first and transfers
to the seller later. Add Zoneless as another branch in that flow.
- Immediate seller payment at checkout: Stripe destination charges, direct
charges, PayPal split payments, or similar pay the seller as part of the
sale. Preserve that behavior for existing providers. For a seller who opts
into Zoneless, collect the charge on the platform instead, record only that
seller's net earnings, and pay those earnings once through Zoneless. Pin the
provider on each sale so it cannot be paid twice.
- Small or file-backed app: no real database, job queue, withdrawal model,
or webhook infrastructure. Add the smallest coherent implementation using
the existing storage and process model. Do not introduce authentication,
cross-process locks, queues, schedulers, reconciliation systems, or new
architectural layers unless the app already needs them.
Also identify the backend runtime, seller model, existing provider IDs and
preferences, test framework, deployment conventions, and secret handling. If
the money flow is unclear, stop and ask before editing. Do not redesign
unrelated parts of the application.
Choose the integration client
JavaScript or TypeScript backend
Install @zoneless/node with the project's package manager. Create one
server-side Zoneless client in the existing payments/integrations layer using:
ZONELESS_API_KEY
ZONELESS_API_URL, using https://api-test.zoneless.com during integration
SOLANA_SECRET_KEY only in the server-side payout processor
ZONELESS_WEBHOOK_SECRET only when the app implements a webhook route
Use the SDK for accounts, account links, transfers, payouts, and webhook
verification.
Use the payout helper that matches the existing worker:
payouts.processAll(SOLANA_SECRET_KEY) when the worker intentionally
processes every pending platform payout;
payouts.processBatch(SOLANA_SECRET_KEY) for one platform-wide batch of up
to 10 pending payouts;
payouts.build({ payouts: [payoutId] }), payouts.sign(...), then
payouts.broadcast(...) when the marketplace must process an explicitly
claimed payout ID.
The SDK already builds and signs Solana transactions. In simulated test mode
it passes dummy sim_tx payloads through without signing. Do not install
@solana/web3.js, @solana/spl-token, bs58, or add mint, cluster, RPC, token
account, or platform-account configuration to a Node application. Those are
Zoneless implementation details. The marketplace app needs only the relevant
environment variables listed above.
Other backend runtimes
Use the project's existing HTTP client and create one small Zoneless adapter.
Do not add Node as an application runtime dependency.
The adapter must:
- require an explicit
ZONELESS_API_URL and normalize it to exactly one /v1
suffix;
- use
https://api-test.zoneless.com with the test profile during integration;
- authenticate with
X-Api-Key;
- send
Idempotency-Key for every mutating request;
- send
Zoneless-Account: acct_z_... for connected-account requests;
- preserve structured API errors and request IDs;
- set timeouts and use the project's retry conventions;
- never retry a mutating request with a new idempotency key.
For payouts, call /v1/payouts/build, sign the returned transaction with a
maintained Solana signer for that backend language, then call
/v1/payouts/broadcast. Confirm the build response contains the payout IDs and
total expected by the claimed marketplace operation. Do not invent mint,
cluster, token-account, or RPC configuration; Zoneless builds the transaction.
If the runtime cannot sign it, stop and ask before adding a sidecar or changing
runtimes.
Match the existing payout trigger
Do not invent a universal payout schedule. Preserve the marketplace's existing
trigger and choose the matching Zoneless processor:
- Scheduled platform payout: create transfers as earnings become eligible,
create pending payouts in the existing daily/weekly worker, then use
processAll() when that worker owns every pending Zoneless payout.
- Bounded worker batch: use
processBatch() when the existing worker
deliberately processes one platform-wide batch of up to 10.
- Seller claim or admin-selected payout: reserve the claimed earnings,
create one transfer and payout, then process that payout ID with
build/sign/broadcast.
- Manual payout: create the transfer and pending payout in the existing
admin flow, but leave transaction processing to the existing manual worker.
Do not add both a claim route and a scheduler unless the application already
supports both. Keep the existing eligibility thresholds, timing, and
withdrawal rules.
Implement the additive payout path
Follow the project's architecture, but preserve these invariants:
-
Provider state
- Add
zoneless as a distinct payout-method value.
- Store a separate connected account ID such as
zonelessAccountId.
- Keep account ID, onboarding completion, current
payouts_enabled, and the
seller's active preference separate.
- Pin the provider on each sale or payout attempt. A preference change
affects future sales or unclaimed earnings only.
- Reuse the existing payout model. For a small app with none, add only the
fields needed to prevent duplicate payment: provider, amount, status,
transfer ID, payout ID, idempotency key, and timestamps. Use the app's
existing persistence style and a short
pending → processing →
paid/failed flow.
-
Seller opt-in and onboarding
- Add Zoneless to the existing payout-method selection UI.
- Create and persist one Express connected account, then create an Account
Link for onboarding. Use a Login Link for an existing seller's dashboard.
- Treat
payouts_enabled, retrieved from Zoneless or received in a verified
account.updated webhook, as the capability truth. A return redirect alone
does not prove onboarding completed.
- Validate preference changes on the server and preserve all existing
provider accounts so the seller can switch back.
-
Earnings and transfers
- Reuse the marketplace ledger and worker if they exist.
- For immediate-payment checkout, keep destination charges unchanged for
Stripe sellers. For a Zoneless seller, omit the destination transfer,
collect on the platform, and record the seller's net earnings only after
payment succeeds.
- Reserve each earning or sale once and pin it to one provider before calling
Zoneless. Never pay the same sale through both the checkout provider and
Zoneless.
- Create a transfer to the connected account, then create its payout. Use a
stable idempotency key for each operation and reuse it on retry.
-
Payout creation and processing
- Create the payout on behalf of the connected account using the
Zoneless-Account context; destination is an optional external wallet
ID, not the connected account ID.
- Process it with the Node SDK helper or explicit-ID flow chosen above.
Remember that
processAll() and processBatch() select pending payouts
platform-wide; use explicit // when the worker must
process one claimed payout.
Verify
Use mocks or test credentials; never send a payout. Add tests for:
- the existing checkout and payout path remaining unchanged;
- seller opt-in, account reuse, and provider switching;
- one sale or earning never being paid through two providers;
- the Zoneless transfer/payout path using the connected-account context and
stable idempotency keys;
- no secret values reaching browser code, logs, fixtures, or snapshots.
For destination-charge marketplaces, explicitly test that Stripe sellers still
use the destination charge and Zoneless sellers do not.
Run the project's formatter, focused tests, linter, type checker, and build.
Fix regressions introduced by the integration.
Human handoff
Report:
- changed files and the existing abstractions reused;
- database migration and deployment commands;
- required environment-variable names, never values;
- tests run and any unverified behavior;
- the test-mode onboarding path;
- that a test payout still uses the live two-step flow: create stays
pending, then
processAll / build and broadcast marks it paid with
simulated USDC. No wallet, faucet, or Devnet is required — broadcast
the unsigned dummy transaction. Use Add test USDC
on the dashboard Balance page (or
POST /v1/test_helpers/treasury/topups) if the platform ledger needs a
balance first;
- where the human must configure the API key and webhook secret;
- the exact live-mode promotion sequence, including the bound live profile
name,
https://api.zoneless.com, deployment secret changes, live webhook
setup, wallet funding, and one supervised payout;
- that setup created a platform wallet and, before enabling live payouts, the
human should run
npx @zoneless/cli@latest wallet backup --profile <live-profile> --output <private-path>
in an interactive terminal and keep the resulting file somewhere private;
when the deployed payout worker needs wallet signing, they should use its
secretKeyBase58 value as SOLANA_SECRET_KEY in the deployment secret
manager;
- that the human must follow
https://zoneless.com/docs/fund-platform-wallet.md to fund the platform
wallet with enough USDC for seller payouts and a small amount of SOL for
Solana network fees;
- that the human must explicitly approve any live rollout.
Do not claim the integration is production-ready until the human completes
secret provisioning, wallet funding, live webhook setup, and a supervised
end-to-end payout.