Checkout Setup
publish: true create keeps the link as a draft with a publishError.Everything that has to be in place before you accept your first payment, in the order it happens: a business account, card payments switched on, an API key with a webhook endpoint, and the API itself. The first three are set up in the dashboard. The fourth is your integration.
Checkout is money arriving. It shares one organization, one API key, one webhook endpoint and one event feed with payouts, so if your organization already pays out, steps 1 and 3 are done and you can start at step 2.
With a test key you can skip steps 1 and 2 entirely. An avvio_test_… key addresses your sandbox organization, which is provisioned already verified and already able to sell by card, and a simulated buyer pays the link for you. Do the whole integration there first and come back to this page when you are ready to take real money. Sandbox is the reference.
1. Create a business account#
Go to business.avvio.xyz and sign in with your work email. You get a one-time code; after the first sign-in you can add a passkey, which is the fastest way back in. Then name your business and choose Create Business Account. That creates your organization: the thing that holds the balance, the links, the API keys and the team.
The dashboard home shows the setup steps in order: Create account, Verify your account, Fund your account, Add members. Checkout needs the first two. Funding is for paying out and is not required to be paid.
Verify the business#
Open Verify and complete business verification (KYB) once. It asks for the legal entity, its beneficial owners, and one control person: the individual who runs the business. Mark that person clearly. Card onboarding in step 2 verifies exactly that person, and cannot start until the application names one.
| Status | What it means |
|---|---|
| Draft | Not sent yet. Finish and submit it |
| Under review | With us. We email you when it is done |
| Needs information | We asked for something. The dashboard shows what, and a button to answer |
| Approved | Every organization-scoped route opens, including checkout |
| Rejected | Contact support |
Checkout routes answer 403 until the organization is verified, with the message *"This organization must complete business verification before it can accept payments."* Verification counts when either our review approves it or the card processor reports the business able to charge (step 2), so a card application that clears first also opens the door. Links, bank transfer and stablecoin payments go live as soon as verification is approved; cards are a separate application.
2. Enable card payments in checkout#
Open Checkout in the sidebar and choose Accept card payments. Anyone on your team can file the application. Only the control person does the identity check, and only if one is needed.
What you agree to. Cards are processed by Whop, and Whop verifies the control person your KYB names. The consent screen lists exactly what is shared: the business's registered name, address, tax ID, structure and what it does; the control person's name, date of birth, phone, home address and tax identification number; and photos of their government ID and a selfie. Read it and tick the two boxes. If you are not the control person, you attest that you are authorized to consent on their behalf. Consent is recorded once and not asked for again.
What happens next. The application is filed from the details already on your verification, so there is usually nothing to upload again. The card account opens in about a minute. Then one of two things:
Filed from documents. The ID photos and selfie on your verification were acceptable, and the identity check runs from them. Nobody is contacted.
Hosted check. Something is missing or not accepted (the page says what, and how to fix it on your verification). The control person photographs an ID and takes a selfie on their phone; about two minutes. The dashboard shows the link to send them, and Whop emails the account owner about it too.
The panel tells you where the application stands the whole time, and the two switches that come out of it are separate:
| Switch | Turns on when | What it lets you do |
|---|---|---|
| Card payments | The card account is open | Publish links with methods: [{ "kind": "card" }]; buyers pay by card, Apple Pay and Google Pay |
| Withdrawals | The identity check passes | Move card money to your bank from Checkout → Balance |
You can take card payments before withdrawals are on; the money waits in your card balance. Buyers see WHOP* followed by your business name on their statement, and you can edit the descriptor from the same panel.
If you publish a card link before this is done, the create call still answers 201 with the link kept as a draft and a publishError reading *"This business is not set up to accept cards yet. Finish card onboarding, then publish the link."* Finish here, then POST /checkout/organizations/{orgId}/links/{linkId}/publish. Bank and crypto links do not need this step at all.
Cards are in pilot and opening to verified businesses a few at a time. If the Accept card payments button is not there yet, the panel says so.
3. Create a webhook endpoint and an API key#
Both live under Developers in the sidebar. Owners, admins and operators can open it.
The API key#
Choose Create API key and fill in four things:
| Field | Pick |
|---|---|
| Name | Where it will live (orders-service), so a leaked key is traceable |
| Permission | Transact to create products and links. Read-only can list links and payments and reconcile, and gets 403 INSUFFICIENT_SCOPE on any write |
| Expiry | One year by default, two at most. The key stops on its own |
| Allowed IP addresses | Optional. Your servers' egress addresses; requests from anywhere else are refused |
The complete key is shown once. Copy it into your secrets vault or an environment variable then; we store only a hash. Never put it in a browser bundle, a mobile app, a screenshot or a support ticket. If it leaks, revoke it and issue a successor from the same page; the successor works before the old one stops. Authentication has the rest.
export AVVIO_API_KEY=avvio_…
export AVVIO_ORG_ID=cmsx… # your organization id, a cuid
export AVVIO_BASE_URL=https://api.avvio.xyz/business/api/v1Your organization id is on the same page. It is the opaque cmsx… value, not an org_-prefixed alias, and it goes unchanged into every path.
The webhook endpoint#
Switch to the Webhooks tab and choose Add endpoint:
- URL: https only. Plain
http://localhostis accepted only against a
local development backend.
- Events: the payout types are pre-selected; the checkout family is
not. Tick the ones you want: checkout_payment.paid, checkout_payment.failed, checkout_payment.refunded, checkout_payment.reversed. An endpoint that never named them never receives them, so a receiver built for payouts is not surprised by a family it does not handle.
- Signing secret: shown once, as
whsec_…. Copy it beside the API key.
Every delivery is signed with it; Webhooks shows the four headers and the two lines of verification.
Registering, pausing, rotating and replaying an endpoint are dashboard actions and cannot be done with an API key: a credential that could repoint its own webhook URL could quietly redirect every payment notification you receive. GET /organizations/{organizationId}/webhook-endpoints lists them read-only, and the events feed at GET /payments/organizations/{orgId}/events is the record you recover from if a delivery is missed.
4. The API#
| Base URL | https://api.avvio.xyz/business/api/v1 |
| Auth | x-api-key: avvio_… on every request. Nothing to sign |
| Routes | /checkout/organizations/{orgId}/… |
| Contract | partner-checkout.openapi.yaml, the checkout OpenAPI spec |
| Writes | Every POST, PATCH and DELETE requires Idempotency-Key. Same key on a retry returns the original result; without it, 400 IDEMPOTENCY_KEY_REQUIRED |
| Amounts | Decimal strings in the link's currency ("150.00") on links and events; base units with decimals on payment rows |
| Errors | One envelope, { type, message, status }. Branch on type |
| Tools | @avvio/payments ≥ 0.6.0 (Node SDK, CLI, MCP server) covers every operation below. Or generate a client from the contract in any language |
The checkout contract is its own OpenAPI file, separate from payouts, so a client generated from it has only these thirteen operations:
| Operation | Method and path |
|---|---|
| List products | GET /checkout/organizations/{orgId}/products |
| Create a product | POST /checkout/organizations/{orgId}/products |
| Read, update, archive a product | GET, PATCH, DELETE …/products/{productId} |
| Create a link | POST /checkout/organizations/{orgId}/links |
| List links | GET /checkout/organizations/{orgId}/links |
| Read, edit a draft, delete a draft | GET, PATCH, DELETE …/links/{linkId} |
| Publish a draft | POST …/links/{linkId}/publish |
| Pause a live link | POST …/links/{linkId}/pause |
| List a link's payments | GET …/links/{linkId}/payments |
Prove the key and the verification in one read before you write anything:
curl -s "$AVVIO_BASE_URL/checkout/organizations/$AVVIO_ORG_ID/products" \
-H "x-api-key: $AVVIO_API_KEY"[] is the right answer for a new organization. 403 with the verification message means step 1 is not finished; 401 means the key is wrong or revoked.
Refunds are a dashboard action in this version (an owner or admin, on the payment's row); they reach you as checkout_payment.refunded. There is no API refund yet.
Then#
Accept Payments: products, links, the
checkout_payment.paidhandler and the success page, end to end- Webhooks: signing, retries and the events table
Authentication and Security: what a key can and cannot do
- The Checkout API reference