Order status
GET /v1/orders/:orderId returns the app-scoped order state without exposing provider secrets.
Integration guide
A new SaaS product needs one server credential, one approved origin, registered SKUs, and a callback endpoint. Stripe opens in the original-site modal by default; the browser never chooses a price, user identity, provider route, or return URL.
Before the first request
Yito Pay onboarding creates an app ID and a one-time server API key. The app record stores the product name, approved return origin, optional entitlement callback URL, provider switches, and merchant route. Each exact hostname that displays Embedded Checkout is registered separately and every sellable SKU maps to a verified Stripe Price, payment mode, currency, and entitlement key. PayPal subscriptions additionally require an approved PayPal Plan.
Store the API key only in the product backend’s secret manager. Do not place it in a browser bundle, public environment variable, mobile application, analytics event, or support screenshot. Yito Pay stores only a keyed digest of the credential, so a lost key must be replaced rather than recovered.
Required product secrets
YITO_PAY_BASE_URL=https://pay.yito.ai
YITO_PAY_APP_KEY=yp_live_••••••••
YITO_PAY_CALLBACK_SECRET=••••••••
YITO_PAY_CHECKOUT_PROVIDER=stripeStripe and PayPal server credentials and webhook verification values remain inside Yito Pay. Individual products do not receive them.
Step 1
After confirming the signed-in user, generate a unique external order ID and call the Yito Pay API with the registered SKU. Reuse that same external order ID when retrying the request. A different user, SKU, or quantity under an existing ID is rejected visibly.
const response = await fetch(
'https://pay.yito.ai/v1/checkout-sessions',
{
method: 'POST',
headers: {
'authorization': 'Bearer ' + process.env.YITO_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('Yito Pay returned ' + response.status);
}
const checkout = await response.json();The response identifies the selected provider and returns only the browser configuration for that provider plus a short-lived recovery URL. Treat every checkout credential as sensitive session material and do not log it.
Step 2
Load the shared widget once and open it only after the server creates the order. For Stripe, the widget mounts Embedded Checkout directly in the original product page, never through a nested Yito Pay iframe. Eligible customers can use Link inside that same Stripe iframe without a separate Link SDK. For an explicitly enabled PayPal route, the same modal shell starts PayPal JS v6 and PayPal controls whether approval uses a popup, provider modal, or required redirect.
<script src="https://pay.yito.ai/sdk/v1/pay-widget.js"></script>
<div id="checkout" role="dialog" aria-modal="true"></div>
<script>
const payment = await window.YitoPay.open({
provider: checkout.provider,
publishableKey: checkout.publishable_key,
clientSecret: checkout.client_secret,
statusUrl: '/api/billing/orders/' + checkout.order_id,
onConfirmed: () => location.assign('/billing/success')
});
</script>The completion callback starts order polling; it does not grant access. If the provider UI cannot initialize, offer the returned recovery URL as an explicit top-level action rather than redirecting automatically.
Step 3
The product backend can query GET /v1/orders/:orderId with its app key. Show a confirmed state only when the API returns paid or the product has processed a valid entitlement callback. A processing state should explain that payment confirmation is still underway instead of pretending the order failed.
Do not poll forever. After a short browser window, send the customer to a pending screen that can be refreshed safely. The verified provider webhook continues working even if the browser is gone.
Step 4
Read the callback body as raw text, reject timestamps outside the allowed tolerance, calculate HMAC-SHA256 over timestamp.rawBody, and compare signatures in constant time. Store X-Yito-Pay-Event-Id before granting or revoking access, and select the prepared per-app secret using X-Yito-Pay-Key-Version.
Return a successful response only after the durable entitlement update is committed. A non-success response triggers a later delivery attempt with the same event ID.
Operational endpoints
Subscription-management and refund requests require the app credential and validated product user or administrator context. They must not be exposed as unauthenticated browser calls. Health checks are public and reveal only service readiness.
GET /v1/orders/:orderId returns the app-scoped order state without exposing provider secrets.
POST /v1/customer-portal-sessions uses the stored subscription provider to open Stripe Billing Portal or PayPal Automatic Payments.
POST /v1/refunds uses the stored order provider and a deterministic idempotency key.
Questions, answered
No. The registered SKU is the only pricing input. Yito Pay loads the registered provider Price or Plan, currency, payment mode, and entitlement from its server-side catalog.
Store it in the product backend secret manager. Never send it to a browser or embed it in a client bundle. The browser should call the authenticated product backend first.
Open the recovery URL returned with the checkout response as a top-level page. It uses the same order boundary without creating a nested iframe.
Yes. When Link is enabled for the selected Stripe account and the buyer is eligible, Stripe can show Link inside the same Embedded Checkout iframe. No separate Link SDK is required, and card checkout still works when Link is unavailable or disabled.
No. PayPal support is implemented behind global and per-app switches, but it must have matching credentials, a verified webhook, catalog mappings, and Sandbox acceptance before an approved Shinstar-routed app can use it.
Build on a reliable payment boundary
Start with the integration guide, then register the app, domain, and server credentials before enabling checkout.