Vendor platform · CLI

From spreadsheet to marketplace.

The medgrid command line puts your catalog on MedGrid without integration code: import products, prices and stock straight from CSV exports, track approvals, and receive signed order notifications. One pip install, five commands.

terminal — a full onboarding
# install once
pip install medgrid-cli

# connect with the credentials MedGrid issued you
medgrid init
connected ✓  vendor=your-store  scope='sync'

# load your whole catalog from a spreadsheet export
medgrid import products.csv
imported: 412 succeeded, 0 failed

medgrid status --file skus.txt   # track approval

Install

Requires Python 3.9+ and nothing else — the tool has zero dependencies.

With pip (recommended)

Standard install with a standard upgrade path.

pip install medgrid-cli   # or: pipx install medgrid-cli
medgrid --version

# update later
pip install -U medgrid-cli

Without pip

The tool is a single self-contained file — download and run it with any Python 3.9+.

curl -O https://medgrid.com/assets/medgrid/cli/medgrid
python3 medgrid --help

Connect

MedGrid issues you three values per environment: a public client_id (mgk_…), a client_secret for API authentication, and a webhook_secret that signs the notifications we send you. They are shown exactly once at generation — store them securely.

medgrid init

Stores credentials in a locked-down local file (./.medgrid/config.json, mode 600), verifies them with a live connection test, and reports who you authenticate as. Access tokens are then obtained, cached and refreshed automatically — you never handle them. Failures come back in plain language: wrong environment, bad secret, profile not yet approved, locked out.

$ medgrid init
Environment [uat/prod] (uat):
client_id: mgk_1a2b3c…
client_secret: (hidden)
webhook_secret (optional): (hidden)
verifying against https://uat.medgrid.com ...
connected ✓  vendor=your-store  scope='sync'

Environments

MedGrid runs two identical copies of the platform. UAT (uat.medgrid.com) is the test environment — build and verify there first; orders never result in real shipments or charges. Production (medgrid.com) is the live marketplace. You receive UAT credentials to integrate against, and a separate production set at go-live.

Credentials belong to exactly one environment. A UAT client_id does not exist on production and vice versa — this is the most common onboarding stumble. Every command takes --env uat or --env prod; UAT is the default, and production always announces itself with a visible banner before anything runs. Not sure which environment issued the credentials you're holding? medgrid check <client_id> answers without needing the secret.

Commands

Exit codes are honest — 0 only when everything succeeded — so every command is safe to use in your own scripts and schedulers. warehouses, status and orders accept --json for machine-readable output.

Setup & connection

CommandWhat it does
medgrid initStore credentials for an environment and verify them live. Scriptable via --client-id / --client-secret / --webhook-secret; prompts otherwise.
medgrid whoami / authShow the authenticated vendor, account class, permitted scope, and session expiry. auth forces a fresh session.
medgrid check <client_id>No secret needed: asks each environment whether it issued this client_id. Each probe counts one failed attempt toward that ID's lockout.

Catalog

CommandWhat it does
medgrid warehouses [--create NAME]List your registered warehouses, or register one. Required before stock uploads.
medgrid import FILEPush a CSV of products, prices or stock — see CSV import. --dry-run validates without sending; --type overrides the filename guess.
medgrid status SKU… [--file skus.txt]Approval and publish state for up to 500 SKUs: Pending / Approved, live or not.

Orders & notifications

CommandWhat it does
medgrid ordersRecent orders containing your items, newest first (default: last 7 days; filter with --since, --status). Your safety net if your endpoint missed a notification.
medgrid webhook set-url URLRegister where MedGrid should deliver event notifications.
medgrid webhook testFire a real, signed test event at that URL right now and report how your endpoint answered.
medgrid webhook verifyOffline check that a payload you received was genuinely signed by MedGrid.
medgrid listen [--port 9876]Local test receiver: prints each incoming event with its signature verdict while you build your real endpoint. Pair with a tunnel to receive UAT deliveries on your machine.

CSV import

Headers are case-insensitive and common synonyms are understood (title → name, category → group, item_code → sku). Prices accept $ signs and thousands commas. Rows that fail validation are skipped with a line-numbered reason and are never partially sent.

TypeColumnsRequired per row
productssku vendor_product_id name description group price cost imagesku or vendor_product_id
pricessku price price_listall three — price_list is the list name MedGrid assigns you
inventorysku warehouse qty snapshot_atsku, warehouse, qty

Safe to re-run, always

Every batch carries an idempotency key derived from the file's content. Re-running the same file — after a network failure, a crash, even two runs at once — replays the original result instead of applying it twice. Never creates duplicates. Imports upsert: an existing SKU is updated, and if a SKU appears twice in one file, the later row wins.

Reviewed before public

Everything you push enters MedGrid's review queue and appears on the marketplace only when approved — track it with medgrid status. Large files are batched automatically (500 rows per request); one bad row fails that row only. Inventory snapshots are timestamped, so a stale file can never overwrite newer stock.

Order notifications

MedGrid POSTs JSON events to your registered URL: order.new, order.cancelled, product.approved, product.rejected, webhook.test. Respond with any 2xx within 10 seconds; failed deliveries retry three times (after 1, 5 and 15 minutes). If your endpoint was down longer, reconcile with medgrid orders — its payload mirrors the webhook body.

Every delivery is signed

The X-MedGrid-Signature header is HMAC-SHA256 of the exact request body, keyed with your webhook_secret. Always verify before trusting a payload:

import hashlib, hmac
expected = "sha256=" + hmac.new(
    webhook_secret.encode(), raw_body, hashlib.sha256
).hexdigest()
assert hmac.compare_digest(
    expected, headers["X-MedGrid-Signature"])

Recommended bring-up

Prove the wiring before any real order depends on it.

# 1. watch real signed events locally
medgrid listen

# 2. point MedGrid at your endpoint
medgrid webhook set-url https://you.example/events

# 3. fire a signed test at it
medgrid webhook test
delivered ✓  your endpoint answered HTTP 200

Limits

LimitDetail
120 API requests / minute / vendorExceeding it returns HTTP 429 with a Retry-After header. A full catalog import is only a handful of requests — you're unlikely to hit this outside tight polling loops.
500 records per batchThe CLI batches large files automatically. Also 500 SKUs per status call.
10 failed logins / 15 minutesLocks the client_id temporarily. Fix the secret before retrying.

Troubleshooting

SymptomMeaning / fix
this environment has never issued this client_idYour credentials belong to the other environment. medgrid check <client_id> tells you which one issued them; then pass --env accordingly.
the client_id is known here, but the client_secret is wrongRe-copy the secret (watch for whitespace), or ask MedGrid to rotate credentials.
the vendor profile is not Approved yetYour MedGrid vendor profile hasn't finished onboarding — contact your MedGrid representative.
temporarily locked outToo many failed authentications. Wait ~15 minutes; fix the secret before retrying.
Unknown price list on a prices importUse the price list name MedGrid assigned to your account.
webhook test reports your endpoint's error statusYour receiver is reachable but rejecting the request — check body parsing and that you respond 2xx.
An identical request is already in progressThe same file is being imported concurrently; the CLI waits and retries automatically.

Need more than the CLI?

Everything the tool does rides on the Vendor API — the same REST surface is yours for deeper integrations: direct sync from your systems, custom fulfillment flows, pharmacy endpoints.

Read the API reference