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

# Retrieve the patient storefront

> Returns your clinic's storefront: settings, curated product listings and bundles. Requires the `shop:read` scope. The `payout` object reflects Routable payout-onboarding status. Enabling the store requires payout_eligible=true.



## OpenAPI

````yaml /openapi.yaml get /shop
openapi: 3.1.0
info:
  title: VitaRelay API
  version: 2.0.0
  description: |
    The VitaRelay REST API.

    **Base URL:** `https://vitarelay.com/api/public/v1`

    ## Authentication
    All requests require a Bearer API key:

    ```text
    Authorization: Bearer vr_live_xxxxxxxxxxxxxxxx
    ```

    Keys are issued per organization. `vr_live_` keys act on production data.
    `vr_test_` keys operate a fully-isolated **sandbox** (see below).

    ## Pagination
    List endpoints are cursor-based. Pass `limit` (default 50, max 100) and
    `cursor` (the `next_cursor` from the previous page). When `next_cursor`
    is `null` there are no further pages. All resource ids are UUIDs.

    ## Idempotency
    Write endpoints accept your own external identifiers —
    `external_patient_id`, `external_intake_id`, `external_order_id`. These act
    as idempotency keys: replaying a request with the same external id returns
    the original resource (HTTP `200` instead of `201`) rather than creating a
    duplicate.

    ## Rate limiting
    Write endpoints are rate limited per API key — default **60 requests per
    minute** (fixed window). Exceeding the limit returns `429 rate_limited`
    with `Retry-After`, `X-RateLimit-Limit`, `X-RateLimit-Remaining` and
    `X-RateLimit-Reset` headers. Read endpoints are not rate limited in v1.

    ## Sandbox
    With a `vr_test_` key, writes never create real patients, intakes or orders
    and never charge a card. They return synthetic ids (`sandbox_pat_…`,
    `sandbox_int_…`, `sandbox_ord_…`) and include `"sandbox": true` in the
    response. Sandbox objects advance through a simulated lifecycle that fires
    real webhook deliveries to your endpoint (`intake.reviewed`, `order.paid` →
    `order.shipped` → `order.delivered`) with `"sandbox": true` in the payload.
    In sandbox, reference a patient by `external_patient_id` or by the returned
    `sandbox_pat_…` id.

    ## Webhooks
    Outbound webhooks are configured in the VitaRelay admin UI (there is no
    webhook management API). Events: `order.paid`, `order.shipped`,
    `order.delivered`, `order.exception`, `intake.reviewed`. Each delivery is
    signed with HMAC-SHA256 over the raw body and carries the headers
    `X-VitaRelay-Signature: sha256=<hex>`, `X-VitaRelay-Event`,
    `X-VitaRelay-Delivery` (event id) and `X-VitaRelay-Timestamp`. Failed
    deliveries are retried with exponential backoff and dead-lettered after the
    maximum attempts.
  contact:
    name: VitaRelay Support
    email: info@vitarelay.com
servers:
  - url: https://vitarelay.com/api/public/v1
    description: Production
security:
  - bearerAuth: []
tags:
  - name: Patients
    description: Patient records scoped to your organization.
  - name: Intakes
    description: Intake form submissions. Write access is Vita Clinic only.
  - name: Orders
    description: >-
      Orders and fulfillment status. Two billing modes: `card_on_file` (default)
      charges the clinic's stored card synchronously, and `patient_checkout`
      creates the order unpaid and returns a checkout block so the patient can
      pay on your own page via Authorize.Net Accept.js (see POST
      /orders/{id}/pay).
  - name: Products
    description: Catalog products available to your organization.
  - name: Prescriptions
    description: >-
      Prescriptions written by your organization (read only). Refer patients
      into the Internal Doctor Network (IDN). You refer; an IDN doctor evaluates
      and prescribes. Requires IDN activation and rx scopes.
  - name: Storefront
    description: >-
      Build and manage your clinic's patient storefront — settings, curated
      product listings and bundles. Requires the `shop:read` / `shop:write`
      scopes.
  - name: Subscriptions
    description: >-
      Patient-shop subscription lifecycle. Requires `subscriptions:read` or
      `subscriptions:write`.
