Introduction

Developer API Reference

Complete technical reference for all public-facing MedGrid APIs. This guide covers authentication, endpoint specifications, request/response schemas, error handling, and integration details for Shopify and ShipStation.

Scope of This Guide: This reference covers only the public-facing APIs — Catalog APIs, Integration Management APIs, Shopify (Exoceuticals) Integration, and ShipStation Integration. Internal system APIs (pharmacy connectors, logistics operations) are not documented here.

Base URLs

Production
https://app.medgrid.com
Sandbox
https://sandbox.medgrid.com

Endpoint URL Pattern

All API endpoints follow the Frappe RPC pattern:

https://app.medgrid.com/api/method/{python.module.path.function_name}

RESTful resource endpoints follow:

https://app.medgrid.com/api/resource/{DocType}/{name}

API Groups

Catalog APIs

Browse warehouses, list available inventory, search products. Used by customers and sales reps to access the MedGrid product catalog.

Integration Management APIs

Vendor self-service hub. Connect, test, sync, and disconnect ShipStation and Shopify integrations from /portal/integrations.

Shopify (Exoceuticals) APIs

Admin-level APIs for the MedGrid–Shopify store connection. OAuth installation, catalog sync, inventory sync, order creation, and inbound webhooks.

ShipStation APIs

Vendor-facing APIs that push MedGrid Sales Orders into a vendor's ShipStation queue and pull tracking numbers back automatically.

Authentication

Authentication

MedGrid supports two authentication methods. Token-based authentication is required for all server-to-server integrations.

Token Authentication (Recommended)

Every authenticated request must include the following HTTP header:

Authorization: token {api_key}:{api_secret}
Content-Type: application/json
Accept: application/json

Generate API Credentials

  1. Log in to the MedGrid Portal.
  2. Navigate to User Settings → API Access.
  3. Click Generate Keys.
  4. Copy the API Key and API Secret — the secret is shown only once.
Never expose credentials client-side. API keys must only be used on a secure server. Never include them in browser JavaScript, mobile app source code, or version control.

Session Token (Browser)

Browser-based portal users authenticate via session cookie obtained at login:

POST/api/method/login
{ "usr": "user@example.com", "pwd": "password" }

On success, a sid session cookie is set automatically for all subsequent browser requests.

Public Endpoints (No Auth)

The following endpoints accept unauthenticated requests. Each is designed to receive inbound data from external systems:

EndpointPurpose
medgrid.exoceuticals.webhookInbound Shopify webhook — HMAC-verified order updates.
medgrid.exoceuticals.oauth_callbackShopify OAuth redirect target after merchant authorises the app.
medgrid.integrations.shopify_callbackShopify OAuth redirect for vendor self-serve Shopify connections.
medgrid.contact_api.submit_contact_formWebsite contact form submission — no auth required for lead capture.
Conventions

API Conventions

Consistent patterns used across all MedGrid APIs.

HTTP Methods

MethodUsage
GETRead-only data retrieval. Parameters passed as query string.
POSTCreate, trigger, or mutate data. Body must be JSON.
PUTUpdate an existing resource entirely.
DELETERemove a resource.

Response Envelope

All RPC method responses wrap the return value in a message key:

{ "message": { ...your data... } }

REST resource responses wrap data in a data key:

{ "data": { ...document fields... } }

Dates & Times

  • Dates: YYYY-MM-DD (e.g. 2026-06-18)
  • Datetimes: YYYY-MM-DD HH:MM:SS (e.g. 2026-06-18 14:30:00)
  • All times are in UTC.

Pagination

List endpoints accept limit_start (offset) and limit_page_length (page size, default 20, max 500) parameters for pagination.

# Get items 21–40
GET /api/resource/Sales Order?limit_start=20&limit_page_length=20
Catalog API
GET

list_warehouses

Auth Required

Returns all active, non-group warehouses. Use to populate a warehouse picker.

GET /api/method/medgrid.catalog.list_warehouses

Parameters

None.

Response

