Sell for a seller
Add one header and your key works in the seller's space. Their checkout, their payment, your cut.
Send a seller's userUuid in the On-Behalf-Of header and the request reads and writes their
products, checkouts and payments, as if they made it. The SDKs make it a client of its own:
- Your server → QBitFlow API: Creates a checkout, On-Behalf-Of: seller
- QBitFlow API → Your server: The seller's checkout
- Customer wallet → Payment contract, on-chain: Pays
- Payment contract → Seller's wallet, on-chain: Direct: the seller's share
- Payment contract → Your wallet, on-chain: Direct: your commission
- Payment contract → Your wallet, on-chain: Held: all of it, your commission withheld
- QBitFlow API → Your server: payment.completed
client-on-behalf-of.sh
# An organization key acting in a member's space: the request reads the member's products, in the# key's mode. Without the header, the same key reads the organization's own.curl https://api.qbitflow.app/v2/products \ -H "X-API-Key: $QBITFLOW_API_KEY" \ -H "On-Behalf-Of: $MEMBER_UUID"# 200: a page of Product ({ items, hasMore, nextCursor? })// An organization key acting in a member's space: every request of seller sends// On-Behalf-Of. It shares client's configuration.const seller = client.onBehalfOf(memberUuid);const products = await seller.products.list();console. log( `${products. items. length} products on the first page of the seller's space`);# Every request of this client sends On-Behalf-Of: it acts in the member's space.seller = client.on_behalf_of(member_uuid) # shares the connections and settings of clientproducts = seller.products.list()print(len(products.items), "products on the first page of the seller's space")marketplace/main.go
// A client acting in the member's space (organization key): every request sends// On-Behalf-Of. It shares the connections and configuration of client.seller := client.OnBehalfOf(memberUUID)products, err := seller.Products.List(ctx, nil)if err != nil { log.Fatal(err)}fmt.Println(len(products.Items), "products on the first page of the seller's space")// An organization key acts in a member's space: every request sends On-Behalf-Of.$seller = $client->onBehalfOf( $memberUuid); // shares $client's transport and configurationecho count( $seller->products->list( )->items), " products on the first page of the member's space\n";Create a checkout as the seller
Exactly as in the sell guide, on the seller's client (seller
above, or -H "On-Behalf-Of: $MEMBER_UUID" in cURL):
checkout-create-payment.sh
# A one-time checkout for an inline product. QBitFlow replaces {{UUID}} with the session's id on# redirect. The same Idempotency-Key on a retry never opens a second checkout.curl https://api.qbitflow.app/v2/checkout-sessions/payment \ -H "X-API-Key: $QBITFLOW_API_KEY" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: $(uuidgen)" \ -d '{ "productName": "T-shirt", "description": "Blue, size M", "priceUsd": "4.99", "reference": "order-1042", "successUrl": "https://shop.example.com/orders/success?uuid={{UUID}}", "cancelUrl": "https://shop.example.com/orders/cancel" }'# 201: a CreatedCheckoutSession ({ "link": "https://…/checkout?uuid=pay@…", "uuid": "pay@…", "expiresAt": "…" })# Redirect the customer to "link".// An inline product: nothing needs to exist in your catalog. QBitFlow replaces {{UUID}} with the// session's id on the redirect.const session = await client. checkoutSessions. createPayment( { productName: 'T-shirt', description: 'Blue, size M', priceUsd: '4.99', // USD, a decimal string, never a float reference: 'order-1042', // your order id: unique per space successUrl: `https://shop.example.com/orders/success?uuid=${Placeholders. UUID}`, cancelUrl: 'https://shop.example.com/orders/cancel',}); // Redirect the customer to the hosted checkout page.console.log(`Redirect the customer to ${session.link}`);session = client. checkout_sessions. create_payment( product_name="T-shirt", description="Blue, size M", price_usd="4.99", # USD, a decimal string: never a float reference="order-1042", # your order id: unique per space # QBitFlow replaces the placeholder with the session's id when it redirects the customer. success_url=f"https://shop.example.com/orders/success?uuid={qbitflow. PLACEHOLDER_UUID}", cancel_url="https://shop.example.com/orders/cancel",)# Redirect the customer to the hosted checkout page.print("Send the customer to", session.link)// An inline product: no product needed in the catalog. QBitFlow replaces {{UUID}}// (qbitflow.PlaceholderUUID) with the session's id on redirect.session, err := client. CheckoutSessions. CreatePayment( ctx, &qbitflow. CreatePaymentSessionParams{ ProductName: "T-shirt", Description: "Blue, size M", PriceUSD: "4.99", // a decimal string, never a float Reference: "order-1042", // your order id: unique per space SuccessURL: "https://shop.example.com/orders/success?uuid=" + qbitflow.PlaceholderUUID, CancelURL: "https://shop.example.com/orders/cancel",})if err != nil { log.Fatal(err)}// In an HTTP handler: http.Redirect(w, r, session.Link, http.StatusSeeOther)fmt.Println("Redirect the customer to", session.Link)$session = $client->checkoutSessions->createPayment( new \QBitFlow\Params\CreatePaymentSessionParams( productName: 'T-shirt', description: 'Blue, size M', priceUsd: '4.99', // a decimal string, never a float reference: 'order-1042', // your order id: unique per space successUrl: 'https://shop.example.com/orders/success?uuid=' . \QBitFlow\Placeholders::UUID, cancelUrl: 'https://shop.example.com/orders/cancel',)); header('Location: ' . $session->link); // send the customer to the hosted checkoutPaid directly, the money goes to the seller's wallet, your commission split off. Held, it all goes to yours, your commission withheld.
Watch out
When a seller's checkout is refused
409 merchant_not_ready says why in details.reason: noWallet (a seller paid directly has no
wallet yet; only they can add one, from their own dashboard), organizationNoWallet (a held
seller, while your own wallets accept nothing), fundsHeld (a subscription for a held seller: trust
them first) or noTokenWallet (a subscription, while their wallets accept only native coins).
Removing your wallet on a chain also removes the seller's currencies there: an open checkout meets
409 currency_not_accepted.
What On-Behalf-Of can and can't do
- Every route that acts in a space (products, customers, checkouts, payments, subscriptions,
webhook endpoints), refunds as reads only, in your key's mode, with the seller's role (
user):/membersand/invitationsanswer403, so call those without the header. AuserUuidthat isn't your seller in that mode answers404. - Every seller at once: without the header,
includeMembers=trueon the payment and subscription routes, on the lists and the single reads, reads every seller's, each naming itsuserUuid(read only: acting on one still takes the header). - Policies bind sellers, not you. Your key acting for a seller isn't bound by your
organization's policies. A seller's own dashboard or key is: what a policy turns off
(
members.products,members.subscriptions,members.refunds,members.apiKeys,members.webhooks), reads included, answers403 policy_disabledwithdetails.policy, before any lookup.members.checkoutRedirectsrefuses a checkout'ssuccessUrlorcancelUrl, named indetails.field. Yourcheckout.customerPaysProcessingFeeis theirs too: a seller's checkout sending anotherfees.processingFeeanswers403 processing_fee_set_by_organization.
Check it
me on the seller's client answers user, the seller in onBehalfOfUserUuid. Pay their test checkout: the
payment is in the seller's space, its settlement.split showing your commission as organization.