paths:
  /shop:
    get:
      tags:
        - Storefront
      summary: Retrieve the patient storefront
      description: >-
        Returns your clinic's storefront: settings, curated product listings and
        bundles. Requires the `shop:read` scope. The `payout` object reflects
        Routable payout-onboarding status. Enabling the store requires
        payout_eligible=true.
      operationId: getShop
      responses:
        '200':
          description: The storefront.
          headers:
            X-RateLimit-Limit:
              $ref: '#/components/headers/XRateLimitLimit'
            X-RateLimit-Remaining:
              $ref: '#/components/headers/XRateLimitRemaining'
            X-RateLimit-Reset:
              $ref: '#/components/headers/XRateLimitReset'
          content:
            application/json:
              schema:
                type: object
                properties:
                  settings:
                    $ref: '#/components/schemas/ShopSettings'
                  products:
                    type: array
                    items:
                      $ref: '#/components/schemas/ShopListing'
                  bundles:
                    type: array
                    items:
                      $ref: '#/components/schemas/ShopBundle'
                  custom_products:
                    type: array
                    items:
                      $ref: '#/components/schemas/ShopCustomProduct'
                  payout:
                    $ref: '#/components/schemas/ShopPayoutStatus'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '422':
          $ref: '#/components/responses/ValidationFailed'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/InternalError'
