Back to Spree

Customers

docs/developer/core-concepts/customers.mdx

5.4.26.5 KB
Original Source

Overview

Customers interact with your store through the Store API. They can register, log in, manage their profile, and view order history.

mermaid
erDiagram
    Customer ||--o{ Order : "places"
    Customer ||--o{ Address : "has many"
    Customer ||--o{ Wishlist : "has many"
    Customer ||--o{ StoreCredit : "has many"
    Customer ||--o{ PaymentSource : "has many"

    Customer {
        string id
        string email
        string first_name
        string last_name
    }

    Order {
        string number
        string state
    }

    Address {
        string firstname
        string lastname
        string address1
        string city
    }

    Wishlist {
        string name
        boolean is_default
    }

Registration

<CodeGroup>
typescript
const { token, user } = await client.customers.create({
  email: '[email protected]',
  password: 'password123',
  password_confirmation: 'password123',
  first_name: 'John',
  last_name: 'Doe',
})
// token => JWT token for subsequent authenticated requests
// user => { id: "usr_xxx", email: "[email protected]", first_name: "John", ... }
bash
curl -X POST 'https://api.mystore.com/api/v3/store/customers' \
  -H 'X-Spree-Api-Key: pk_xxx' \
  -H 'Content-Type: application/json' \
  -d '{
    "email": "[email protected]",
    "password": "password123",
    "password_confirmation": "password123",
    "first_name": "John",
    "last_name": "Doe"
  }'
</CodeGroup>

Login

<CodeGroup>
typescript
const { token, user } = await client.auth.login({
  email: '[email protected]',
  password: 'password123',
})
// Use the token for authenticated requests
bash
curl -X POST 'https://api.mystore.com/api/v3/store/auth/login' \
  -H 'Authorization: Bearer pk_xxx' \
  -H 'Content-Type: application/json' \
  -d '{
    "email": "[email protected]",
    "password": "password123"
  }'
</CodeGroup>

The response includes a JWT token and a user object. Pass the token in subsequent requests via the Authorization: Bearer <token> header.

Token Refresh

Refresh an expiring token to keep the session alive:

<CodeGroup>
typescript
const { token } = await client.auth.refresh({
  token: existingToken,
})
bash
curl -X POST 'https://api.mystore.com/api/v3/store/auth/refresh' \
  -H 'Authorization: Bearer <jwt_token>'
</CodeGroup>

Password Reset

Password reset is a two-step flow. First, request a reset email. Then, use the token from the email to set a new password.

Step 1: Request Reset

<CodeGroup>
typescript
await client.customer.passwordResets.create({
  email: '[email protected]',
  redirect_url: 'https://myshop.com/reset-password',
})
// Always returns { message: "..." } — even if the email doesn't exist
// This prevents email enumeration
bash
curl -X POST 'https://api.mystore.com/api/v3/store/customer/password_resets' \
  -H 'X-Spree-Api-Key: pk_xxx' \
  -H 'Content-Type: application/json' \
  -d '{
    "email": "[email protected]",
    "redirect_url": "https://myshop.com/reset-password"
  }'
</CodeGroup>

The optional redirect_url parameter specifies where the password reset link in the email should point to. The token will be appended as a query parameter (e.g., https://myshop.com/reset-password?token=...). If the store has Allowed Origins configured, the redirect_url must match one of them.

This fires a customer.password_reset_requested event with the reset token in the payload. If you're using the spree_emails package, the email is sent automatically. Otherwise, subscribe to this event to send the reset email yourself (see Events).

Step 2: Reset Password

<CodeGroup>
typescript
const { token, user } = await client.customer.passwordResets.update(
  'reset-token-from-email',
  {
    password: 'newsecurepassword',
    password_confirmation: 'newsecurepassword',
  }
)
// Returns JWT token + user (auto-login)
bash
curl -X PATCH 'https://api.mystore.com/api/v3/store/customer/password_resets/RESET_TOKEN' \
  -H 'X-Spree-Api-Key: pk_xxx' \
  -H 'Content-Type: application/json' \
  -d '{
    "password": "newsecurepassword",
    "password_confirmation": "newsecurepassword"
  }'
</CodeGroup>

On success, the user is automatically logged in and a JWT token is returned. The reset token expires after 15 minutes (configurable via Spree::Config.customer_password_reset_expires_in) and is single-use (changing the password invalidates it).

Customer Profile

<CodeGroup>
typescript
// Get current customer
const customer = await client.customer.get()
// {
//   id: "usr_xxx",
//   email: "[email protected]",
//   first_name: "John",
//   last_name: "Doe",
//   default_shipping_address: { ... },
//   default_billing_address: { ... },
//   addresses: [{ ... }, { ... }],
// }

// Update profile
const updated = await client.customer.update({
  first_name: 'Jonathan',
  accepts_email_marketing: true,
})
bash
# Get current customer
curl 'https://api.mystore.com/api/v3/store/customer' \
  -H 'Authorization: Bearer <jwt_token>'

# Update profile
curl -X PATCH 'https://api.mystore.com/api/v3/store/customer' \
  -H 'Authorization: Bearer <jwt_token>' \
  -H 'Content-Type: application/json' \
  -d '{ "first_name": "Jonathan", "accepts_email_marketing": true }'
</CodeGroup>

Customer Resources

Authenticated customers have access to these resources:

ResourceDescription
AddressesBilling and shipping addresses with default selection
OrdersPast order history
Credit CardsSaved credit cards for checkout
Payment SourcesOther saved payment methods (PayPal, Klarna, etc.)
Store CreditsBalance assigned by the store, usable at checkout
Gift CardsGift cards owned by or assigned to the customer
WishlistsSaved product lists

Guest Checkout

Customers don't need to register to purchase. Guest checkout uses an order token (X-Spree-Token) to identify the cart. See Orders — Cart for details.