# Management Store Etsy Public API — Full Reference REST API for Etsy shop and order data, including manual fulfillment updates. Authenticate with Bearer API keys (mse_ prefix). ## Overview - v1 exposes GET endpoints (list/get orders, list shops) and write endpoints for manual fulfillment (PATCH/DELETE). Keys are created in the web app under Settings → API access. - Default key scopes are orders:read and shops:read. Opt in to orders:write when creating a key to update or cancel manual fulfillment. - Each API key is tenant-scoped: it can only access shops linked to the license keys owned by the key creator. - ROOT/ADMIN users do not get system-wide access via API keys — only license-owned shops apply. - List endpoints accept multiple query parameters at once (filters combine with AND). - Orders: shopEtsyId accepts multiple shops: repeat ?shopEtsyId=a&shopEtsyId=b or comma-separated ?shopEtsyId=a,b. Alias query key: shop. - Never log or commit raw API keys. Use environment variables or secret managers in production integrations. ## Authentication - Header: `Authorization: Bearer mse_` - Key prefix: `mse_` ## Response formats - List responses use { data: T[], pagination: { page, limit, total, totalPages } }. - Single-resource responses use { data: T } (no pagination). - Errors return { error: string, code?: string } with appropriate HTTP status. Rate limit: 60 requests per 60 seconds per API key. ## Links - OpenAPI: https://etsy.lntech-ecommerce.com/openapi.json - Index: https://etsy.lntech-ecommerce.com/llms.txt - Explorer: https://etsy.lntech-ecommerce.com/developers ## Endpoints ## GET /api/v1/orders **Operation ID:** `listOrders` **Scope:** `orders:read` **Group:** Orders Returns a paginated list of orders for shops accessible to your API key. Combine filters (shops, dates, search, fulfillment, tracking, sort). Requires the orders:read scope. ### Path parameters _None._ ### Query parameters | Name | Type | Required | Default | Description | |------|------|----------|---------|-------------| | page | number | no | 1 | Page number (1-based). Default: 1. | | limit | number | no | 20 | Items per page (max 100). Default: 20. | | shopEtsyId | string[] | no | | Filter one or more shops by Etsy shop ID (shopEtsyId from the response). Add multiple IDs below or use comma-separated values. Omit for all accessible shops. | | search | string | no | | Search order ID, recipient name, or address fields. | | startDate | date | no | | Inclusive start date (YYYY-MM-DD) for orderDate filter. | | endDate | date | no | | Inclusive end date (YYYY-MM-DD) for orderDate filter. | | timeZone | string | no | Asia/Bangkok | IANA time zone for date filters. Default: Asia/Bangkok. | | fulfillmentStatus | string | no | | Filter by fulfillment: fulfilled, synced_to_provider, manual, pending, or failed. | | tracking | string | no | | Filter by tracking: has (with tracking number) or none. | | sortBy | string | no | orderDate | Sort field: orderDate, orderId, recipientName, totalCost, or shop. Default: orderDate. | | sortOrder | string | no | desc | asc or desc. Default: desc. | ### Example request ```bash curl -sS -X GET \ -H 'Authorization: Bearer mse_YOUR_API_KEY' \ -H 'Accept: application/json' \ 'https://etsy.lntech-ecommerce.com/api/v1/orders?page=1&limit=20' ``` ### Example response ```json { "data": [ { "id": "clx000000000000000000000001", "shopId": "clx000000000000000000000002", "orderId": "1234567890", "orderDate": "2026-07-31T10:00:00.000Z", "totalCostFormatted": "$24.99", "currencyCode": "USD", "shop": { "id": "clx000000000000000000000002", "shopName": "My Etsy Shop", "shopEtsyId": "12345" }, "items": [] } ], "pagination": { "page": 1, "limit": 20, "total": 1, "totalPages": 1 } } ``` ### Errors - **401** (`MISSING_API_KEY`): Missing or invalid API key. - **401** (`INVALID_API_KEY`): Missing or invalid API key. - **400** (`INVALID_QUERY_PARAM`): One or more query parameters are invalid. - **400** (`INVALID_DATE_FORMAT`): Date query parameters must use YYYY-MM-DD. - **403** (`FORBIDDEN_SHOP`): One or more Etsy shop IDs are not accessible for this key. - **429** (`RATE_LIMITED`): Too many requests. Retry after the Retry-After header value. ## GET /api/v1/orders/{id} **Operation ID:** `getOrder` **Scope:** `orders:read` **Group:** Orders Returns a single order by its internal UUID (`id` from the list response), including line items and shop summary. The order must belong to a shop accessible to your API key. Requires the orders:read scope. ### Path parameters | Name | Type | Required | Default | Description | |------|------|----------|---------|-------------| | id | string | yes | | Internal order UUID from the list response `id` field (not the Etsy receipt / orderId). | ### Query parameters _None._ ### Example request ```bash curl -sS -X GET \ -H 'Authorization: Bearer mse_YOUR_API_KEY' \ -H 'Accept: application/json' \ 'https://etsy.lntech-ecommerce.com/api/v1/orders/clx000000000000000000000001' ``` ### Example response ```json { "data": { "id": "clx000000000000000000000001", "shopId": "clx000000000000000000000002", "orderId": "1234567890", "orderDate": "2026-07-31T10:00:00.000Z", "orderUrl": null, "totalCost": 24.99, "totalCostFormatted": "$24.99", "totalBaseCost": null, "baseCostUpdatedAt": null, "currencyCode": "USD", "itemsCost": 24.99, "shippingCost": 0, "taxCost": 0, "discount": 0, "recipientName": "Jane Doe", "recipientEmail": null, "recipientPhone": null, "addressLine1": "123 Main St", "addressLine2": null, "city": "Austin", "state": "TX", "zip": "78701", "country": "US", "noteFromBuyer": null, "expectedShipDate": null, "paymentDate": "2026-07-31T10:00:00.000Z", "shippingMethod": null, "hasTracking": false, "fulfillmentProviderType": null, "providerStatus": null, "lenfulSyncStatus": "PENDING", "merchizeSyncStatus": "PENDING", "mangoteeSyncStatus": "PENDING", "burgerPrintsSyncStatus": "PENDING", "syncedAt": "2026-07-31T10:05:00.000Z", "createdAt": "2026-07-31T10:05:00.000Z", "updatedAt": "2026-07-31T10:05:00.000Z", "shop": { "id": "clx000000000000000000000002", "shopName": "My Etsy Shop", "shopEtsyId": "12345" }, "items": [] } } ``` ### Errors - **401** (`MISSING_API_KEY`): Missing or invalid API key. - **401** (`INVALID_API_KEY`): Missing or invalid API key. - **404** (`ORDER_NOT_FOUND`): Order not found, or not accessible with this API key. - **429** (`RATE_LIMITED`): Too many requests. Retry after the Retry-After header value. ## POST /api/v1/orders/{id}/manual-fulfillment **Operation ID:** `markManualFulfillment` **Scope:** `orders:write` **Group:** Orders Marks an order as manually fulfilled (`fulfillmentProviderType` = manual). Idempotent if already manual. Fails with 409 if the order is already synced to a real fulfillment provider. Optional tracking (`trackingNumber`, `trackingCompany`, `trackingUrl`) may be set only in this request — there is no separate public API to update tracking later. Requires the orders:write scope. ### Path parameters | Name | Type | Required | Default | Description | |------|------|----------|---------|-------------| | id | string | yes | | Internal order UUID from the list response `id` field (not the Etsy receipt / orderId). | ### Query parameters _None._ ### Request body | Name | Type | Required | Description | |------|------|----------|-------------| | trackingNumber | string | no | Carrier tracking number (optional). Omit or send an empty string for no tracking number. | | trackingCompany | string | no | Carrier / company name (optional). | | trackingUrl | string | no | Public tracking URL (optional). Must be a valid URL when provided. | ### Example request ```bash curl -sS -X POST \ -H 'Authorization: Bearer mse_YOUR_API_KEY' \ -H 'Accept: application/json' \ -H 'Content-Type: application/json' \ --data-raw '{"trackingNumber":"1Z999AA10123456784","trackingCompany":"UPS","trackingUrl":"https://www.ups.com/track?tracknum=1Z999AA10123456784"}' \ 'https://etsy.lntech-ecommerce.com/api/v1/orders/clx000000000000000000000001/manual-fulfillment' ``` ### Example response ```json { "data": { "id": "clx000000000000000000000001", "fulfillmentProviderType": "manual", "hasTracking": false, "tracking": null, "updatedAt": "2026-08-04T10:00:00.000Z" } } ``` ### Errors - **401** (`MISSING_API_KEY`): Missing or invalid API key. - **401** (`INVALID_API_KEY`): Missing or invalid API key. - **400** (`VALIDATION_ERROR`): Request body failed validation. - **403** (`INSUFFICIENT_SCOPE`): API key is missing a required scope for this operation. - **404** (`ORDER_NOT_FOUND`): Order not found, or not accessible with this API key. - **409** (`ALREADY_SYNCED_TO_PROVIDER`): Order is already synced to a real fulfillment provider and cannot be marked as manual. - **429** (`RATE_LIMITED`): Too many requests. Retry after the Retry-After header value. ## DELETE /api/v1/orders/{id}/manual-fulfillment **Operation ID:** `cancelManualFulfillment` **Scope:** `orders:write` **Group:** Orders Removes manual fulfillment from an order (inverse of mark): clears `fulfillmentProviderType`, deletes stored manual tracking, and recomputes `hasTracking`. Requires the orders:write scope. The order must already be manually fulfilled. ### Path parameters | Name | Type | Required | Default | Description | |------|------|----------|---------|-------------| | id | string | yes | | Internal order UUID from the list response `id` field (not the Etsy receipt / orderId). | ### Query parameters _None._ ### Example request ```bash curl -sS -X DELETE \ -H 'Authorization: Bearer mse_YOUR_API_KEY' \ -H 'Accept: application/json' \ 'https://etsy.lntech-ecommerce.com/api/v1/orders/clx000000000000000000000001/manual-fulfillment' ``` ### Example response ```json { "data": { "id": "clx000000000000000000000001", "fulfillmentProviderType": null, "hasTracking": false, "updatedAt": "2026-08-03T10:00:00.000Z" } } ``` ### Errors - **401** (`MISSING_API_KEY`): Missing or invalid API key. - **401** (`INVALID_API_KEY`): Missing or invalid API key. - **403** (`INSUFFICIENT_SCOPE`): API key is missing a required scope for this operation. - **404** (`ORDER_NOT_FOUND`): Order not found, or not accessible with this API key. - **409** (`NOT_MANUAL_FULFILLMENT`): Order is not currently manually fulfilled. - **429** (`RATE_LIMITED`): Too many requests. Retry after the Retry-After header value. ## PATCH /api/v1/orders/{id}/base-cost **Operation ID:** `updateOrderBaseCost` **Scope:** `orders:write` **Group:** Orders Sets or clears the internal cost of goods (`totalBaseCost`) for an order. Pass a non-negative number in dollars, or `null` to clear. Also updates `baseCostUpdatedAt`. Requires the orders:write scope. The order must belong to a shop accessible to your API key. ### Path parameters | Name | Type | Required | Default | Description | |------|------|----------|---------|-------------| | id | string | yes | | Internal order UUID from the list response `id` field (not the Etsy receipt / orderId). | ### Query parameters _None._ ### Request body | Name | Type | Required | Description | |------|------|----------|-------------| | totalBaseCost | number or null | yes | Internal cost of goods in dollars (non-negative number), or null to clear. | ### Example request ```bash curl -sS -X PATCH \ -H 'Authorization: Bearer mse_YOUR_API_KEY' \ -H 'Accept: application/json' \ -H 'Content-Type: application/json' \ --data-raw '{"totalBaseCost":22}' \ 'https://etsy.lntech-ecommerce.com/api/v1/orders/clx000000000000000000000001/base-cost' ``` ### Example response ```json { "data": { "id": "clx000000000000000000000001", "totalBaseCost": 22, "baseCostUpdatedAt": "2026-08-04T08:00:00.000Z", "updatedAt": "2026-08-04T08:00:01.000Z" } } ``` ### Errors - **401** (`MISSING_API_KEY`): Missing or invalid API key. - **401** (`INVALID_API_KEY`): Missing or invalid API key. - **400** (`VALIDATION_ERROR`): Request body failed validation. - **403** (`INSUFFICIENT_SCOPE`): API key is missing a required scope for this operation. - **404** (`ORDER_NOT_FOUND`): Order not found, or not accessible with this API key. - **429** (`RATE_LIMITED`): Too many requests. Retry after the Retry-After header value. ## GET /api/v1/shops **Operation ID:** `listShops` **Scope:** `shops:read` **Group:** Shops Returns a paginated list of shops accessible to your API key. Filter by status or search by name / Etsy shop ID. Requires the shops:read scope. ### Path parameters _None._ ### Query parameters | Name | Type | Required | Default | Description | |------|------|----------|---------|-------------| | page | number | no | 1 | Page number (1-based). Default: 1. | | limit | number | no | 20 | Items per page (max 100). Default: 20. | | search | string | no | | Search by shop name or Etsy shop ID. | | status | string | no | | Filter by shop status: ACTIVE only (API keys only access active shops). | | sortBy | string | no | shopName | Sort field: shopName, shopEtsyId, lastSyncAt, or createdAt. Default: shopName. | | sortOrder | string | no | asc | asc or desc. Default: asc. | ### Example request ```bash curl -sS -X GET \ -H 'Authorization: Bearer mse_YOUR_API_KEY' \ -H 'Accept: application/json' \ 'https://etsy.lntech-ecommerce.com/api/v1/shops?page=1&limit=20' ``` ### Example response ```json { "data": [ { "id": "clx000000000000000000000002", "shopName": "My Etsy Shop", "shopEtsyId": "12345", "avatar": null, "status": "ACTIVE", "syncStatus": "success", "lastSyncAt": "2026-07-31T10:00:00.000Z", "createdAt": "2026-01-15T08:00:00.000Z", "updatedAt": "2026-07-31T10:00:00.000Z" } ], "pagination": { "page": 1, "limit": 20, "total": 1, "totalPages": 1 } } ``` ### Errors - **401** (`MISSING_API_KEY`): Missing or invalid API key. - **401** (`INVALID_API_KEY`): Missing or invalid API key. - **400** (`INVALID_QUERY_PARAM`): One or more query parameters are invalid. - **429** (`RATE_LIMITED`): Too many requests. Retry after the Retry-After header value. ## Agent instructions - Prefer machine-readable docs: /llms.txt (index), /llms-full.txt (full reference), /openapi.json (schema). - Always send Authorization: Bearer and Accept: application/json. - Respect 429 responses and Retry-After header. - Do not scrape the React /developers UI when structured docs are available.