{
  "message": [
    {
      "name": "ShipStation Warehouse - SM",
      "warehouse_name": "ShipStation Warehouse",
      "company": "Skydell Medical"
    }
  ]
}

Response Fields

FieldTypeDescription
namestringUnique warehouse identifier. Pass this as the warehouse param in other catalog calls.
warehouse_namestringHuman-readable display name.
companystringCompany the warehouse belongs to.
Catalog API
GET

list_warehouses_ordered

Auth Required

Returns warehouses ordered by the priority list configured in Medgrid Settings, then alphabetically. Preferred warehouses appear first.

GET /api/method/medgrid.catalog.list_warehouses_ordered

Parameters

None.

Response

{
  "message": [
    { "name": "ShipStation Warehouse - SM", "label": "ShipStation Warehouse - SM" },
    { "name": "Exoceuticals Warehouse - SM", "label": "Exoceuticals Warehouse - SM" }
  ]
}
Catalog API
GET

items_in_warehouse

Auth Required

Returns all items with actual_qty > 0 in the specified warehouse, joined with Item Price for the given price list.

GET /api/method/medgrid.catalog.items_in_warehouse

Query Parameters

ParamTypeRequiredDefaultDescription
warehousestringRequiredWarehouse name from list_warehouses.
price_liststringOptionalSelling Settings defaultPrice List to apply for the rate column.

Response

{
  "message": [
    {
      "item_code": "VD3-5000-120",
      "item_name": "Vitamin D3 5000 IU (120 Softgels)",
      "description": "High-potency Vitamin D3 supplement.",
      "stock_uom": "Box",
      "rate": 28.50,
      "available_qty": 150
    }
  ]
}

Response Fields

FieldTypeDescription
item_codestringProduct SKU — primary key used in order line items.
item_namestringDisplay name.
descriptionstringProduct description (may contain HTML).
stock_uomstringUnit of measure.
ratenumber | nullPrice from the specified price list. null if no price record exists.
available_qtynumberCurrent stock available for ordering.
Catalog API
GET

search_items

Auth Required

Full-text search across item_name and description. Returns only items with positive stock. When warehouse is supplied, results are strictly filtered to that warehouse only.

GET /api/method/medgrid.catalog.search_items

Query Parameters

ParamTypeRequiredDefaultDescription
querystringRequiredSearch string — matched as LIKE %query% against item_name and description.
warehousestringOptionalAll warehousesStrictly filters to this warehouse when provided.
price_liststringOptionalSelling Settings defaultPrice List for the rate column.

Response

{
  "message": [
    {
      "item_code": "VD3-5000-120",
      "item_name": "Vitamin D3 5000 IU (120 Softgels)",
      "description": "High-potency Vitamin D3 supplement.",
      "stock_uom": "Box",
      "rate": 28.50,
      "available_qty": 150,
      "warehouse": "ShipStation Warehouse - SM"
    }
  ]
}
When warehouse is omitted, the response includes a warehouse column per row indicating where the stock is located.
Integration API
GET

list_connections

Auth Required

Returns the integration registry plus the calling user's current connection status for each integration. Credentials are never returned — only metadata and status flags.

POST /api/method/medgrid.integrations.list_connections

Parameters

None.

Response

{
  "message": {
    "integrations": [
      {
        "id": "shipstation",
        "label": "ShipStation",
        "tagline": "Push your MedGrid orders into ShipStation, pull tracking back.",
        "auth_kind": "api_key_secret",
        "status": "connected",
        "last_sync_at": "2026-06-18 10:30:00",
        "last_error": null,
        "stats": { "orders_pushed": 12, "tracking_pulled": 8 },
        "has_credentials": true,
        "credential_keys": ["api_key", "api_secret"]
      },
      {
        "id": "shopify",
        "label": "Shopify",
        "status": "not_connected",
        "last_sync_at": null,
        "last_error": null,
        "stats": {},
        "has_credentials": false
      },
      {
        "id": "sendblue",
        "label": "SMS / iMessage support",
        "status": "connected",
        "last_sync_at": "2026-05-10 08:00:00",
        "stats": { "verified_phone": "+15551234567" }
      }
    ],
    "user": "vendor@example.com"
  }
}

