Skip to main content
NNexvendo
← Back home

API documentation

Read-only API for your tenant data.

Use the Nexvendo REST API to pull your aggregated catalog, customers, and quotes into your own systems — ERP, BI dashboards, custom portals. Bearer-token auth, JSON-only, EU-hosted.

Authentication

Create an API key in your portal at /portal/api-keys. You'll see the plaintext value once at creation — copy it then. We never show it again; only a SHA-256 hash is stored.

Pass the key in the Authorization header on every request:

curl https://nexvendo.com/api/v1/catalog \
  -H "Authorization: Bearer nxv_live_xxxxxxxxxxxxxxxxxxxxxxxx"

Format

Keys start with nxv_live_ followed by a URL-safe random suffix. Treat them as passwords — never commit to source control.

Scopes

Two scopes today: read (catalog, customers, quotes — list and fetch) and write (customer creation). Pick scopes per-key in the portal.

Base URL

All endpoints live under https://nexvendo.com/api/v1/. Responses are JSON with Content-Type: application/json. Pagination is offset-based with limit + offset query parameters.

Endpoints

Catalog, customers, and quotes are live. Quote creation arrives once a design partner pilots it — we'd rather build it against a real workflow than ship a guess.

GET/api/v1/catalog

List product offers for the authenticated tenant.

Query parameters

  • limit
    integer · default 100
    Max 1000. Number of rows to return.
  • offset
    integer · default 0
    Starting offset for pagination.
  • distributor_id
    uuid
    Filter to a single distributor.
  • manufacturer
    string
    Exact-match filter on manufacturer name.
  • condition
    string
    Filter by condition: 'new', 'refurbished_a', 'refurbished_b', etc.
  • q
    string
    Full-text search across SKU, MPN, EAN, name, manufacturer.

Example request

curl https://nexvendo.com/api/v1/catalog?limit=50&condition=refurbished_a \
  -H "Authorization: Bearer nxv_live_..."

Example response

{
  "data": [
    {
      "id": "1a2b3c…",
      "distributor_id": "dist-uuid",
      "distributor_sku": "LEN-21CB000WMX",
      "manufacturer": "Lenovo",
      "mpn": "21CB000WMX",
      "ean": "0196801105119",
      "name": "Lenovo ThinkPad X1 Carbon Gen 11 i7 32GB 1TB 14\"",
      "condition": "refurbished_a",
      "list_price": 15700,
      "currency": "SEK",
      "stock": 6,
      "co2e_kg": 84,
      "imported_at": "2026-06-03T10:00:00Z",
      "updated_at": "2026-06-03T10:00:00Z"
    }
  ],
  "pagination": {
    "limit": 50,
    "offset": 0,
    "total": 1247,
    "has_more": true
  }
}
GET/api/v1/customers

List customers (your B2B end customers) for the authenticated tenant.

Query parameters

  • limit
    integer · default 100
    Max 500.
  • offset
    integer · default 0
    Starting offset for pagination.
  • status
    string
    Filter by status: 'lead', 'active', or 'inactive'.
  • q
    string
    Search across name, contact_email, vat_number.

Example request

curl https://nexvendo.com/api/v1/customers?status=active \
  -H "Authorization: Bearer nxv_live_..."

Example response

{
  "data": [
    {
      "id": "9f3e7c…",
      "name": "Helsinki MSP Oy",
      "contact_name": "Petra Lindqvist",
      "contact_email": "petra@helsinkimsp.fi",
      "vat_number": "FI28765432",
      "country": "FI",
      "status": "active",
      "created_at": "2026-04-12T08:11:02Z",
      "updated_at": "2026-05-29T13:44:30Z"
    }
  ],
  "pagination": { "limit": 100, "offset": 0, "total": 23, "has_more": false }
}
GET/api/v1/customers/{id}

Retrieve a single customer by id.

