> ## Documentation Index
> Fetch the complete documentation index at: https://spreecommerce.org/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Subscribe to the newsletter

> Subscribes an email address to the newsletter for the current store.

Behavior:

- If the email is already verified for this store, the existing subscription is returned unchanged.
- If the request is unauthenticated (guest), the subscription is created in an unverified state
  and two events are published: `newsletter_subscriber.subscription_requested` (carrying the
  `verification_token` and the validated `redirect_url`, intended for headless storefronts that
  want to send the confirmation email themselves via a webhook handler) and the legacy
  `newsletter_subscriber.subscribed` lifecycle event (which the bundled `spree_emails` package
  listens to and uses to send a default confirmation email). The confirmation link should point
  at `redirect_url?token=<verification_token>` and call `POST /newsletter_subscribers/verify`
  when the user clicks it.
- If the request is authenticated via JWT and the customer's email matches the subscribed email,
  the subscription is auto-verified and no events are fired — the JWT already proves email
  ownership, so no confirmation email is needed.

The optional `redirect_url` is where the verification token should land on the storefront. The
server does not return a validation error when the URL is outside the store's
[Allowed Origins](/developer/core-concepts/allowed-origins); instead, the URL is silently
omitted from the webhook payload (secure-by-default). When no allow-list is configured on the
store, the URL is also omitted. Callers therefore receive the same 201 regardless, and the
webhook handler should fall back to the store's storefront URL when `redirect_url` is missing
from the payload.

Newsletter consent is preserved across registration: if a guest subscribes and later registers
with the same email, the existing subscriber record is reused.




## OpenAPI

````yaml /api-reference/store.yaml post /api/v3/store/newsletter_subscribers
openapi: 3.0.3
info:
  title: Store API
  contact:
    name: Spree Commerce
    url: https://spreecommerce.org
    email: hello@spreecommerce.org
  description: >
    Spree Store API v3 - Customer-facing storefront API for building headless
    commerce experiences.


    ## Authentication


    The Store API uses two authentication methods:


    ### API Key (Required)

    All requests must include a publishable API key in the `x-spree-api-key`
    header.


    ### JWT Bearer Token (For authenticated customers)

    After login, include the JWT token in the `Authorization: Bearer <token>`
    header.


    ### Order Token (For guest checkout)

    When creating an order, a `token` is returned. Include this in the
    `x-spree-token` header

    for guest access to that specific order.


    ## Response Format


    All responses are JSON. List endpoints return paginated responses with
    `data` and `meta` keys.


    ## Error Handling


    Errors return a consistent format:

    ```json

    {
      "error": {
        "code": "record_not_found",
        "message": "Product not found"
      }
    }

    ```
  version: v3
servers:
  - url: http://{defaultHost}
    variables:
      defaultHost:
        default: localhost:3000
security: []
tags:
  - name: Authentication
    description: Customer authentication (login, logout, token refresh)
  - name: Product Catalog
    description: Products and categories
  - name: Carts
    description: Shopping cart management
  - name: Orders
    description: Order lookup
  - name: Customers
    description: Customer account, addresses, saved payment methods, and order history
  - name: Markets
    description: Markets, countries, currencies, and locales
  - name: Wishlists
    description: Customer wishlists
  - name: Newsletter Subscribers
    description: Guest and customer newsletter subscriptions (double opt-in)
  - name: Policies
    description: Store policies (return policy, privacy policy, terms of service)
  - name: Digitals
    description: Digital product downloads
