Customer sign-in (magic link)
Orchard customers are passwordless: a shopper enters their email, gets a link, and clicking it signs them in. No passwords to store or reset.
Customer accounts are an opt-in, billable module. Confirm the operator has enabled it for your tenant before building this.
The flow
enter email ──▶ POST /customer/magic-link/request
│ (Orchard emails a link with a one-time token)
click email link ──▶ your page reads the token from the URL
│
▼
POST /customer/magic-link/consume ──▶ session (JWT + refresh)
│
▼
GET /customer/me (Authorization: Bearer <session jwt>)1. Request a link
curl -X POST https://api-test.theorchard.dev/api/v1/customer/magic-link/request \
-H "x-tenant-slug: your-slug" \
-H "Content-Type: application/json" \
-d '{ "email": "shopper@example.com" }'This always responds the same way ({ "ok": true }) whether or not the email
exists — it never reveals whether someone has an account. Orchard sends the email
containing a link back to your site with a one-time token, e.g.
https://your-store.com/auth/callback?token=....
2. Consume the token
On your callback page, exchange the token for a session:
curl -X POST https://api-test.theorchard.dev/api/v1/customer/magic-link/consume \
-H "x-tenant-slug: your-slug" \
-H "Content-Type: application/json" \
-d '{ "token": "<token-from-the-link>" }'You get back a session JWT (and a refresh mechanism). Store the session securely (an HttpOnly cookie is best). The JWT is short-lived (15 minutes) — see refresh below.
3. Use the session
Send the session JWT as a Bearer token for customer-scoped calls:
curl https://api-test.theorchard.dev/api/v1/customer/me \
-H "Authorization: Bearer <session-jwt>"Customer-scoped surfaces (the customer portal) let a signed-in shopper see and manage their own data:
| Action | Endpoint |
|---|---|
| Current customer | GET /api/v1/customer/me |
| Orders / subscriptions / returns | GET /api/v1/customer-portal[...] |
| Cancel a subscription | POST /api/v1/customer-portal/cancel |
| Start a return | POST /api/v1/customer-portal/returns |
4. Refresh and sign out
The session JWT expires after 15 minutes; refresh it on a rolling basis (up to 30 days) so the shopper stays signed in:
curl -X POST https://api-test.theorchard.dev/api/v1/customer/refresh \
-H "Authorization: Bearer <session-jwt>" # returns a fresh session
curl -X POST https://api-test.theorchard.dev/api/v1/customer/signout \
-H "Authorization: Bearer <session-jwt>" # ends the sessionSecurity notes
- Each tenant’s customer sessions are signed with a per-tenant secret — a session from one store is meaningless at another.
- Keep the session JWT out of
localStorageif you can; prefer an HttpOnly, Secure cookie set by your server. - See Authentication for the full session model.