Query parameters

    Example request

    curl https://nexvendo.com/api/v1/customers/9f3e7c… \
      -H "Authorization: Bearer nxv_live_..."

    Example response

    {
      "data": {
        "id": "9f3e7c…",
        "name": "Helsinki MSP Oy",
        "contact_email": "petra@helsinkimsp.fi",
        "vat_number": "FI28765432",
        "country": "FI",
        "status": "active",
        "created_at": "2026-04-12T08:11:02Z",
        "updated_at": "2026-05-29T13:44:30Z"
      }
    }
    POST/api/v1/customers

    Create a new customer. Requires write scope. Returns the created record with 201.

    Query parameters

    • name
      string
      Required. Legal name of the customer.
    • contact_name
      string
      Primary contact at the customer.
    • contact_email
      string
      Primary contact email.
    • contact_phone
      string
      Primary contact phone.
    • vat_number
      string
      VAT identifier, e.g. DK12345678.
    • country
      string
      ISO-2 country code, e.g. DK, SE, NO, FI.
    • address_line1
      string
    • city
      string
    • postal_code
      string
    • status
      string
      'lead', 'active', or 'inactive'. Defaults to 'active'.

    Example request

    curl -X POST https://nexvendo.com/api/v1/customers \
      -H "Authorization: Bearer nxv_live_..." \
      -H "Content-Type: application/json" \
      -d '{"name":"Acme IT ApS","country":"DK","vat_number":"DK87654321","status":"lead"}'

    Example response

    {
      "data": {
        "id": "newly-minted-uuid",
        "name": "Acme IT ApS",
        "country": "DK",
        "vat_number": "DK87654321",
        "status": "lead",
        "created_at": "2026-06-03T11:42:17Z",
        "updated_at": "2026-06-03T11:42:17Z"
      }
    }
    GET/api/v1/quotes

    List quotes for the authenticated tenant. Totals are included; line items are not (fetch a single quote for those).

    Query parameters

    • limit
      integer · default 50
      Max 200.
    • offset
      integer · default 0
      Starting offset for pagination.
    • status
      string
      Filter: 'draft', 'sent', 'accepted', 'rejected', 'expired', 'revised'.
    • customer_id
      uuid
      Filter to a single customer.
    • updated_since
      ISO 8601
      Incremental sync — return only quotes updated at or after this timestamp.

    Example request

    curl https://nexvendo.com/api/v1/quotes?status=accepted&updated_since=2026-06-01T00:00:00Z \
      -H "Authorization: Bearer nxv_live_..."

    Example response

    {
      "data": [
        {
          "id": "quote-uuid",
          "number": "Q-2026-00042",
          "status": "accepted",
          "customer_id": "9f3e7c…",
          "customer_name": "Helsinki MSP Oy",
          "valid_until": "2026-06-30",
          "currency": "EUR",
          "total_cost": 8400,
          "total_sell": 11760,
          "total_margin": 3360,
          "created_at": "2026-06-01T09:14:00Z",
          "updated_at": "2026-06-02T15:22:11Z"
        }
      ],
      "pagination": { "limit": 50, "offset": 0, "total": 5, "has_more": false }
    }
    GET/api/v1/quotes/{id}

    Retrieve a single quote with line items.

    Query parameters

      Example request

      curl https://nexvendo.com/api/v1/quotes/quote-uuid \
        -H "Authorization: Bearer nxv_live_..."

      Example response

      {
        "data": {
          "id": "quote-uuid",
          "number": "Q-2026-00042",
          "status": "accepted",
          "customer_name": "Helsinki MSP Oy",
          "currency": "EUR",
          "total_cost": 8400,
          "total_sell": 11760,
          "total_margin": 3360,
          "lines": [
            {
              "id": "line-uuid",
              "position": 1,
              "description": "Lenovo ThinkPad X1 Carbon Gen 11",
              "distributor_sku": "LEN-21CB000WMX",
              "mpn": "21CB000WMX",
              "manufacturer": "Lenovo",
              "condition": "refurbished_a",
              "quantity": 6,
              "unit_cost": 1400,
              "unit_sell": 1960,
              "currency": "EUR"
            }
          ]
        }
      }
      POST/api/v1/quotes

      Create a DRAFT quote from catalog references. Requires write scope. Drafts only, by design — your integration pushes the configuration, a human reviews and sends from the portal. Lines resolve against your catalog by offer_id, distributor SKU, or MPN (cheapest match wins on ambiguity); any line that fails to resolve rejects the whole request with 422.

      Query parameters

      • lines
        array
        Required, 1–100 entries: { offer_id? | sku? | mpn?, quantity? (default 1), unit_sell? (default: cost + your markup rules), description? }.
      • customer_id
        uuid
        Link an existing customer (snapshot copied onto the quote).
      • customer
        object
        Inline snapshot when not linking: { name?, contact?, email? }.
      • currency
        string
        Defaults to the first line's offer currency.
      • valid_until
        date
        YYYY-MM-DD.
      • notes
        string
        Internal notes — never customer-facing.

      Example request

      curl -X POST https://nexvendo.com/api/v1/quotes \
        -H "Authorization: Bearer nxv_live_..." \
        -H "Content-Type: application/json" \
        -d '{
          "customer_id": "9f3e7c…",
          "valid_until": "2026-07-15",
          "lines": [
            { "sku": "LEN-21CB000WMX", "quantity": 6 },
            { "mpn": "WD22TB4", "quantity": 6, "unit_sell": 2590 }
          ]
        }'

      Example response

      {
        "data": {
          "id": "new-quote-uuid",
          "number": "Q-2026-00057",
          "status": "draft",
          "customer_id": "9f3e7c…",
          "customer_name": "Helsinki MSP Oy",
          "valid_until": "2026-07-15",
          "currency": "EUR",
          "total_cost": 10260,
          "total_sell": 14304,
          "total_margin": 4044,
          "lines": [
            { "position": 1, "description": "Lenovo ThinkPad X1 Carbon Gen 11", "quantity": 6, "unit_sell": 1960, "currency": "EUR" },
            { "position": 2, "description": "Dell Thunderbolt 4 Dock WD22TB4", "quantity": 6, "unit_sell": 2590, "currency": "EUR" }
          ]
        }
      }
      GET/api/v1/distributors

      List the distributors connected to the authenticated tenant — those reachable via a feed configuration or that have sent at least one pricefile ingestion.

      Query parameters

      • limit
        integer · default 100
        Max 200.
      • offset
        integer · default 0
        Starting offset for pagination.

      Example request

      curl https://nexvendo.com/api/v1/distributors \
        -H "Authorization: Bearer nxv_live_..."

      Example response

      {
        "data": [
          {
            "id": "dist-uuid",
            "name": "TD Synnex DK",
            "country": "DK",
            "type": "distributor",
            "status": "integrated"
          }
        ],
        "pagination": { "limit": 100, "offset": 0, "total": 1, "has_more": false }
      }

      Webhooks

      Instead of polling, subscribe to quote lifecycle events. Configure endpoints at /portal/api-keys — you pick an HTTPS URL and the events; we show the signing secret once.

      Events & payload

      quote.sent, quote.accepted, quote.declined, quote.expired. Each delivery is a JSON POST:

      {
        "event": "quote.accepted",
        "created_at": "2026-06-04T14:02:11Z",
        "data": {
          "quote": {
            "id": "quote-uuid",
            "number": "Q-2026-00042",
            "status": "accepted",
            "customer_id": "9f3e7c…",
            "customer_name": "Helsinki MSP Oy",
            "total_sell": 11760,
            "currency": "EUR",
            "valid_until": "2026-06-30",
            "response_note": "Approved — PO 4517 follows."
          }
        }
      }

      Signatures & delivery

      Every request carries X-Nexvendo-Signature: t=<unix>,v1=<hex> where v1 is HMAC-SHA256 of `${t}.${rawBody}` with your endpoint's whsec_… secret. Verify with constant-time comparison and reject timestamps older than ±5 minutes.

      Delivery semantics: 5-second timeout per attempt; failed deliveries retry automatically with backoff (5 min → 30 min → 2 h, 4 attempts total), so design your handler to be idempotent — the same event can arrive more than once. Respond 2xx quickly and process async. For certainty, reconcile periodically with GET /api/v1/quotes?updated_since=…. The event header is also sent as X-Nexvendo-Event.

      Rate limits

      No published rate limits today. The API is intended for read-mostly integration use — pulling the catalog every 5 minutes is fine, every second is excessive. We'll publish concrete limits when we add per-tier quotas. If you hit unexpected throttling, contact us.

      Error responses

      All errors are JSON with { "error": "<reason>" } and an appropriate HTTP status: 401 (missing/invalid/revoked key), 403 (insufficient scope), 503 (service unavailable), 500 (server error). Retry 5xx with exponential backoff; do not retry 4xx.

      Need a different endpoint?

      We're shipping more endpoints as design partners request them. Quote creation, customer update, webhook subscriptions — tell us what's blocking your integration and we'll prioritise.

      info@nexvendo.com