paths:
  /api/v3/store/newsletter_subscribers:
    post:
      tags:
        - Newsletter Subscribers
      summary: Subscribe to the newsletter
      description: >
        Subscribes an email address to the newsletter for the current store.


        Behavior:


        - If the email is already verified for this store, the existing
        subscription is returned unchanged.

        - If the request is unauthenticated (guest), the subscription is created
        in an unverified state
          and two events are published: `newsletter_subscriber.subscription_requested` (carrying the
          `verification_token` and the validated `redirect_url`, intended for headless storefronts that
          want to send the confirmation email themselves via a webhook handler) and the legacy
          `newsletter_subscriber.subscribed` lifecycle event (which the bundled `spree_emails` package
          listens to and uses to send a default confirmation email). The confirmation link should point
          at `redirect_url?token=<verification_token>` and call `POST /newsletter_subscribers/verify`
          when the user clicks it.
        - If the request is authenticated via JWT and the customer's email
        matches the subscribed email,
          the subscription is auto-verified and no events are fired — the JWT already proves email
          ownership, so no confirmation email is needed.

        The optional `redirect_url` is where the verification token should land
        on the storefront. The

        server does not return a validation error when the URL is outside the
        store's

        [Allowed Origins](/developer/core-concepts/allowed-origins); instead,
        the URL is silently

        omitted from the webhook payload (secure-by-default). When no allow-list
        is configured on the

        store, the URL is also omitted. Callers therefore receive the same 201
        regardless, and the

        webhook handler should fall back to the store's storefront URL when
        `redirect_url` is missing

        from the payload.


        Newsletter consent is preserved across registration: if a guest
        subscribes and later registers

        with the same email, the existing subscriber record is reused.
      parameters:
        - name: x-spree-api-key
          in: header
          required: true
          schema:
            type: string
        - name: Authorization
          in: header
          required: false
          description: >-
            Optional Bearer JWT — when present, links the subscription to that
            customer
          schema:
            type: string
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                email:
                  type: string
                  format: email
                  example: subscriber@example.com
                redirect_url:
                  type: string
                  format: uri
                  example: https://your-store.com/newsletter/confirm
                  description: >-
                    Storefront URL the verification token should be appended to.
                    Silently omitted from the webhook payload when the store has
                    allowed origins configured and this URL does not match one
                    of them, or when no allowed origins are configured at all.
              required:
                - email
      responses:
        '201':
          description: auto-verified when JWT matches subscribed email
          content:
            application/json:
              example:
                id: sub_UkLWZg9DAJ
                email: harriet.conroy@mohr.co.uk
                created_at: '2026-05-26T16:14:11.183Z'
                updated_at: '2026-05-26T16:14:11.186Z'
                verified: true
                verified_at: '2026-05-26T16:14:11Z'
                customer_id: cus_UkLWZg9DAJ
              schema:
                $ref: '#/components/schemas/NewsletterSubscriber'
        '422':
          description: invalid email format
          content:
            application/json:
              example:
                error:
                  code: validation_error
                  message: Email is invalid
                  details:
                    email:
                      - is invalid
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
        - api_key: []
      x-codeSamples:
        - lang: javascript
          label: Spree SDK
          source: |-
            import { createClient } from '@spree/sdk'

            const client = createClient({
              baseUrl: 'https://your-store.com',
              publishableKey: '<api-key>',
            })

            const subscriber = await client.newsletterSubscribers.create({
              email: 'subscriber@example.com',
              redirect_url: 'https://your-store.com/newsletter/confirm',
            })
components:
  schemas:
    NewsletterSubscriber:
      type: object
      properties:
        id:
          type: string
        email:
          type: string
        created_at:
          type: string
        updated_at:
          type: string
        verified:
          type: boolean
        verified_at:
          type: string
          nullable: true
        customer_id:
          type: string
          nullable: true
      required:
        - id
        - email
        - created_at
        - updated_at
        - verified
        - verified_at
        - customer_id
      x-typelizer: true
    ErrorResponse:
      type: object
      properties:
        error:
          type: object
          properties:
            code:
              type: string
              example: record_not_found
            message:
              type: string
              example: Record not found
            details:
              type: object
              description: Field-specific validation errors
              nullable: true
              example:
                name:
                  - is too short
                  - is required
                email:
                  - is invalid
          required:
            - code
            - message
      required:
        - error
      example:
        error:
          code: validation_error
          message: Validation failed
          details:
            name:
              - is too short
            email:
              - is invalid
  securitySchemes:
    api_key:
      type: apiKey
      name: x-spree-api-key
      in: header
      description: Publishable API key for store access

````