Skip to content

Self-serve signup

A prospective merchant signs up by POSTing to one public endpoint. The request creates a pending signup that's reviewed (by rules, an operator, or both) and, once approved, provisions a tenant. This is the same endpoint the marketing site's signup form posts to — you can call it from your own front end too.

Submit a signup

POST /api/v1/public/signupno auth, no tenant header (you're creating a tenant, not acting within one).

const res = await fetch("https://api.litecommerce.io/api/v1/public/signup", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    contactName: "Dana Reyes",     // required, 1–120 chars
    email: "dana@summitgear.co",   // required, valid email, ≤254 chars
    tenantName: "Summit Gear Co.", // required, 2–120 chars
    plan: "free",                  // optional: "free" | "pro" | "enterprise" (default "free")
    source: "pricing-free",        // optional attribution, ≤120 chars
  }),
});
 
const signup = await res.json();
// → { "id": "…", "status": "pending_review", "createdAt": "2026-05-28T…Z" }

Submitting the same email again while a signup is still pending_review (or already approved) returns the existing record rather than creating a duplicate — the endpoint is idempotent on email.

What protects this endpoint

The API validates the body strictly (unknown fields are rejected with 400), de-dupes on email, and runs every submission through an auto-approval rule set (below). Bot-defenses like Cloudflare Turnstile and a honeypot live in the marketing site's hosted form, not the API itself — if you build your own signup UI, add your own front-end abuse protection on top of the API's rule checks.

The lifecycle

POST /public/signup
      │
      ▼
 pending_review ──► (auto-approval rules evaluate) ──► decision recorded
      │                                                    │
      │                                          ┌─────────┴──────────┐
      ▼                                          ▼                    ▼
 operator review                          auto_approved        flagged_for_review
 in platform-admin                     (provisions when         / enterprise_review
      │                                  the plan's flag is on)        │
      ▼                                          │                     ▼
  approved ──────────────────────────────────────┴──────────► operator decides
      │
      ▼
 tenant provisioned + welcome email

A pending signup carries two independent fields:

  • statuspending_reviewapproved · rejected · spam (terminal, set once).
  • autoApprovalDecisionawaiting_evaluationauto_approved · flagged_for_review · enterprise_review. This is the rules' verdict; it's separate from whether the tenant has actually been provisioned.

Auto-approval rules

Every signup is scored against a small rule set. Any failure routes it to flagged_for_review (an operator decides); passing all of them yields auto_approved. The checks:

  • Disposable email domain — the address's domain is on a deny-list.
  • Brand-impersonation tenant name — the name collides with a well-known brand.
  • Per-IP rate — too many signups from one IP in a 24-hour window.
  • Prior-tenant email — the email is already attached to a tenant or another pending signup.
  • MX record — the email domain has no reachable mail server (DNS lookup, short timeout). A transient DNS failure also flags for review — but a signup flagged only for this reason is automatically re-evaluated after a short grace period, so a momentary blip recovers on its own; a genuinely unreachable domain stays flagged for an operator.

Enterprise signups skip the rules entirely and go straight to enterprise_review — Enterprise is always a human conversation.

When does auto-approval actually provision?

A clean auto_approved verdict only provisions automatically when the operator has enabled it for that plan via an Edge Config flag:

  • marketing_signupAutoApproveFree
  • marketing_signupAutoApprovePro
  • marketing_signupAutoApproveEnterprisecode-enforced off. The API short-circuits Enterprise to "not auto-approved" before even reading the flag, so flipping it has no effect.

With a plan's flag off (the default — "Wave A"), an auto_approved signup still waits for an operator to approve it manually. With it on (Wave B/C), the system provisions the tenant within seconds of signup. Either way the verdict is recorded for audit.

Flag keys use underscores, not dots — Vercel Edge Config rejects dotted keys.

What provisioning creates

On approval (operator-driven or automatic), one atomic transaction:

  1. Creates the organization on FREE_TRIAL, status ONBOARDING.
  2. Upserts the founding owner user (by email) and an OWNER membership.
  3. Marks the pending signup approved and links it to the new org.
  4. Queues a founding-owner welcome email (delivered via the outbox just after commit).

If anything in that transaction fails, it all rolls back — there's no half-provisioned tenant. The welcome email is a durable outbox event, so a delivery hiccup is retried rather than lost.