Skip to content
API · Products

Products and variations

Read your store catalog and pricing from your external system.

List products

GET /api/v1/external/products

Returns all products of the tenant's catalog. Requires scope products:read.

Request

curl https://api.nuvlyx.com/api/v1/external/products \
  -H "Authorization: Bearer nvl_live_YOUR_TOKEN"

Response 200

[
  {
    "id": "0f1c2b9e-…",
    "name": "1-month digital subscription",
    "slug": "1-month-digital-subscription",
    "kind": "DIGITAL",
    "status": "ACTIVE",
    "variations": [
      {
        "id": "abc12345-…",
        "sku": "SUB-1M",
        "price": "10000.00",
        "stockQuantity": 42,
        "durationDays": 30,
        "dependsOnStock": true
      }
    ],
    "createdAt": "2026-04-01T15:30:00.000Z"
  }
]

Get a product

GET /api/v1/external/products/:id

Returns a single product with all its variations, price tiers and categories. Requires scope products:read.

Path parameters

ParameterTypeDescription
idUUIDProduct identifier.

Request

curl https://api.nuvlyx.com/api/v1/external/products/0f1c2b9e-… \
  -H "Authorization: Bearer nvl_live_YOUR_TOKEN"

Errors

  • 401 — Missing or invalid token.
  • 403 — Token missing the products:read scope.
  • 404 — Product not found or belongs to another store.

Quote the price for a customer

GET /api/v1/external/products/:id/price

Returns the price of each variation of the product, applying the price tier that maps to the customer. Useful when your bot needs to show the customer the exact price before confirming the order. Requires scope products:read.

Query parameters

ParamTypeDescription
customerIdUUIDCustomer UUID. Mutually exclusive with customerPhone.
customerPhoneE.164Customer's linked phone. Mutually exclusive with customerId.

If you send neither, the response returns the base (retail) price for each variation. Sending both returns 400.

Request

curl "https://api.nuvlyx.com/api/v1/external/products/0f1c…/price?customerId=9f8e…" \
  -H "Authorization: Bearer nvl_live_YOUR_TOKEN"

Response 200

{
  "productId": "0f1c…",
  "productName": "1-month digital subscription",
  "currency": "COP",
  "customer": {
    "id": "9f8e…",
    "tier": { "id": "tier_…", "name": "Silver", "level": 2 }
  },
  "variations": [
    {
      "variationId": "abc12345-…",
      "sku": "SUB-1M",
      "basePrice": "10000.00",
      "price": "8500.00",
      "appliedTier": { "id": "tier_…", "name": "Silver", "level": 2 },
      "availableStock": 42,
      "dependsOnStock": true
    }
  ]
}

Notes

  • No tier assigned: if the customer has no tier, customer.tier and appliedTier are null and price equals basePrice.
  • Variation with no tier-specific rate: if the variation has no explicit price for the customer's tier, price falls back to basePrice and appliedTier is null for that variation only.
  • Unlinked phone: sending customerPhone for a customer who hasn't linked WhatsApp yet returns 404 with an explicit message.
  • Heads-up: this endpoint is for display. When you call POST /external/orders the server recomputes the price with the same logic — it never accepts a price from the client.