Supercommerce API Docs
Store API

Auth — Storefront Registration

Customer sign-up for the storefront: creates an account and returns an authenticated session in one step. Phone number (E.164) is required.

Storefront customer registration via POST /store/auth/register. The endpoint creates the customer account and immediately returns an authenticated session — the caller is logged in without a separate sign-in step.

Source: api-modules/auth/src/controllers/store-auth.controller.ts.

Admin invite, vendor-org invite, and the generic better-auth endpoint /auth/sign-up/email do not require a phone number — only this storefront path does.


Conventions

Authentication

EndpointAuth
POST /store/auth/registernone (public — creates session)

Response envelope

Successful registration returns a 201 wrapped by ResponseInterceptor:

{
  "data": <payload>,
  "message": "Success",
  "statusCode": 201
}

Errors follow the standard error envelope:

{
  "message": "<reason>",
  "statusCode": 400,
  "errorCode": "VALIDATION_ERROR"
}

Session cookies

On success the response sets better-auth session cookies:

HeaderValue
Set-Cookiebetter-auth.session_token=<token>; Path=/; HttpOnly; SameSite=Lax
set-auth-tokenBearer token string (for clients that prefer header-based auth)

The customer is fully authenticated after a successful 201 — no separate login call needed.

Error envelope

statusCodeerrorCodeWhen
400VALIDATION_ERRORMalformed body — bad email, password < 8 chars, non-E.164 phone
422UNPROCESSABLE_ENTITYEmail address already registered
409CONFLICTPhone number already in use

Domain types

RegisteredUserResponse

type RegisteredUserResponse = {
  id: string;
  email: string;
  name: string;
  phoneNumber: string;          // E.164, e.g. "+9779812345678"
  phoneNumberVerified: false;   // always false at registration
};

phoneNumber is unique per store installation. Attempting to register with an already-used phone returns 409.


Endpoints

POST /store/auth/register — Customer sign-up

Creates a new customer account and returns an authenticated session. Phone number is required and must be in E.164 format.

Request body (JSON)

FieldTypeRequiredNotes
namestringyesDisplay name
emailstringyesValid email address
passwordstringyes8–128 characters
phoneNumberstringyesE.164 format — e.g. +9779812345678

Request example

{
  "name": "Priya Sharma",
  "email": "priya@example.com",
  "password": "securePass1",
  "phoneNumber": "+9779812345678"
}

Response 201

{
  "data": {
    "user": {
      "id": "01J9xxxx...",
      "email": "priya@example.com",
      "name": "Priya Sharma",
      "phoneNumber": "+9779812345678",
      "phoneNumberVerified": false
    }
  },
  "message": "Success",
  "statusCode": 201
}

Along with the JSON body, the response sets Set-Cookie: better-auth.session_token=... (and set-auth-token for bearer clients) — the customer is logged in immediately.

Errors

StatusWhen
400Invalid email / password shorter than 8 chars / phoneNumber is not valid E.164
422Email address already registered
409Phone number already in use

Registration is all-or-nothing: the account is created first and the phone attached immediately after, so if the phone write fails (including losing a uniqueness race to a concurrent request) the account is deleted again before the error returns. A 409 therefore leaves nothing behind — the same email can be retried once a free phone number is supplied.


Transactional auth emails

These better-auth flows send real email via the configured SMTP transport (SMTP_HOST/SMTP_PORT/SMTP_USER/SMTP_PASS, from address MAIL_FROM). All templates are brand-neutral (no per-store logo/colours) — this is a white-label, single-tenant platform.

TriggerEndpoint(s)Email sentNotes
Email verificationPOST /auth/send-verification-email, GET /auth/verify-email?token=…"Verify your email"Auto-sent on sign-up, but not required to log in (requireEmailVerification is off). Clicking the link also signs the user in (autoSignInAfterVerification).
Password resetPOST /auth/request-password-reset, POST /auth/reset-password"Reset your password", then "Your password was changed"The reset-link email is followed by a security-notice email once the reset completes (onPasswordReset).
Magic linkPOST /auth/sign-in/magic-link"Sign in to your account"Passwordless sign-in link (expires in ~10 min).
Change emailPOST /auth/change-email"Confirm your email change", then "Confirm your new email address"Two hops when the current address is verified: the current address approves first, which mails the new address, and the change applies only once that second link is followed. If the current address is unverified there is a single hop, sent straight to the new address.
Delete accountPOST /auth/delete-user, GET /auth/delete-user/callback?token=…"Confirm your account deletion"Self-service deletion is gated behind the emailed confirmation link.
Welcome(none — fired on user creation)"Welcome"Sent on every new account (storefront sign-up, OAuth, passkey).

If SMTP is not configured the callbacks fall back to logging the link to the server console, so local development still works without a mail server.

Source: wiring in apps/api/src/app.module.ts; config in api-modules/auth/src/auth.config.ts; templates in api-modules/mailer/src/templates/.


Phone-OTP endpoints (available but not yet enabled)

The better-auth phoneNumber plugin mounts the following endpoints. They exist and accept requests but the SMS sender is currently a stub that only logs — phone-based login is not yet wired to a real SMS provider and is not enabled for production use.

MethodPathPurpose
POST/auth/phone-number/send-otpSend a one-time code to a phone number
POST/auth/phone-number/verifyVerify the code and sign in
POST/auth/sign-in/phone-numberSign in with phone number + password

Do not surface these flows in the customer app until SMS delivery is wired and the feature is explicitly enabled.


User phone fields

Two fields were added to the user record:

FieldTypeNotes
phoneNumberstring | nullUnique; null for users created outside the storefront registration path
phoneNumberVerifiedbooleanSet to false at registration; updated to true after successful OTP verification (feature not yet enabled)

  • customer — address book CRUD for the authenticated customer. See store/customer.md.
  • guest-checkout — anonymous checkout without an account. See store/guest-checkout.md.

On this page