churnguardianDocs
Developers

Entrance API

One endpoint mints a hosted cancel-flow link at the moment a customer tries to cancel. Call it from your server, then send the customer to the URL it returns.

Overview

The entrance API does not read or change anything in Stripe by itself. It takes a customer and a subscription, resolves the offer that customer should see, records the presentation, and returns a short-lived URL to the hosted cancel flow. Your app decides when to call it and where to send the browser.

If you have not connected Stripe or set up cancel flows yet, start with the setup guide.

Authentication

Every request carries your entrance key as a bearer token. Generate it in Settings → Cancel Flows. The key is shown once, so store it in your server environment and never in the browser.

HTTP header
Authorization: Bearer <your entrance key>

Server only

The entrance key is a secret. Only call this endpoint from your backend. The returned cancel-flow URL is safe to share with the customer.

The endpoint

Endpoint
POST /api/cancel-flow/entrance

Send JSON with the two Stripe identifiers. The customer is whoever is trying to cancel, and the subscription is the one you would otherwise cancel.

Request body

FieldTypeDescription
customerIdstringThe Stripe customer id, for example cus_123.
subscriptionIdstringThe Stripe subscription id, for example sub_123.

GET variant

The same input works as query parameters, and responds with a 307 redirect straight to the hosted flow. This is handy when your server wants to redirect the customer without handling the URL itself.

GET
GET /api/cancel-flow/entrance?customerId=cus_123&subscriptionId=sub_123

Response

A successful POST returns the hosted flow URL plus the offer that was chosen, so you can log or display it if you want to.

200 OK
{
  "ok": true,
  "url": "https://app.churnguardian.com/cancel/eyJvcmdJZCI6...",
  "combo": { "discountPct": 30, "durationMonths": 3 }
}

Send the customer to url. The link is tied to that customer and subscription, needs no login, and expires after 7 days.

Errors

StatusWhen it happensWhat to do
401The bearer key is missing or does not match an account, or Stripe is not connected.Check the key and confirm Stripe is connected.
400customerId or subscriptionId is missing.Send both fields as non-empty strings.
400A flow could not be created for that subscription.Confirm the subscription exists on the connected Stripe account.

Examples

curl

bash
curl -X POST https://app.churnguardian.com/api/cancel-flow/entrance \
  -H "Authorization: Bearer $CHURNGUARDIAN_ENTRANCE_KEY" \
  -H "Content-Type: application/json" \
  -d '{"customerId":"cus_123","subscriptionId":"sub_123"}'

Node

server.js
const res = await fetch(
  `${process.env.CHURNGUARDIAN_URL}/api/cancel-flow/entrance`,
  {
    method: 'POST',
    headers: {
      Authorization: `Bearer ${process.env.CHURNGUARDIAN_ENTRANCE_KEY}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({ customerId, subscriptionId })
  }
);

const { url } = await res.json();
// Redirect the customer to the hosted flow.
redirect(url);

Notes

  • A customer is assigned to the adaptive or control arm the first time they appear, and stays there, so the comparison stays honest.
  • Calling the endpoint records an offer presentation, which is what the cancel-flow dashboard counts.
  • The hosted page is self-contained. You do not need to render anything on your side beyond the redirect.