{"templateId":"api_docs","sharedDataIds":{"apiDocsStore":"api-docs-Merchant API v1/mapi_v1_oas31.yaml","sidebar":"sidebar-sidebars.yaml"},"props":{"definitionId":"Merchant API v1/mapi_v1_oas31.yaml","settings":{"baseUrlPath":"/merchant-api-v1/mapi_v1_oas31"},"disableAutoScroll":true,"seo":{"title":"Merchant API v1","llmstxt":{"hide":true}},"dynamicMarkdocComponents":[],"metadata":{"type":"openapi","title":"Merchant API v1","version":"1.0.0","description":"The Merchant API lets merchants integrate their own systems, such as a store or an ERP for which Hive has no native integration, with Hive.\n\nYou can create SKUs and orders, and read back the fulfillment and delivery status of orders. You can also work with other parts of Hive's warehouse management: restocking shipments, returns and warehouses.\n\nThe API does not give access to all the data and features of the Hive app. An access token belongs to one sales channel (shop): SKUs, orders and shipments are scoped to that shop, while restocking shipments, returns and warehouses are scoped to the merchant that owns it. If your platform is listed in [Hive's integration list](https://www.hive.app/product/integrations), you do not need this API.\n\n## Versioning\nThis is version 1 of the Merchant API. It stays available for existing integrations but is frozen: new features are only added to v2, and new integrations should use v2. The same access tokens work for both versions.\n\n## Access tokens\nEvery request must be authenticated with an API access token, sent as a bearer token in the `Authorization` header:\n\n```\nAuthorization: Bearer your_api_token\n```\n\nAsk your account manager for a token. The production domain is `https://app.hive.app`, the staging domain is `https://staging.app.hive.app`.\n\nA missing or unknown token is answered with `401 Unauthorized`. A token that has expired, or whose sales channel is no longer active, is answered with `403 Forbidden`.\n\n## Requests\nRequest bodies are JSON. Every request to v1 is read as JSON, whatever its `Content-Type` header says, but sending `Content-Type: application/json` is recommended. A body that is not valid JSON is answered with `400 Bad Request`. Numeric properties of a request body also accept numeric strings, such as `\"42000\"`, and a number sent for a string property is stored as its text.\n\nEndpoints that take a whole resource (creating or updating an order, creating a SKU, and each item of a SKU bulk upsert) reject properties they do not know with `422 Unprocessable Entity`; the properties they accept but ignore are listed as such. The other endpoints ignore unknown properties.\n\n## Errors\nA failed request answers with a `4xx` status code and a JSON body whose `errors` property is an array of human-readable messages:\n\n```json\n{\n  \"success\": false,\n  \"errors\": [\"Name can't be blank\", \"Merchant sku can't be blank\"]\n}\n```\n\nThe common cases are `400` for a malformed request, `401` and `403` for authentication problems, `404` when the requested record does not exist or does not belong to you, `409` when a record with the same data already exists, `422` when the data is invalid, and `429` when the rate limit is exceeded.\n\n## Pagination\nList endpoints, except `GET /warehouses`, are paginated. The response is an object with the records in `data` and the page information in `pagination`:\n\n```json\n{\n  \"data\": [],\n  \"pagination\": {\n    \"current_page\": 1,\n    \"item_count\": 2,\n    \"page_count\": 1,\n    \"items_per_page\": 20\n  }\n}\n```\n\nPass `page` to choose a page (it starts at 1, the default) and `limit` to choose the page size (default 20). A `limit` above 100 is treated as 100. A `page` past the last one returns an empty `data` array. `pagination.page_count` tells how many pages there are.\n\nMost list endpoints also accept `created_at[gt]`, `created_at[gte]`, `created_at[lt]` and `created_at[lte]` to filter by creation time, as ISO 8601 date-times.\n\n## Rate Limiting\nRequests are rate limited per sales channel, by default to 100 requests per calendar minute (UTC). If you have a valid use case for a higher limit, contact your account manager. Real-time updates are available through webhooks, so frequent polling should not be necessary.\n\nResponses carry two headers with the current usage:\n\n```\nX-Rate-Limit-Used: 42\nX-Rate-Limit-Max: 100\n```\n\nRequests over the limit are answered with `429 Too Many Requests` and a `Retry-After` header giving the number of seconds until the next minute starts, for example `Retry-After: 3.2`.\n\n## Webhooks\nWebhooks notify you of events as they happen, for example when the delivery status of a shipment changes. Hive sends an HTTP `POST` request with a JSON body to the URL you registered for the event. To set up webhooks, give your account manager the URL for each event you want to receive.\n\nv1 webhooks are separate from v2 webhooks: a URL registered for v1 receives the v1 events below, whose body is the bare v1 resource (the same object the v1 endpoints return), with no envelope around it. See the `webhooks` section below for each event and its payload.\n\n- `delivery_status_updated`: the carrier delivery status of a shipment changed. The payload is a Shipment.\n- `shipment_status_updated`: the fulfillment status of a shipment changed. The payload is a Shipment.\n- `restocking_shipment_status_updated`: the status of a restocking shipment changed. The payload is a RestockingShipment.\n- `return_status_updated`: the status of a return changed. The payload is a Return.\n\nAnswer with a `2xx` status to acknowledge a webhook; Hive does not follow redirects, and any status below `400` counts as received. Hive waits 5 seconds for the answer. A timeout, a connection failure or a `5xx` status is retried with growing intervals, up to 12 attempts over about 11 to 13 hours; `429` answers are retried the same way, counted separately. Any other `4xx` status is treated as a rejection of the payload and is not retried.\n\n### Webhook Security\nHive signs each webhook request with an `x-hive-signature` header whenever the sales channel has a valid API token (without one, the header is left out): the hex-encoded HMAC-SHA256 digest of the request body, keyed with your API token. If the sales channel has several valid tokens, the oldest one is the key. Ignore requests without this header or whose signature does not match.\n\n```ruby\ndef request_valid?(req) # req is a Rack::Request\n  return false if !req.post?\n  request_sig = req.get_header(\"HTTP_X_HIVE_SIGNATURE\")\n  expected_sig = OpenSSL::HMAC.hexdigest(\"sha256\", ENV[\"API_TOKEN\"], req.body.read)\n  Rack::Utils.secure_compare(request_sig.to_s, expected_sig)\nend\n```\n\n### Webhook Reliability\nWebhook handlers should be idempotent. Hive does not guarantee the order of the calls, and a retried call carries the same payload again. Each request has an `x-hive-event-id` header, which stays the same across the retries of one call. Compare the timestamps in the payload with the last update you stored, and ignore a payload older than what you have.\n"},"compilationErrors":[],"markdown":{"partials":{},"variables":{"rbac":{"teams":["anonymous"]},"user":{},"remoteAddr":{"hostname":"developers.hive.app","port":4000,"ipAddress":"216.73.217.122"},"lang":"default_locale","env":{"PUBLIC_REDOCLY_BRANCH_NAME":"main"}}},"pagePropGetterError":{"message":"","name":""}},"slug":"/merchant-api-v1/mapi_v1_oas31","userData":{"isAuthenticated":false,"teams":["anonymous"]},"isPublic":true}