For partners

White-label integration

Everything needed to run payment requests and checkout under a partner's own brand. The partner's pages frame ours; once a buyer reaches the checkout, signing in, paying and settling all happen inside our site.

Site (production)
https://stabledrop.me
API (production)
https://api.stabledrop.me
Test (site and API)
https://test.conduit-ucpi.com
You (the partner)

The white-label brand, reading this. You request your brand (step 1) and host the pages on your site (step 4).

Stabledrop (us)

The Stabledrop team. We set up your brand and allow your domains (steps 2 and 3). Nothing for you to do there.

Your merchants

Your customers who take payments, through links, a checkout button or the API (steps 5 and 6).

#StepWho does it
1Request your brand: paste your config and sendYou (the partner)
2Create your brandStabledrop (us)
3Allow your domainsStabledrop (us)
4Host the framed pages on your siteYou (the partner)
5Take paymentsYour merchants
6Confirm paymentsYour merchantsYou (the partner)
7Test end to endYou (the partner)Stabledrop (us)
Step 1

Request your brand

Who does this:You (the partner)You, the partner: fill in the form below and send it.

Paste your brand config, add your email address and domains, and send us the email this builds. We set up your brand and allow your domains (steps 2 and 3), then reply to confirm.

Required. We reply here.

The sites that will host the pages, e.g. your-site.example, www.your-site.example

Optional, e.g. staging.your-site.example

Paste your whole brand config JSON, or upload the file. It must include your brand id as "id" and your display name as "name".

Your logo (and a dark-background version), favicon, share image and any WOFF2 fonts. PNG, JPEG, WebP, SVG, ICO or WOFF2; up to 6 files, 1 MB each.

It goes to [email protected], with your files attached, and we reply to the address you give.

Nothing you send can change a payment's terms, fee, tiebreaker or verification. Branding only changes how the pages look and read.

Step 2

We create your brand

Who does this:Stabledrop (us)Stabledrop, once your request arrives. Nothing for you to do here; this is how we do it.

  1. Upload the image and font files to the service (POST /api/brands/{id}/assets); each upload returns an asset id.
  2. Add the brand to webapp/config/brands/snapshot.json, referring to those asset ids. Pull first, because pushing replaces the whole record.
  3. Push it, then commit the updated snapshot so the copy bundled with the site agrees.
  4. Tell the partner their brand id.
snapshot.json · brands.your-brand.config (excerpt)
{
  "id": "your-brand",
  "name": "Your Brand",
  "tagline": "Protected payments",
  "locale": "en",
  "links": {
    "support": "mailto:[email protected]",
    "terms": "/terms-of-service",
    "privacy": "/privacy-policy",
    "arbitration": "/dispute-policy"
  }
}
shell · from the webapp repo
WHITELABEL_URL=https://api.stabledrop.me WHITELABEL_ADMIN_KEY=… node scripts/brands/pull.mjs
# edit config/brands/snapshot.json, then push only this brand
WHITELABEL_URL=https://api.stabledrop.me WHITELABEL_ADMIN_KEY=… node scripts/brands/push.mjs your-brand

Theme colours are "R G B" triples in primary and secondary ramps. Use the test service's address for the test environment.

Step 3

We allow your domains

Who does this:Stabledrop (us)Stabledrop. Nothing for you to do here; we email you when your pages can go live.

  • Frame allow-list: add every partner domain to the webapp's ALLOWED_FRAME_ANCESTORS variable, in each environment the partner will use (test and production), then redeploy the webapp. Without this the browser shows an empty frame.
  • Privy: add the domains to the allowed origins in the Privy dashboard.

Check the variable for each environment before telling a partner their pages are ready.

Step 4

Host the framed pages on your site

Who does this:You (the partner)You, the partner, on your own website: copy these pages into it.

Each page on your site frames one of ours with your brand id. Keep the allow attribute: without clipboard-write the copy buttons fail inside your page.

Checkout: your-site/contract-create (required for checkout)

Passes its own address parameters straight to our checkout, always under your brand. A link such as your-site/contract-create?seller=0x…&amount=9.77&description=Order%20%231042opens that payment. It also forwards the checkout's results to whatever opened the page, for merchants who open it as a popup.

contract-create.html
<div id="checkout"></div>
<script>
  var BRAND = 'your-brand';
  var SITE = 'https://stabledrop.me';

  // The merchant's terms are this page's own query string; the brand is always yours.
  var params = new URLSearchParams(window.location.search);
  params.set('b', BRAND);

  var frame = document.createElement('iframe');
  frame.src = SITE + '/contract-create?' + params.toString();
  frame.title = 'Checkout';
  frame.allow = 'clipboard-write; payment';
  frame.style.cssText = 'width:100%;height:760px;border:0';
  document.getElementById('checkout').appendChild(frame);

  // The checkout reports to this page (payment_completed, payment_error,
  // payment_cancelled, close_modal). Forward them to whatever opened this page.
  window.addEventListener('message', function (event) {
    if (event.origin !== SITE) return;
    if (window.opener) window.opener.postMessage(event.data, '*');
    if (window.parent !== window) window.parent.postMessage(event.data, '*');
  });
</script>

Payment requests: your-site/create

Merchants make a payment request and get a link, QR code and PDF to send their customer.

create.html
<iframe src="https://stabledrop.me/create?b=your-brand"
        title="Request a payment"
        allow="clipboard-write; payment"
        style="width:100%;height:760px;border:0"></iframe>