Status Values

ValueMeaning
connectedCredentials saved and verified.
not_connectedNo credentials stored yet.
errorCredentials exist but last test failed.
syncingA sync operation is currently running.
Integration API
POST

connect_shipstation

Auth Required

Validates and saves ShipStation API credentials in one step. Credentials are tested against ShipStation before being persisted — if they are invalid, nothing is saved.

POST /api/method/medgrid.integrations.connect_shipstation

Request Body

FieldTypeRequiredDescription
api_keystringRequiredShipStation API Key from Account Settings → API Settings.
api_secretstringRequiredShipStation API Secret.

Request

{
  "api_key": "ss-api-key-here",
  "api_secret": "ss-api-secret-here"
}

Response — Success

{
  "message": {
    "ok": true,
    "integration": "shipstation",
    "status": "connected"
  }
}

Response — Failure

{
  "message": {
    "ok": false,
    "error": "Invalid API Key or Secret — ShipStation rejected the credentials.",
    "status": "error"
  }
}
Integration API
POST

test_connection

Auth Required

Re-tests an existing connection's stored credentials against the external service. Updates the integration status to connected or error.

POST /api/method/medgrid.integrations.test_connection

Request Body

FieldTypeRequiredDescription
integration_typestringRequiredOne of: shipstation, shopify.

Response

{ "message": { "ok": true, "error": null } }
Integration API
POST

sync_now

Auth Required

Triggers a manual full sync for the specified integration. For ShipStation: pushes up to 25 unfulfilled orders and pulls tracking for previously pushed orders. For Shopify: pulls the product catalog.

POST /api/method/medgrid.integrations.sync_now

Request Body

FieldTypeRequiredDescription
integration_typestringRequiredshipstation or shopify.

Response — ShipStation

{
  "message": {
    "ok": true,
    "stats": {
      "orders_pushed": 3,
      "tracking_pulled": 5,
      "round_trip_ok": true,
      "push_errors": [],
      "pull_errors": []
    }
  }
}

Response — Shopify

{
  "message": {
    "ok": true,
    "stats": {
      "products_pulled": 47,
      "round_trip_ok": true,
      "sample_titles": ["Product A", "Product B"]
    }
  }
}
Integration API
POST

disconnect

Auth Required

Removes stored credentials for an integration. The integration status returns to not_connected.

POST /api/method/medgrid.integrations.disconnect

Request Body

{ "integration_type": "shipstation" }

Response

{ "message": { "ok": true, "integration": "shipstation" } }
Integration API
POST

shopify_start_install

Auth Required

Generates the Shopify OAuth authorisation URL for the vendor's store. The caller opens this URL in a browser popup to begin the OAuth flow.

POST /api/method/medgrid.integrations.shopify_start_install

Request Body

FieldTypeRequiredDescription
shop_domainstringRequiredVendor's Shopify store domain. Must end in .myshopify.com.

Request

{ "shop_domain": "your-store.myshopify.com" }

Response

{
  "message": {
    "ok": true,
    "authorize_url": "https://your-store.myshopify.com/admin/oauth/authorize?client_id=...&scope=...&state=abc123",
    "state": "abc123nonce"
  }
}

Open authorize_url in a browser. After the merchant approves, Shopify calls shopify_callback automatically.

Integration API
GET

shopify_callback

Public (OAuth Redirect)

Shopify OAuth redirect target. Called automatically by Shopify after the merchant approves the connection. Exchanges the authorization code for an access token and persists the integration.

GET /api/method/medgrid.integrations.shopify_callback

This endpoint is called by Shopify — you do not call it directly. Shopify appends these query parameters automatically:

ParamProvided ByDescription
codeShopifyTemporary authorization code to exchange for an access token.
hmacShopifyHMAC-SHA256 signature of the callback URL params.
shopShopifyThe .myshopify.com shop domain.
stateShopify (echoed)The state nonce generated by shopify_start_install. Verified for CSRF protection.

Success Response

