Medidenta / Partner API / InventoryHTTPS · JSON

Inventory reference

One feed. Your assigned catalog.

Read stock and product metadata for the SKUs made available to your key. Pull everything in one request, or filter by a comma-separated SKU list.

GEThttps://hub.medidenta.com/api/inventory.php

Read or Read/Write requiredRead-only endpointNo request body

Full inventory or specific SKUs

Request URLs
# Full inventory assigned to this key
GET https://hub.medidenta.com/api/inventory.php

# One product
GET https://hub.medidenta.com/api/inventory.php?sku=SKU-100

# Multiple products in one request
GET https://hub.medidenta.com/api/inventory.php?sku=SKU-100,SKU-200

With no parameters, the endpoint returns all readable products in your key’s inventory scope, in a single response without pagination. “Full inventory” means your assigned catalog, not every product held by Medidenta.

Query parameters

ParameterTypeRequiredBehavior
skuStringNoOne SKU, or up to 100 comma-separated SKUs. Omit it for full inventory. Each SKU is limited to 100 bytes.

Request examples

These examples look up two SKUs. Omit the filter, or set the SKU array to empty, to retrieve your full assigned catalog.

cURL

# Full inventory: omit --data-urlencode.
# Specific products: include the comma-separated sku parameter.
curl --silent --show-error --fail-with-body \
  --user "$MEDIDENTA_CONSUMER_KEY:$MEDIDENTA_CONSUMER_SECRET" \
  --header "Accept: application/json" \
  --get "https://hub.medidenta.com/api/inventory.php" \
  --data-urlencode "sku=SKU-100,SKU-200"

JavaScript

// Server-side Node.js 18+; no browser credentials.
async function syncInventory() {
  const key = process.env.MEDIDENTA_CONSUMER_KEY;
  const secret = process.env.MEDIDENTA_CONSUMER_SECRET;
  if (!key || !secret) throw new Error('Configure API credentials');

  const url = new URL('https://hub.medidenta.com/api/inventory.php');
  const skus = ['SKU-100', 'SKU-200']; // Use [] for full inventory.
  if (skus.length) url.searchParams.set('sku', skus.join(','));

  const response = await fetch(url, {
    headers: {
      Authorization: 'Basic ' + Buffer.from(key + ':' + secret).toString('base64'),
      Accept: 'application/json'
    }
  });
  const data = await response.json();
  if (!response.ok) throw new Error(`HTTP ${response.status}: ${data.code}`);
  console.log(data.meta.returned_count, data.products);
}
syncInventory().catch(error => {
  console.error(error.message);
  process.exitCode = 1;
});

Python

# Python 3 standard library; no extra packages.
import os, json, base64
from urllib.request import Request, urlopen
from urllib.parse import urlencode
from urllib.error import HTTPError

key = os.environ['MEDIDENTA_CONSUMER_KEY']
secret = os.environ['MEDIDENTA_CONSUMER_SECRET']
auth = base64.b64encode(f'{key}:{secret}'.encode()).decode()
skus = ['SKU-100', 'SKU-200']  # Use [] for full inventory.
url = 'https://hub.medidenta.com/api/inventory.php'
if skus:
    url += '?' + urlencode({'sku': ','.join(skus)})
request = Request(url, headers={
    'Authorization': 'Basic ' + auth,
    'Accept': 'application/json'
})
try:
    with urlopen(request, timeout=60) as response:
        data = json.load(response)
    print(data['meta']['returned_count'], data['products'])
except HTTPError as error:
    detail = json.loads(error.read())
    raise RuntimeError(f"HTTP {error.code}: {detail.get('code')}") from error

PHP