Developer guide: your-site/integrate

Our integration guide, shown with your brand. Its code samples already include your brand id, and its support contact is the one from your brand record.

integrate.html
<iframe src="https://stabledrop.me/integrate?b=your-brand"
        title="Integration guide"
        allow="clipboard-write"
        style="width:100%;height:85vh;min-height:720px;border:0"></iframe>

Optional: your-site/dashboard

dashboard.html
<iframe src="https://stabledrop.me/dashboard?b=your-brand"
        title="Payments dashboard"
        allow="clipboard-write; payment"
        style="width:100%;height:85vh;min-height:720px;border:0"></iframe>

For testing, use https://test.conduit-ucpi.com in place of https://stabledrop.me.

Step 5

Your merchants take payments

Who does this:Your merchantsYour merchants, on their own sites. Share this step with them, or point them at your integrate page from step 4, which shows the same with your brand filled in.

Merchants can use any of three routes. All of them record the payment under the partner's brand.

A. A link to the partner's checkout page

link
https://your-site.example/contract-create?seller=0xYourWalletAddress&amount=9.77&description=Order%20%231042&tokenSymbol=USDC
ParameterMeaning
sellerRequired. The wallet that is paid: 0x plus 40 hex characters, or an email address.
amountRequired. In dollars as typed, for example 9.77. At least 1, or exactly 0.001 for a free test.
descriptionRequired. What the payment is for, up to 160 characters.
tokenSymbolUSDC (default) or USDT.
epoch_expiryPayout date as a Unix timestamp. Default 7 days. 0 pays the seller instantly, with no dispute window.
order_idYour order reference, echoed back in events and webhooks.
returnWhere to send the buyer afterwards.
webhook_urlYour endpoint to be told when the payment is made.

Without all three required parameters, the buyer is sent to the general payment page instead.

B. A checkout button on the merchant's own website

The script opens our checkout in a popup. Point baseUrl at our site and set brand: the partner's branding and attribution, with nothing hosted by the partner.

merchant's page
<script src="https://stabledrop.me/conduit-checkout.js"></script>
<script>
  ConduitCheckout.init({
    sellerAddress: '0xYourWalletAddress',
    baseUrl: 'https://stabledrop.me',
    brand: 'your-brand',
    onSuccess: function (data) { console.log('Paid', data); },
    onError: function (error) { console.error(error); },
    onCancel: function () { console.log('Cancelled'); }
  });
</script>

<button onclick="ConduitCheckout.open({ amount: '9.77', description: 'Order #1042', orderId: '1042' })">
  Pay
</button>

C. From the merchant's server, with no script

No sign-in or API key. The answer contains the escrow address, how to fund it, a pay_link to send the customer, and the exact request that creates the escrow once paid. We do not email the customer for a server call; the merchant sends the pay_link.

shell
curl -X POST https://api.stabledrop.me/api/ap2/prepare \
  -H 'Content-Type: application/json' \
  -d '{
    "seller": "0xYourWalletAddress",
    "nominal_buyer": "[email protected]",
    "amount": 9770000,
    "expiry_timestamp": 1893456000,
    "description": "Order #1042",
    "brand": "your-brand"
  }'

On the API, amount is in base units: 1 USDC is 1000000, so 9.77 is 9770000. Once the money arrives, send the answer's settle.request.body unchanged to POST /api/ap2/settle. Every field is described in the API reference.

Step 6

Confirm payments

Who does this:Your merchantsYou (the partner)Your merchants check each payment before shipping. You can see every payment made under your brand.

Check a payment before shipping anything. The results service is public and needs no key. Treat it as the source of truth; a webhook only tells you to look.

your merchants · check one payment
curl -X POST https://api.stabledrop.me/api/results \
  -H 'Content-Type: application/json' \
  -d '{"contractid": "507f1f77bcf86cd799439011"}'
you · every payment made under your brand
curl -X POST https://api.stabledrop.me/api/results \
  -H 'Content-Type: application/json' \
  -d '{"brandId": "your-brand"}'

A payment has arrived when its state is one of ACTIVE, DISPUTED, RESOLVED, CLAIMED or COMPLETED. Having a chainAddress does not mean it was paid: the address is recorded when the buyer opens the checkout.

Step 7

Test end to end

Who does this:You (the partner)Stabledrop (us)You run these checks on your pages; we fix anything on our side. An empty frame means step 3 is not done yet: tell us.

  • Each hosted page shows our page inside it, in the partner's branding (an empty frame means the domain is not on the allow-list yet).
  • your-site/contract-create?seller=…&amount=0.001&description=Test opens a checkout for the free test amount.
  • Pay it; the payment appears in /api/results under your brand id.
  • The developer guide's samples show your brand id and your support contact.
  • A merchant's checkout button opens the popup and calls onSuccess after paying.
Good to know

Limits of framed pages

  • Google sign-in cannot run inside a frame. Buyers inside your page get email sign-in and an "open in a new tab" option for Google. Some browsers, notably Safari, may not keep a sign-in inside a frame.
  • Links we generate are on our domain. Payment links, request emails and dashboard links open stabledrop.me/…?b=your-brand: your branding, our address.
  • No webhooks to the partner. Partners follow their payments through the results service, filtered by brand id.
  • Calling our API from a browser page on your domain needs your origin allowed for cross-origin requests. Calls from a server do not.