{
  "message": {
    "ok": true,
    "shop": "your-store.myshopify.com",
    "redirect": "/portal/integrations?shopify=connected"
  }
}
Shopify Integration

Shopify (Exoceuticals) Integration

MedGrid connects to the Exoceuticals Shopify store via the Shopify Admin GraphQL API (version 2026-04). This integration handles catalog sync, inventory sync, order creation, and inbound fulfillment webhooks.

Audience: These APIs are for MedGrid administrators configuring the Exoceuticals marketplace connection. They require System Manager permissions.

Configuration (System Settings)

The following fields must be configured in System Settings → API Integration → Exoceuticals before using these APIs:

Setting FieldDescriptionExample
exoceuticals_shop_domainThe Shopify store domain.2899e4.myshopify.com
exoceuticals_api_tokenAdmin API access token (obtained via OAuth callback). Stored encrypted.shpat_xxxx
exoceuticals_api_versionShopify API version to use.2026-04
exoceuticals_webhook_secretHMAC secret for verifying inbound webhooks. Set in Shopify Admin → Notifications → Webhooks.Random string
exoceuticals_order_tagTag applied to every order created in Shopify. Identifies MedGrid orders.Skydell
exoceuticals_location_idDefault Shopify fulfillment location GID.gid://shopify/Location/12345

Item-Level Mapping Fields

These custom fields are added to the Item DocType to link MedGrid items with Shopify variants:

Item FieldDescription
exoceuticals_product_idShopify Product GID (populated by sync_catalog).
exoceuticals_variant_idShopify ProductVariant GID. Required to place orders via sync_to_exoceuticals.
exoceuticals_inventory_item_idShopify InventoryItem GID. Required for sync_inventory.
exoceuticals_qtyLast-known inventory quantity mirrored from Shopify.
exoceuticals_last_syncedTimestamp of last successful sync for this item.
Shopify
GET

oauth_install_url

Auth Required

Builds the Shopify install URL for the Exoceuticals Custom App OAuth flow. Admin opens this URL in a browser to authorise the connection.

POST /api/method/medgrid.exoceuticals.oauth_install_url

Parameters

ParamTypeRequiredDescription
shopstringOptionalOverride shop domain. Defaults to exoceuticals_shop_domain in System Settings.

Response

{
  "message": {
    "install_url": "https://2899e4.myshopify.com/admin/oauth/authorize?client_id=...&scope=...&state=...",
    "shop": "2899e4.myshopify.com",
    "redirect_uri": "https://app.medgrid.com/api/method/medgrid.exoceuticals.oauth_callback"
  }
}
Shopify
GET

oauth_callback

Public (OAuth Redirect)

Shopify redirects here after the merchant authorises the app. Verifies the HMAC, exchanges the code for an Admin API access token, and persists it in System Settings.

GET /api/method/medgrid.exoceuticals.oauth_callback

Called automatically by Shopify. Verifies: (1) .myshopify.com domain, (2) state nonce, (3) HMAC-SHA256 signature across all query params.

Success Response

{
  "status": "success",
  "shop": "2899e4.myshopify.com",
  "scope": "read_products,write_products,read_orders,write_orders,read_inventory,write_inventory",
  "message": "Exoceuticals connected. You can close this tab."
}

Error Response

{
  "status": "error",
  "message": "HMAC verification failed."
}
Shopify
POST

sync_catalog

Auth Required

Pulls all products and variants from Shopify and writes their GIDs onto matching MedGrid Items (matched by SKU). Does NOT auto-create Items — catalog membership is curated, not auto-imported.

POST /api/method/medgrid.exoceuticals.sync_catalog

Parameters

None.

Response

{
  "message": {
    "status": "ok",
    "matched": 142,
    "unmatched_count": 3
  }
}

Response Fields

FieldDescription
matchedNumber of Shopify variants successfully linked to MedGrid Items by SKU.
unmatched_countNumber of Shopify variants whose SKU did not match any MedGrid Item. These are logged for review.
Shopify
POST

sync_inventory

Auth Required