<?php
// PHP 8+ with the cURL extension enabled.
$key = getenv('MEDIDENTA_CONSUMER_KEY');
$secret = getenv('MEDIDENTA_CONSUMER_SECRET');
if (!$key || !$secret) throw new RuntimeException('Configure API credentials');
$skus = ['SKU-100', 'SKU-200']; // Use [] for full inventory.
$url = 'https://hub.medidenta.com/api/inventory.php';
if ($skus) $url .= '?' . http_build_query(['sku' => implode(',', $skus)]);
$ch = curl_init($url);
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPAUTH => CURLAUTH_BASIC,
    CURLOPT_USERPWD => $key . ':' . $secret,
    CURLOPT_HTTPHEADER => ['Accept: application/json'],
    CURLOPT_CONNECTTIMEOUT => 10,
    CURLOPT_TIMEOUT => 60,
]);
$raw = curl_exec($ch);
if ($raw === false) throw new RuntimeException(curl_error($ch));
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
$data = json_decode($raw, true, 512, JSON_THROW_ON_ERROR);
if ($status >= 400) throw new RuntimeException('HTTP ' . $status . ': ' . $data['code']);
echo $data['meta']['returned_count'] . ' products returned';

Successful response

All languages receive the same JSON structure. This full-inventory example contains illustrative product values, not live inventory.

200 OK · full inventory
{
  "success": true,
  "meta": {
    "returned_count": 2,
    "requested_count": null,
    "not_found_count": 0,
    "ambiguous_count": 0
  },
  "products": [
    {
      "sku": "SKU-100",
      "status": "active",
      "current_stock": 25,
      "price": 19.95,
      "images": [
        "/uploads/products/example.jpg"
      ],
      "name": "Example dental supply",
      "dimensions": {
        "length": 10,
        "width": 5,
        "height": 2,
        "unit": "in"
      },
      "category": "Supplies",
      "brand": "Example Brand"
    },
    {
      "sku": "SKU-200",
      "status": "inactive",
      "current_stock": 0,
      "price": null,
      "images": [],
      "name": "Another example product",
      "dimensions": null,
      "category": null,
      "brand": null
    }
  ],
  "not_found": [],
  "ambiguous_skus": [],
  "request_timestamp": "2026-11-10T22:05:00Z"
}

Product fields

FieldTypeMeaning
skuStringProduct identifier. Use this to match your product.
statusStringactive or inactive. Inactive products remain in scoped responses.
current_stockNumberTotal quantity on hand across inventory locations and statuses. May include reserved or unavailable stock; zero when there are no balances.
priceNumber or nullCatalog selling price. Zero remains zero; an unset price is null. Currency is not included in this response.
imagesArray of stringsPrimary image first, followed by sort order. Empty array if none. Local paths resolve against https://hub.medidenta.com, not the docs host.
nameString or nullCatalog product name.
dimensionsObject or nullSingle-item dimensions: length, width, height, unit. Missing individual measurements remain null. Units are returned as stored; no conversion.
categoryString or nullCatalog category.
brandString or nullCatalog brand.

Response metadata

FieldMeaning
meta.returned_countNumber of product objects actually returned.
meta.requested_countUnique requested SKUs for a filtered lookup; null for a full sync.
meta.not_found_countNumber of requested SKUs not found or outside your scope.
meta.ambiguous_countNumber of SKUs matching multiple products, omitted rather than guessed.
not_foundRequested SKUs with no accessible match.
ambiguous_skusSKUs matching multiple products.
request_timestampServer request-start time in UTC ISO 8601 format. Not an individual product’s update time.

Sync and missing-item behavior

404 Not Found · no accessible match
{
  "success": false,
  "code": "not_found",
  "message": "No products found for the requested SKUs.",
  "meta": {
    "returned_count": 0,
    "requested_count": 1,
    "not_found_count": 1,
    "ambiguous_count": 0
  },
  "products": [],
  "not_found": [
    "UNKNOWN-SKU"
  ],
  "ambiguous_skus": [],
  "request_timestamp": "2026-11-10T22:05:00Z"
}

Other responses: 400 for invalid parameters, 401 for invalid credentials, 403 for missing Read permission, 405 for non-GET methods, and 500 for a server error. See errors and retries.