Skip to content

Server-Side Checkout

Use this method when your backend creates Stripe Checkout Sessions. With hosted capture installed, add data-liftvector="true" to your existing checkout anchor or form. No extra browser code is needed for ordinary HTML checkout. Your backend must still read via and pass it to Stripe as client_reference_id.

Open Settings → Website integration → Server-Side Checkout and copy your merchant’s Installation snippet. Load the classic defer script once on referral landing pages and pages that hand off to checkout, before downstream checkout code.

The LiftVector script’s src is https://static.liftvector.app/script/liftvector.js. Preserve the merchant, provider, and method attributes from your workspace snippet.

The script captures the affiliate’s via token and retains it on the same website origin and browser for up to 30 days. See browser retention for expiry and storage limits.

If your server already captures and retains referrals, use server-only capture instead of the browser installation and marked controls.

Use your own checkout route instead of /checkout in these examples. Keep your existing checkout fields, authentication, and antiforgery protection. The examples show where to add the attribute, not a replacement for your checkout implementation.

<a href="/checkout" data-liftvector="true">Continue to checkout</a>

LiftVector adds via to the destination query string. For an example captured token of alice, your backend receives /checkout?via=alice. Read via from the request query; do not hardcode the example token.

Relative and absolute HTTP(S) URLs are supported. Existing query parameters and fragments are preserved, including the base query inherited by empty or fragment-only links. Unmarked anchors and non-HTTP(S) destinations are not changed.

<form action="/checkout" method="post" data-liftvector="true">
<!-- Keep your existing checkout fields here. -->
<button type="submit">Continue to checkout</button>
</form>

LiftVector supplies a hidden input named via. Native POST submission sends it as a form field, not JSON. Read it from your backend’s submitted form data.

<form action="/checkout" method="get" data-liftvector="true">
<button type="submit">Continue to checkout</button>
</form>

The hidden via input is submitted in the query string. Read it the same way as the checkout anchor’s parameter.

Leave via out of your own parameters and form controls when you want LiftVector to supply the captured candidate. Existing merchant values take precedence, even when empty or equal to the candidate:

  • An anchor’s existing via query parameter is preserved.
  • A form control named via is preserved; LiftVector does not add a competing field.
  • For GET forms, an explicit via in the action URL is copied into a hidden field unless your form already supplies it. This preserves the reference when native GET submission replaces the action query.
  • For POST forms, an explicit action-URL via remains in the query, and LiftVector does not add a captured form value. Your backend must read that deliberately supplied query reference rather than expect a generated form field.

Only script-owned values are updated or removed when their source changes. An expired captured candidate is removed, not replaced with an empty field; a merchant-supplied reference is not removed just because browser capture expires.

Anchors and forms inserted or changed after page load are supported in the ordinary document, not inside iframes or shadow roots. DOM observation is asynchronous: let the script process newly inserted controls before immediate programmatic submission. If capture is unavailable, normal navigation and submission must still work without a referral.

3. Pass the token to Stripe from your backend

Section titled “3. Pass the token to Stripe from your backend”
  1. Read via from the matching query or form field, or from your unexpired server-owned capture.
  2. Validate the unchanged value: 4–64 lowercase ASCII letters, digits, underscores, or hyphens. Do not trim, lowercase, decode it into an identity, or substitute an internal affiliate ID.
  3. Set the Checkout Session’s top-level client_reference_id to that original public token when creating the Session. This applies to both mode=payment and mode=subscription.
  4. Omit the referral when absent, expired, or invalid. Missing referral data must not block checkout.

The examples below extend your existing server-side Stripe Session creation call. token is the unexpired via value read from your checkout request or server session; options contains your existing prices, checkout mode, and redirect URLs. Use your already configured server-side Stripe client. These are additions to your checkout, not standalone endpoints or a LiftVector API.