Refreshes inventory quantities from Shopify for all Items that have an exoceuticals_inventory_item_id set. Also mirrors quantities into the Exoceuticals warehouse Bin records.

POST /api/method/medgrid.exoceuticals.sync_inventory

Response

{
  "message": {
    "status": "ok",
    "updated": 138,
    "warehouse": "Exoceuticals Warehouse - SM"
  }
}
Shopify
POST

sync_to_exoceuticals

Auth Required

Creates a Shopify order from a submitted MedGrid Sales Order. Tags the order "Skydell" per Exoceuticals' requirements. Can only be called once per Sales Order (idempotent guard).

POST /api/method/medgrid.exoceuticals.sync_to_exoceuticals

Request Body

FieldTypeRequiredDescription
sales_orderstringRequiredMedGrid Sales Order name (e.g. SAL-2026-00123). Must be submitted (docstatus=1).
line_itemsarrayOptionalList of SO item row names to include. If omitted, all eligible lines are included.

Request

{ "sales_order": "SAL-2026-00123" }

Response

{
  "message": {
    "status": "success",
    "exoceuticals_order_id": "gid://shopify/Order/4567890123",
    "exoceuticals_order_name": "#1042"
  }
}

Prerequisites

  • Sales Order must be submitted (docstatus = 1).
  • Order must not already have an exoceuticals_order_id.
  • At least one line item must have exoceuticals_variant_id set on the Item — run sync_catalog first.
  • Sales Order must have a valid shipping address.
Shopify
POST

poll_exoceuticals_status

Auth Required

Queries Shopify for the current fulfillment status of a previously synced order and updates the Sales Order fields accordingly. Used as belt-and-suspenders alongside webhooks.

POST /api/method/medgrid.exoceuticals.poll_exoceuticals_status

Request

{ "sales_order": "SAL-2026-00123" }

Response

{ "message": "Fulfilled" }

Returns the new exoceuticals_status string. Also updates exoceuticals_tracking_number, exoceuticals_carrier, and exoceuticals_tracking_url on the Sales Order if shipping data is available.

Webhook
POST

exoceuticals webhook

Public (HMAC-Verified)

Inbound webhook endpoint for Shopify order updates. Register this URL in Shopify Admin → Settings → Notifications → Webhooks for the topics listed below.

POST /api/method/medgrid.exoceuticals.webhook

Required Headers (sent by Shopify)

HeaderValuePurpose
X-Shopify-Hmac-Sha256Base64-encoded HMAC-SHA256Signature verification. Computed over the raw request body using the webhook secret.
X-Shopify-Topice.g. orders/fulfilledThe event topic that triggered this webhook.
Content-Typeapplication/jsonShopify always sends JSON.

Supported Topics

TopicMedGrid Action
orders/updatedRe-evaluates order status; updates exoceuticals_status field on the Sales Order.
orders/fulfilledSets status to Fulfilled; writes tracking number, carrier, and tracking URL from fulfillment data.
orders/cancelledSets status to Cancelled on the matched Sales Order.

Example Payload (orders/fulfilled)

{
  "id": 4567890123,
  "fulfillment_status": "fulfilled",
  "cancelled_at": null,
  "fulfillments": [
    {
      "tracking_number": "1Z999AA10123456784",
      "tracking_company": "UPS",
      "tracking_urls": ["https://ups.com/track?number=1Z999AA10123456784"]
    }
  ]
}

Response

{
  "message": {
    "status": "ok",
    "topic": "orders/fulfilled",
    "sales_order": "SAL-2026-00123"
  }
}
HMAC Verification is Mandatory. Every webhook request is verified using HMAC-SHA256. Requests that fail verification are immediately rejected with HTTP 401 and the event is logged.
ShipStation Integration

ShipStation Integration

The ShipStation integration enables vendors to receive MedGrid Sales Orders in their ShipStation account and automatically synchronise tracking numbers back to MedGrid.

Authentication

ShipStation uses HTTP Basic Auth. MedGrid constructs the header internally from the vendor's stored credentials:

