Order status
GET /v1/orders/:orderId reads only the authenticated app's order.
Integration guide
The shared widget opens a DOM modal inside each approved product—not a new browser window or automatic redirect—while app credentials, registered EUR SKUs, and signed callbacks keep financial terms off the client.
Before the first request
Vidle Pay onboarding stores each approved product's exact HTTPS origin, return paths, callback URL, Mindepy merchant route, and sellable EUR SKUs. Each SKU maps to an active app-scoped Stripe Price, payment mode, billing interval, amount, and entitlement key.
The one-time app key belongs only in that product's backend secret manager. Never place it in a browser bundle, public environment variable, analytics event, mobile app, log, or screenshot.
Product secrets
VIDLE_PAY_BASE_URL=https://pay.vidle.org
VIDLE_PAY_APP_KEY=vp_live_••••••••
VIDLE_PAY_CALLBACK_SECRET=••••••••
VIDLE_PAY_CHECKOUT_PROVIDER=stripeStripe keys and webhook verification secrets remain inside Vidle Pay and are never shared with the product.
Step 1
Confirm the signed-in user, generate a unique order ID, and call Vidle Pay with the registered SKU. Reuse the same external order ID only for an identical retry.
const response = await fetch(
'https://pay.vidle.org/v1/checkout-sessions',
{
method: 'POST',
headers: {
authorization: 'Bearer ' + process.env.VIDLE_PAY_APP_KEY,
'content-type': 'application/json',
'idempotency-key': externalOrderId
},
body: JSON.stringify({
external_order_id: externalOrderId,
external_user_id: authenticatedUser.id,
sku: 'pro_monthly',
provider: 'stripe',
quantity: 1
})
}
);
if (!response.ok) throw new Error('Vidle Pay returned ' + response.status);
const checkout = await response.json();Do not log the returned Checkout client secret or recovery credential.
Step 2
Load the shared widget once. It creates a Shadow DOM modal and mounts Stripe's provider-owned Checkout directly over the product page. It does not call window.open() or navigate the customer away. Link may appear for eligible buyers without a separate Link SDK.
<script src="https://pay.vidle.org/sdk/v1/pay-widget.js"></script>
<script>
await window.VidlePay.open({
provider: 'stripe',
publishableKey: checkout.publishable_key,
clientSecret: checkout.client_secret,
statusUrl: '/api/billing/orders/' + checkout.order_id,
onConfirmed: () => location.assign('/billing/success'),
onPending: () => showPendingPaymentMessage(),
onError: (error) => reportCheckoutError(error)
});
</script>Register the app with managed_payments_enabled=false so Checkout returns an embeddable client secret. The SDK loads its modal CSS automatically and requires a same-origin status URL. Completion starts status polling; it is not payment proof. Offer the recovery URL only as an explicit top-level action when Stripe.js cannot initialize.
Step 3
Query GET /v1/orders/:orderId from the product backend with its app key. Show confirmed only for paid or after the signed entitlement callback is committed. Delayed methods should remain processing.
Do not poll forever. A pending screen can be refreshed safely while verified Stripe events continue without the browser.
Step 4
Read the raw body, reject stale timestamps, calculate HMAC-SHA256 over timestamp.rawBody, and compare signatures in constant time. Store X-Vidle-Pay-Event-Id before changing access.
Return success only after the durable entitlement update commits. Retries preserve the same semantic event ID.
GET /v1/orders/:orderId reads only the authenticated app's order.
POST /v1/customer-portal-sessions opens Stripe Billing Portal for the stored customer.
POST /v1/refunds uses a deterministic idempotency key and the order's immutable Stripe payment reference.
Questions, answered
No. A registered SKU is the only pricing input. Vidle Pay loads the trusted EUR Price, amount, mode, interval, and entitlement from its server catalog.
Store it in the integrating product backend secret manager. Never send it to a browser or include it in a client-accessible build variable.
No. The SDK creates a DOM modal over the current product page and mounts Stripe Embedded Checkout inside it, so ordinary popup blockers do not apply. A recovery-page navigation is shown only as an explicit fallback, while Stripe controls any required bank authentication.
No. The entire pay.vidle.org pool is Stripe-only; its control API rejects PayPal and no PayPal production credential or Queue is installed.
Build on a reliable payment boundary
Start with the integration guide, then register the app, domain, and server credentials before enabling checkout.