components:
  headers:
    XRateLimitLimit:
      description: Requests permitted in the current window.
      schema:
        type: integer
    XRateLimitRemaining:
      description: Requests remaining in the current window.
      schema:
        type: integer
    XRateLimitReset:
      description: Unix timestamp when the current window resets.
      schema:
        type: integer
    RetryAfter:
      description: Seconds to wait before retrying.
      schema:
        type: integer
  schemas:
    ShopSettings:
      type: object
      description: Storefront settings for your clinic's patient shop.
      properties:
        shop_id:
          type: string
          format: uuid
        org_id:
          type: string
          format: uuid
        is_enabled:
          type: boolean
          description: When false the patient shop is closed and patients see nothing.
        allow_rnd:
          type: boolean
          description: Allow research-use-only products to be listed.
        headline:
          type:
            - string
            - 'null'
        welcome_message:
          type:
            - string
            - 'null'
        eligibility:
          type: object
          description: Which product families this clinic may offer to patients.
    ShopListing:
      type: object
      description: One curated product in the patient shop.
      properties:
        id:
          type: string
          format: uuid
          description: Listing id (used by DELETE /shop/products/{listingId}).
        platform_product_id:
          type: string
          format: uuid
        markup_type:
          type: string
          enum:
            - percent
            - flat
        markup_value:
          type: number
        custom_title:
          type:
            - string
            - 'null'
        custom_description:
          type:
            - string
            - 'null'
        rx_mode:
          type: string
          enum:
            - none
            - refill_only
            - refill_or_approval
            - approval
        is_listed:
          type: boolean
        purchase_mode:
          $ref: '#/components/schemas/PurchaseMode'
        default_cadence:
          $ref: '#/components/schemas/Cadence'
        first_order_immediate:
          type: boolean
        name:
          type: string
        description:
          type:
            - string
            - 'null'
        product_type:
          type:
            - string
            - 'null'
        dosage_form:
          type:
            - string
            - 'null'
        image_urls:
          type:
            - array
            - 'null'
          items:
            type: string
        requires_prescription:
          type: boolean
        item_kind:
          type: string
          enum:
            - product
        available_cadences:
          type: array
          items:
            type: string
            enum:
              - weekly
              - monthly
              - quarterly
          description: All three cadences when subscribable, otherwise empty.
        requires_shipping:
          type: boolean
        patient_price_cents:
          type: integer
          description: What the patient pays.
        eligible:
          type: boolean
    ShopBundle:
      type: object
      description: A multi-product package, optionally subscribable.
      properties:
        id:
          type: string
          format: uuid
        name:
          type: string
        description:
          type:
            - string
            - 'null'
        image_url:
          type:
            - string
            - 'null'
        pricing_mode:
          type: string
          enum:
            - sum
            - flat
            - package_markup
        flat_price_cents:
          type:
            - integer
            - 'null'
        package_markup_type:
          type:
            - string
            - 'null'
          enum:
            - percent
            - flat
            - null
        package_markup_value:
          type: number
        is_listed:
          type: boolean
        is_subscribable:
          type: boolean
          deprecated: true
        purchase_mode:
          $ref: '#/components/schemas/PurchaseMode'
        default_cadence:
          type:
            - string
            - 'null'
          enum:
            - weekly
            - monthly
            - quarterly
            - null
        first_order_immediate:
          type: boolean
          description: Bill and ship the first order at signup.
        items:
          type: array
          items:
            $ref: '#/components/schemas/ShopBundleItem'
        item_kind:
          type: string
          enum:
            - bundle
        patient_price_cents:
          type: integer
        available_cadences:
          type: array
          items:
            type: string
        requires_prescription:
          type: boolean
        requires_shipping:
          type: boolean
          description: false only when every package item is a service.
        rx_mode:
          type: string
        eligible:
          type: boolean
    ShopCustomProduct:
      type: object
      properties:
        id:
          type: string
          format: uuid
        name:
          type: string
        description:
          type:
            - string
            - 'null'
        item_kind:
          type: string
          enum:
            - custom
        patient_price_cents:
          type: integer
        product_kind:
          type: string
          description: service is non-shippable; other custom kinds may be physical.
        requires_shipping:
          type: boolean
          description: false for services.
        requires_prescription:
          type: boolean
          description: Always false.
        available_cadences:
          type: array
          items:
            type: string
        is_listed:
          type: boolean
        is_active:
          type: boolean
        purchase_mode:
          $ref: '#/components/schemas/PurchaseMode'
        default_cadence:
          $ref: '#/components/schemas/Cadence'
        first_order_immediate:
          type: boolean
    ShopPayoutStatus:
      type: object
      description: >-
        The clinic's Routable payout-onboarding state. A storefront cannot be
        enabled until payout_eligible is true.
      properties:
        status:
          type: string
          enum:
            - not_started
            - invited
            - onboarding
            - ready
            - payout_eligible
            - error
        payout_eligible:
          type: boolean
        invite_url:
          type:
            - string
            - 'null'
          description: >-
            Hosted Routable onboarding link (bank + tax + KYC). Present once
            onboarding has started.
        routable_company_id:
          type:
            - string
            - 'null'
        needs_onboarding:
          type: boolean
          description: Convenience flag = !payout_eligible.
          additionalProperties: true
    PurchaseMode:
      type: string
      enum:
        - one_time
        - subscription
        - both
      description: >-
        Controls whether checkout permits one-time purchases, subscriptions, or
        both.
    Cadence:
      type:
        - string
        - 'null'
      enum:
        - weekly
        - monthly
        - quarterly
        - null
    ShopBundleItem:
      type: object
      required:
        - platform_product_id
      properties:
        platform_product_id:
          type: string
          format: uuid
        qty:
          type: integer
          minimum: 1
          maximum: 99
          default: 1
        name:
          type: string
          readOnly: true
        product_type:
          type:
            - string
            - 'null'
          readOnly: true
    Error:
      type: object
      required:
        - error
      properties:
        error:
          type: object
          required:
            - code
            - message
          properties:
            code:
              type: string
              description: |
                One of `invalid_body`, `validation_failed`, `unauthorized`,
                `insufficient_scope`, `not_vita_clinic`, `patient_not_found`,
                `product_not_found`, `product_not_allowed`, `duplicate_request`,
                `rate_limited`, `card_required`, `payment_declined`,
                `internal_error`, `not_found`.
            message:
              type: string
      example:
        error:
          code: validation_failed
          message: One or more fields are invalid
  responses:
    Unauthorized:
      description: Missing, invalid or revoked API key (`unauthorized`).
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    Forbidden:
      description: |
        The key lacks the required scope (`insufficient_scope`) or its
        organization is not an active Vita Clinic (`not_vita_clinic`).
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    ValidationFailed:
      description: Body parsed but failed validation (`validation_failed`).
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    RateLimited:
      description: Per-key rate limit exceeded (`rate_limited`). Default 60 writes/minute.
      headers:
        Retry-After:
          $ref: '#/components/headers/RetryAfter'
        X-RateLimit-Limit:
          $ref: '#/components/headers/XRateLimitLimit'
        X-RateLimit-Remaining:
          $ref: '#/components/headers/XRateLimitRemaining'
        X-RateLimit-Reset:
          $ref: '#/components/headers/XRateLimitReset'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    InternalError:
      description: Unexpected server error (`internal_error`).
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      description: |
        API key issued by VitaRelay. Send as `Authorization: Bearer vr_live_…`
        (production) or `Authorization: Bearer vr_test_…` (sandbox).

````