If client_reference_id is already used for an order or customer ID, resolve the conflict before enabling handoff. Preserve existing references, including empty strings; do not overwrite them, concatenate values, or use metadata as a fallback. Subscription renewals use the established financial association rather than another copied browser token.

The script cannot set client_reference_id on a Session your server creates. Installing capture and marking the control completes the browser-side work only.

Using Stripe’s Node.js SDK (stripe), on your server:

const valid =
typeof token === "string" &&
token.length >= 4 &&
token.length <= 64 &&
!/[^a-z0-9_-]/.test(token);
if (valid && options.client_reference_id == null) {
options.client_reference_id = token;
}
const session = await stripe.checkout.sessions.create(options);
const checkoutUrl = session.url;

Redirect the customer to checkoutUrl using your existing response flow.

Using Stripe’s Python SDK (stripe), where client is your configured StripeClient and options is your Session parameters dictionary:

import re
valid = (
isinstance(token, str)
and re.fullmatch(r"[a-z0-9_-]{4,64}", token) is not None
)
if valid and options.get("client_reference_id") is None:
options["client_reference_id"] = token
session = client.v1.checkout.sessions.create(options)
checkout_url = session.url

Redirect the customer to checkout_url using your existing response flow.

Using Stripe’s PHP SDK (stripe/stripe-php), where $stripe is your configured \Stripe\StripeClient, $token is the request or retained referral, and $options is your Session parameters array:

$valid = is_string($token)
&& preg_match('/\A[a-z0-9_-]{4,64}\z/', $token) === 1;
if ($valid && !isset($options['client_reference_id'])) {
$options['client_reference_id'] = $token;
}
$session = $stripe->checkout->sessions->create($options);
$checkoutUrl = $session->url;

Redirect the customer to $checkoutUrl using your existing response flow.

Using Stripe’s .NET SDK (Stripe.net), where client is your configured StripeClient, token is a nullable string, and options is your existing SessionCreateOptions:

using System.Text.RegularExpressions;
using Stripe.Checkout;
if (options.ClientReferenceId is null &&
Regex.IsMatch(token ?? "", @"\A[a-z0-9_-]{4,64}\z"))
{
options.ClientReferenceId = token;
}
var sessions = new SessionService(client);
var session = await sessions.CreateAsync(options);
var checkoutUrl = session.Url;

Redirect the customer to checkoutUrl using your existing response flow. All four examples preserve an existing reference, including an empty string, and omit invalid referral candidates.

For a checkout implemented with your own JSON request, read window.LiftVector?.referral ?? null when checkout starts and include it explicitly as via in your existing request body. Read that JSON field on the backend, then apply the same validation and Session handoff above.

In your existing browser checkout handler, add the field to the payload you already send:

const via = window.LiftVector?.referral ?? null;
const payload = {
...checkoutFields,
via,
};

Here checkoutFields is your existing JSON payload object. Serialize payload as the body of your existing authenticated checkout request; retain its endpoint, headers, error handling, and antiforgery protection. This adds the referral field without introducing a separate request or checkout API. Apply one of the server-side examples above to the received via value.

data-liftvector does not rewrite JSON or intercept arbitrary requests. Keep authentication and antiforgery protection. Load external deferred checkout code after LiftVector; inline scripts and async loaders do not guarantee that order.

No browser script or attribute is required if your server captures via when the visitor arrives. Validate it and retain it in your server-side session or account state with a finite expiry. Invalid input must not replace a valid retained candidate, and ordinary navigation must not renew expiry. Use the unexpired token in the same backend handoff.

Complete a referred purchase in the connected environment. For a sandbox-connected merchant, use a fresh sandbox customer when checking new attribution. Inspect the resulting Checkout Session’s client_reference_id, confirm collected payment, and check the sale, affiliate attribution, and expected commission in LiftVector.

Then record merchant confirmation in Website integration. Confirmation alone does not prove the handoff works. Use troubleshooting if the token does not reach the Session.