Authorization: Basic BASE64(api_key:api_secret)

Integration Flow

StepDirectionAPI CallDescription
1MedGrid → ShipStationGET /accounts/listtagsAuth probe — confirms credentials are valid before any data is sent.
2MedGrid → ShipStationPOST /orders/createorderPushes each eligible Sales Order as a new ShipStation order.
3ShipStation → MedGridGET /shipments?orderId={id}MedGrid queries ShipStation for tracking info on previously pushed orders.
4InternalMedGrid DB writeTracking number and carrier are written to Delivery Note.lr_no and transporter.
ShipStation

Order Push to ShipStation

When sync_now is called for ShipStation, MedGrid queries for submitted Sales Orders whose items' default_supplier matches the calling vendor and that have not yet been pushed (shipstation_order_id is empty).

Order Payload Structure

MedGrid sends this payload to POST https://ssapi.shipstation.com/orders/createorder:

{
  "orderNumber":   "SAL-2026-00123",
  "orderKey":      "SAL-2026-00123",
  "orderDate":     "2026-06-18",
  "orderStatus":   "awaiting_shipment",
  "customerEmail": "customer@example.com",
  "amountPaid":    91.00,
  "items": [
    {
      "lineItemKey": "row-id-1",
      "sku":         "VD3-5000-120",
      "name":        "Vitamin D3 5000 IU (120 Softgels)",
      "quantity":    2,
      "unitPrice":   28.50
    }
  ]
}

On success, ShipStation returns an orderId which MedGrid stores in Sales Order.shipstation_order_id to track the push.

Multi-Vendor Order Splitting

When a Sales Order contains items from multiple vendors, only the calling vendor's line items are included in the ShipStation payload. Items belonging to other vendors are pushed separately by those vendors on their own sync.

ShipStation

Tracking Number Pull

During each sync, MedGrid queries ShipStation for shipments on previously pushed orders and writes tracking info to the corresponding Delivery Note.

How Tracking Pull Works

  1. MedGrid queries all Sales Orders with a non-empty shipstation_order_id.
  2. For each, it calls GET https://ssapi.shipstation.com/shipments?orderId={shipstation_order_id}.
  3. For any shipment with a trackingNumber, MedGrid finds the linked Delivery Note and sets:
    • Delivery Note.lr_no = tracking number
    • Delivery Note.transporter = carrier code (uppercase)
// ShipStation shipment response (excerpt)
{
  "shipments": [
    {
      "trackingNumber": "1Z999AA10123456784",
      "carrierCode": "ups",
      "shipDate": "2026-06-19"
    }
  ]
}
Reference

Data Models

Key data structures returned by MedGrid APIs.

Integration Connection Object

{
  "id": "shipstation",
  "label": "ShipStation",
  "tagline": "Push your MedGrid orders into ShipStation, pull tracking back.",
  "auth_kind": "api_key_secret",
  "status": "connected",
  "last_sync_at": "2026-06-18 10:30:00",
  "last_error": null,
  "stats": {
    "orders_pushed": 12,
    "tracking_pulled": 8
  },
  "has_credentials": true,
  "credential_keys": ["api_key", "api_secret"],
  "permits": ["orders.write", "tracking.read"],
  "what_we_push": ["MedGrid Sales Orders (line items, ship-to address, weight)"],
  "what_we_pull": ["Tracking numbers", "Carrier + service", "Ship date"]
}

Catalog Item Object

{
  "item_code": "VD3-5000-120",
  "item_name": "Vitamin D3 5000 IU (120 Softgels)",
  "description": "High-potency Vitamin D3 supplement.",
  "stock_uom": "Box",
  "rate": 28.50,
  "available_qty": 150,
  "warehouse": "ShipStation Warehouse - SM"
}

Sales Order Status Fields (Exoceuticals)

{
  "exoceuticals_order_id":       "gid://shopify/Order/4567890123",
  "exoceuticals_order_name":     "#1042",
  "exoceuticals_status":         "Fulfilled",
  "exoceuticals_tracking_number": "1Z999AA10123456784",
  "exoceuticals_carrier":        "UPS",
  "exoceuticals_tracking_url":   "https://ups.com/track?number=1Z999AA10123456784",
  "exoceuticals_sync_date":      "2026-06-18 14:00:00"
}
Reference

