Skip to content

Quickstart

This guide will walk you through getting Proxy up and running so you can provide a delegated checkout experience for your customers.

Before using any SDKs, connect your payment provider, set up its webhook, create Proxy API keys, and configure the handoff experience.

Navigate to the payment providers section of your dashboard. In the Stripe section, enter the following:

  • Stripe account ID (found here)
  • Your Stripe publishable key
  • A Stripe private key with read permission for all core resource types

In Proxy’s payment providers dashboard, add a webhook config and enter a route key. Proxy shows the webhook URL as soon as the route key is set. Copy that URL, but keep the Proxy form open.

Go to Stripe’s Webhooks dashboard and create a new webhook endpoint with the following settings:

Setting Value
Event destination scope Your account
API version At least 2024-06-20
Events payment_intent.succeeded
payment_intent.payment_failed
payment_intent.canceled
checkout.session.completed
invoice.paid
invoice.payment_failed
customer.subscription.updated
customer.subscription.deleted
Destination type Webhook endpoint
Endpoint URL The webhook URL copied from Proxy

After Stripe creates the endpoint, copy the new webhook’s signing secret. Paste it into the Proxy webhook secret field and create the webhook config.

Head over to the API Keys section of your Proxy dashboard and create a secret key and a publishable key. Our SDKs will use these keys to connect to Proxy.

A handoff is the Proxy-hosted payment link the buyer shares when someone else needs to pay. Proxy uses this setup to know what name to show on that link and where to send the payer after they open it.

In the Hosted handoff section, save these required fields:

  • Display name: the merchant or product name shown to the payer
  • Checkout URL: the page in your app where the payer completes checkout
  • Allowed hosts: the domains Proxy is allowed to forward payers to

The Checkout URL’s domain must be included in Allowed hosts. Save this before creating payment links; without it, Proxy cannot create a shareable handoff link.

For your backend apps:

Terminal window
npm install @proxy-checkout/server-js @proxy-checkout/stripe-server-js stripe

For your frontend apps:

Terminal window
npm install @proxy-checkout/client-js

Start in the checkout page the buyer already uses. Proxy does not render this button for you. Add your own delegated payment button and call your backend when it is clicked.

type HandoffResponse = {
expiresAt: string;
handoffUrl: string;
proxySessionId: string;
};
async function startDelegatedPayment(
payerEmail?: string,
): Promise<HandoffResponse | null> {
const response = await fetch("/api/proxy/handoffs", {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({ payerEmail }),
});
if (!response.ok) {
// fallback
return null;
}
const handoff = (await response.json()) as HandoffResponse;
// Present the url to the user. Whether you copy it to clipboard,
// show a modal, or open up a mobile share sheet is your decision.
return handoff;
}

When the payer opens the handoff link, Proxy sends them to the Checkout URL you configured in the dashboard with a proxy_session_id query parameter. Use your existing checkout UI on that page.

Parse the Proxy session ID, load the checkout state from your backend, then ask your backend for a Stripe client secret when the payer is ready to pay.

import { parseProxySessionIdFromUrl } from "@proxy-checkout/client-js";
async function loadPayerCheckout() {
const proxySessionId = parseProxySessionIdFromUrl(window.location.href);
if (!proxySessionId) {
return null;
}
const response = await fetch(
`/api/proxy/sessions/${encodeURIComponent(proxySessionId)}`,
);
if (!response.ok) {
return null;
}
const checkout = await response.json();
return checkout;
}
async function createStripeCheckout(proxySessionId: string) {
const response = await fetch(
`/api/proxy/sessions/${encodeURIComponent(proxySessionId)}/checkout-session`,
{ method: "POST" },
);
if (!response.ok) {
return null;
}
return (await response.json()) as { clientSecret: string };
}

The only Proxy-specific browser step is reading the proxy_session_id. Use the returned clientSecret with your existing Stripe client flow.