Error Reference

Complete reference of HTTP status codes, error response formats, and integration-specific error codes.

Standard MedGrid Error Response

{
  "exc_type": "ValidationError",
  "exception": "frappe.exceptions.ValidationError: Both API Key and API Secret are required.",
  "_server_messages": "[{\"message\": \"Both API Key and API Secret are required.\"}]"
}

HTTP Status Code Reference

CodeMeaningCommon CauseResolution
200SuccessRequest completed. Check message.ok for integration-level success flags.
400Bad RequestMissing/invalid field.Read _server_messages for the specific validation error.
401UnauthenticatedMissing or malformed Authorization header.Verify format: Authorization: token KEY:SECRET.
403ForbiddenRole lacks permission, or endpoint requires a higher-level role (e.g. System Manager).Contact MedGrid to confirm role assignment.
404Not FoundWrong DocType name, wrong document ID, or typo in endpoint URL.Double-check the endpoint path and document name.
409ConflictOrder already synced to the external system.Do not resubmit — check the existing external order instead.
417Expectation FailedBusiness rule violation (e.g. SO not submitted, missing variant ID).Read _server_messages for the specific condition that needs to be met.
429Rate LimitedToo many requests (ShipStation: 40/min; Shopify: cost-bucket).Implement exponential backoff. MedGrid handles retries automatically on internal calls.
500Server ErrorUnhandled exception on MedGrid's side.Report to MedGrid support with timestamp, endpoint, and full error text.

Integration-Specific Error Codes

IntegrationError IndicatorMeaningFix
ShipStationHTTP 401 from ShipStationInvalid API Key/Secret.Regenerate ShipStation credentials and reconnect via connect_shipstation.
ShipStationHTTP 429 from ShipStationRate limit hit (40 req/min).MedGrid retries automatically with backoff. No action needed unless persistent.
ShopifyuserErrors array in 200 responseGraphQL mutation rejected (e.g. invalid variant GID, out-of-stock).Check userErrors[].field and userErrors[].message for details.
Shopify OAuth"HMAC verification failed"Callback request did not originate from Shopify.Ensure webhook secret matches what Shopify has configured.
Shopify OAuth"OAuth state expired or invalid"State nonce expired (10-minute window) or already used.Restart the install flow — generate a new authorize_url.
ShopifyHTTP 401 on test_connectionAccess token revoked in Shopify.Disconnect and reconnect via OAuth to get a fresh token.
ShopifyHTTP 402Shopify store is frozen or past due on payment.Merchant must update their Shopify billing before the API will respond.

Webhook Error Response

{
  "status": "error",
  "code": "INVALID_TOKEN",
  "message": "Authentication failed"
}
Reference

Rate Limits & Best Practices

Rate limits prevent API overload. MedGrid manages all external rate limits automatically.

MedGrid API Rate Limits

MedGrid does not enforce a hard rate limit on authenticated API calls from customers and vendors. Burst traffic may be throttled server-side. Implement exponential backoff for any 429 or 5xx response.

External System Rate Limits

SystemLimitMedGrid Handling
ShipStation40 requests/minute per API key pair.HTTP 429 triggers exponential backoff, up to 3 retries, before failing the sync with an error.
Shopify (GraphQL)50 query cost units/second (leaky bucket). Mutations cost more than queries.MedGrid batches GraphQL calls to stay within the cost budget. Sync jobs process in chunks of 100 items.

Performance Best Practices

  • Cache list_warehouses results — warehouses change infrequently (safe to cache for 15 minutes).
  • Use webhooks for order status updates instead of polling poll_exoceuticals_status continuously.
  • Always develop and test against the Sandbox environment before switching to Production.
  • Implement exponential backoff in your own code for any 429 or 500 response from MedGrid.
  • Keep sync_catalog as a scheduled daily job rather than calling it on every order.