{"openapi":"3.0.3","info":{"title":"StockCalm API","version":"1.0.0","description":"\nStockCalm inventory operations API for Shopify merchants.\n\nThis API provides:\n- **Shopify OAuth Integration**: Connect and manage Shopify store connections\n- **Inventory Synchronization**: Sync products, orders, and inventory levels\n- **Reorder Calculations**: Sales velocity-based reorder suggestions with rationale\n- **Approval Management**: Bulk approve and undo reorder suggestions\n- **Webhook Management**: Handle Shopify webhooks for real-time updates\n- **Health Monitoring**: API and database health endpoints\n\n## Multi-Tenant Security\n\n**CRITICAL**: Merchant context is derived exclusively from verified auth/session state.\nAny `merchant_id` present in query parameters, request body, or URL parameters is **silently ignored**.\nThis ensures tenant isolation cannot be bypassed via URL manipulation.\n\nFor current `/api/v1/*` routes, merchant/session context should come from the\nsanctioned route-tool and request-actor adapters documented in\n`docs/architecture/api-v1-request-lifecycle.md` and\n`docs/architecture/request-actor-contract.md`, not from route-local helper seams.\n\n## Authentication\nMost endpoints require authentication via Supabase Auth JWT tokens.\nInclude the token in the Authorization header: `Bearer <token>`\n\n## Rate Limiting\nAPI endpoints are rate-limited to prevent abuse:\n- Authentication endpoints: 5 requests per 15 minutes\n- Password reset: 3 requests per hour\n- General API: 60 requests per minute\n\n## Error Handling\nMost API endpoints follow a common error envelope:\n```json\n{\n  \"success\": false,\n  \"error\": {\n    \"code\": \"ERROR_CODE\",\n    \"message\": \"Human-readable message\",\n    \"details\": {}\n  }\n}\n```\n\nSome security or monitoring endpoints document narrower flat contracts such as `{ error, code }`\nor `{ error }` directly on the path. Treat each path-level response schema as the source of truth\nwhen it differs from the common envelope above. This matters especially for the\nnon-v1 webhook control-plane routes under `/api/webhooks/*`, which publish raw\nJSON route-local contracts in the current runtime.\n","contact":{"name":"StockCalm Support","email":"support@stockcalm.com"},"license":{"name":"Proprietary","url":"https://stockcalm.com/terms"}},"servers":[{"url":"https://stockcalm.com","description":"Configured application URL"},{"url":"https://api.stockcalm.com","description":"Production"},{"url":"https://staging-api.stockcalm.com","description":"Staging"}],"tags":[{"name":"Documentation","description":"OpenAPI distribution, Swagger UI, and changelog endpoints"},{"name":"Health","description":"Health check and monitoring endpoints"},{"name":"Authentication","description":"Authentication and user session endpoints"},{"name":"Billing","description":"Merchant billing snapshot, Stripe Checkout, and Stripe Billing Portal endpoints"},{"name":"Shopify OAuth","description":"Shopify OAuth connection management"},{"name":"Shopify Connections","description":"Manage connected Shopify stores"},{"name":"Sync","description":"Data synchronization operations"},{"name":"Webhooks","description":"Webhook processing and monitoring"},{"name":"Inventory","description":"Inventory management and reorder calculations"},{"name":"Storefront Sellability","description":"Native-only Shopify sellability policy overview, override, reconcile, history, and unmapped diagnostic endpoints"},{"name":"Analytics","description":"Merchant analytics and reporting endpoints"},{"name":"Products","description":"Product and catalog operations"},{"name":"SKUs","description":"SKU-specific read and mutation endpoints"},{"name":"Compliance","description":"Compliance and policy monitoring endpoints"},{"name":"Business Hours","description":"Business hours configuration and analytics helpers"},{"name":"Reorder Management","description":"Reorder suggestion calculations and approvals"},{"name":"Approvals","description":"Bulk approval operations and approval management"}],"security":[{"BearerAuth":[]}],"components":{"securitySchemes":{"BearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"Supabase Auth JWT token"},"CSRFToken":{"type":"apiKey","in":"header","name":"X-CSRF-Token","description":"CSRF protection token for state-changing operations"},"SessionCookieAuth":{"type":"apiKey","in":"cookie","name":"__browser_session__","description":"Represents an authenticated same-site browser session. Actual Supabase-managed cookie names are implementation-managed and may vary; non-browser clients should use BearerAuth."}},"schemas":{"ErrorResponse":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string","example":"VALIDATION_ERROR"},"message":{"type":"string","example":"Invalid request parameters"},"details":{"nullable":true}},"required":["code","message"]},"meta":{"type":"object","properties":{"requestId":{"type":"string"},"timestamp":{"type":"string","format":"date-time"}}}},"required":["success","error"]},"ResponseMeta":{"type":"object","properties":{"version":{"type":"string","example":"1.0.0"},"timestamp":{"type":"string","format":"date-time","example":"2025-01-01T00:00:00.000Z"},"requestId":{"type":"string","example":"req_abc123"},"correlationId":{"type":"string","example":"corr_xyz789"}}},"Pagination":{"type":"object","properties":{"page":{"type":"integer","example":1},"limit":{"type":"integer","example":50},"total":{"type":"integer","example":100},"totalPages":{"type":"integer","example":2},"hasNext":{"type":"boolean","example":true},"hasPrev":{"type":"boolean","example":false}},"required":["page","limit","total","totalPages","hasNext","hasPrev"]},"OpenApiDocument":{"type":"object","properties":{"openapi":{"type":"string","example":"3.0.3"},"info":{"type":"object","properties":{"title":{"type":"string","example":"StockCalm API"},"version":{"type":"string","example":"1.0.0"}},"required":["title","version"]},"paths":{"type":"object","additionalProperties":{"nullable":true}},"tags":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"description":{"type":"string"}},"required":["name"]}}},"required":["openapi","info","paths"],"additionalProperties":{"nullable":true}},"DocumentationFlatError":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error"]},"DocumentationChangelogResponse":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"changelog":{"type":"string"},"sourcePath":{"type":"string","example":"docs/api/changelog.md"},"lastModifiedAt":{"type":"string","format":"date-time"}},"required":["changelog","sourcePath","lastModifiedAt"]},"meta":{"type":"object","properties":{"version":{"type":"string"},"timestamp":{"type":"string","format":"date-time"},"requestId":{"type":"string"},"correlationId":{"type":"string"}}}},"required":["success","data"]},"ShopDomain":{"type":"string","pattern":"^[a-zA-Z0-9][a-zA-Z0-9-]*\\.myshopify\\.com$","example":"my-store.myshopify.com","description":"Shopify store domain (must end with .myshopify.com)"},"OAuthInitiateRequest":{"type":"object","properties":{"shopDomain":{"type":"string","pattern":"^[a-zA-Z0-9][a-zA-Z0-9-]*\\.myshopify\\.com$","example":"my-store.myshopify.com","description":"Shopify store domain (must end with .myshopify.com)"},"scopes":{"type":"array","items":{"type":"string"},"example":["read_products","write_inventory","read_orders"],"description":"OAuth scopes requested for the Shopify installation flow."}},"required":["shopDomain"]},"OAuthInitiateResponse":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"authorizationUrl":{"type":"string","format":"uri","example":"https://my-store.myshopify.com/admin/oauth/authorize?client_id=...","description":"URL to redirect the user to for Shopify authorization."},"shopDomain":{"type":"string","pattern":"^[a-zA-Z0-9][a-zA-Z0-9-]*\\.myshopify\\.com$","example":"my-store.myshopify.com","description":"Shopify store domain (must end with .myshopify.com)"},"scopes":{"type":"array","items":{"type":"string"},"example":["read_products","write_inventory","read_orders"],"description":"OAuth scopes requested for the Shopify installation flow."}},"required":["authorizationUrl","shopDomain"]}},"required":["success","data"]},"ShopifyConnectRequest":{"type":"object","properties":{"shopDomain":{"type":"string","pattern":"^[a-zA-Z0-9][a-zA-Z0-9-]*\\.myshopify\\.com$","example":"my-store.myshopify.com","description":"Shopify store domain (must end with .myshopify.com)"},"scopes":{"type":"array","items":{"type":"string"},"example":["read_products","write_inventory","read_orders"],"description":"OAuth scopes requested for the Shopify installation flow."}},"required":["shopDomain"]},"ShopifyConnectResponse":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"authUrl":{"type":"string","format":"uri","example":"https://my-store.myshopify.com/admin/oauth/authorize?client_id=..."},"shopDomain":{"type":"string","pattern":"^[a-zA-Z0-9][a-zA-Z0-9-]*\\.myshopify\\.com$","example":"my-store.myshopify.com","description":"Shopify store domain (must end with .myshopify.com)"},"scopes":{"type":"array","items":{"type":"string"},"example":["read_products","write_inventory","read_orders"],"description":"OAuth scopes requested for the Shopify installation flow."}},"required":["authUrl","shopDomain","scopes"]}},"required":["success","data"]},"LegacyShopifyConnectResponse":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"authUrl":{"type":"string","format":"uri"}},"required":["authUrl"]}},"required":["success","data"]},"ConnectionStatus":{"type":"string","enum":["connected","disconnected","error","pending"],"description":"Current status of the Shopify connection."},"ShopifyConnectionHealth":{"type":"object","properties":{"id":{"type":"string"},"connection_id":{"type":"string"},"health_status":{"type":"string","enum":["healthy","degraded","unhealthy"]},"last_check_at":{"type":"string","format":"date-time"},"last_successful_sync_at":{"type":"string","nullable":true,"format":"date-time"},"last_error_at":{"type":"string","nullable":true,"format":"date-time"},"last_error_message":{"type":"string","nullable":true},"consecutive_failures":{"type":"integer"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}},"required":["id","connection_id","health_status","last_check_at","consecutive_failures"]},"ShopifyConnectionWebhookStatus":{"type":"object","properties":{"id":{"type":"string"},"connection_id":{"type":"string"},"topic":{"type":"string"},"endpoint":{"type":"string"},"is_active":{"type":"boolean"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"},"last_error_at":{"type":"string","nullable":true,"format":"date-time"},"recent_deliveries":{"type":"array","items":{"type":"object","properties":{"processed_at":{"type":"string","format":"date-time"},"status":{"type":"string"},"error_message":{"type":"string"}},"required":["status"]},"default":[]}},"required":["id","connection_id","topic","endpoint","is_active","created_at","updated_at"]},"V1ShopifyConnectionDocument":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"merchant_id":{"type":"string","format":"uuid"},"shop_domain":{"type":"string","example":"my-store.myshopify.com"},"shop_name":{"type":"string","nullable":true},"shop_id":{"anyOf":[{"type":"string"},{"type":"number"},{"nullable":true}]},"shop_owner_email":{"type":"string","nullable":true,"format":"email"},"shop_country":{"type":"string","nullable":true},"shop_currency":{"type":"string","nullable":true},"scope":{"type":"string","nullable":true},"status":{"type":"string","enum":["connected","disconnected","error","pending"],"description":"Current status of the Shopify connection."},"expires_at":{"type":"string","nullable":true,"format":"date-time"},"connected_at":{"type":"string","nullable":true,"format":"date-time"},"last_sync_at":{"type":"string","nullable":true,"format":"date-time"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"},"health":{"$ref":"#/components/schemas/ShopifyConnectionHealth"},"webhook_count":{"type":"integer"},"active_webhook_count":{"type":"integer"}},"required":["id","shop_domain","status"],"additionalProperties":{"nullable":true}},"LegacyShopifyConnectionDocument":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"merchant_id":{"type":"string","format":"uuid"},"shop_domain":{"type":"string","example":"my-store.myshopify.com"},"shop_name":{"type":"string","nullable":true},"shop_id":{"anyOf":[{"type":"string"},{"type":"number"},{"nullable":true}]},"shop_owner_email":{"type":"string","nullable":true,"format":"email"},"shop_country":{"type":"string","nullable":true},"shop_currency":{"type":"string","nullable":true},"scope":{"type":"string","nullable":true},"status":{"type":"string","enum":["connected","disconnected","error","pending"],"description":"Current status of the Shopify connection."},"expires_at":{"type":"string","nullable":true,"format":"date-time"},"connected_at":{"type":"string","nullable":true,"format":"date-time"},"last_sync_at":{"type":"string","nullable":true,"format":"date-time"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"},"health":{"$ref":"#/components/schemas/ShopifyConnectionHealth"},"webhook_count":{"type":"integer"},"active_webhook_count":{"type":"integer"},"webhooks":{"type":"array","items":{"$ref":"#/components/schemas/ShopifyConnectionWebhookStatus"}}},"required":["id","shop_domain","status"],"additionalProperties":{"nullable":true}},"V1ShopifyConnectionsListResponse":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"$ref":"#/components/schemas/V1ShopifyConnectionDocument"}},"summary":{"type":"object","properties":{"total":{"type":"integer"},"connected":{"type":"integer"},"disconnected":{"type":"integer"},"error":{"type":"integer"}},"required":["total","connected","disconnected","error"]},"pagination":{"type":"object","properties":{"limit":{"type":"integer"},"offset":{"type":"integer"},"total":{"type":"integer"},"hasMore":{"type":"boolean"}},"required":["limit","offset","total","hasMore"]},"meta":{"type":"object","properties":{"version":{"type":"string"},"timestamp":{"type":"string","format":"date-time"},"correlationId":{"type":"string"}}}},"required":["success","data","summary","pagination"]},"LegacyShopifyConnectionsListResponse":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"connections":{"type":"array","items":{"$ref":"#/components/schemas/LegacyShopifyConnectionDocument"}},"summary":{"type":"object","properties":{"total":{"type":"integer"},"connected":{"type":"integer"},"disconnected":{"type":"integer"},"error":{"type":"integer"}},"required":["total","connected","disconnected","error"]},"pagination":{"type":"object","properties":{"limit":{"type":"integer"},"offset":{"type":"integer"},"total":{"type":"integer"},"hasMore":{"type":"boolean"}},"required":["limit","offset","total","hasMore"]}},"required":["connections","summary","pagination"]},"meta":{"type":"object","properties":{"requestId":{"type":"string"},"correlationId":{"type":"string"},"timestamp":{"type":"string","format":"date-time"}}}},"required":["success","data"]},"ShopifyConnectionsCompatError":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"string"}},"required":["success","error"]},"ShopifyConnectionsCompatStructuredError":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string","example":"CONNECTIONS_FETCH_ERROR"},"message":{"type":"string","example":"Failed to fetch Shopify connections"}},"required":["code","message"]}},"required":["success","error"]},"LegacyCreateShopifyConnectionRequest":{"type":"object","properties":{"shop_domain":{"type":"string","example":"my-store.myshopify.com"}},"required":["shop_domain"],"additionalProperties":{"nullable":true}},"LegacyCreateShopifyConnectionResponse":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"message":{"type":"string"},"shopDomain":{"type":"string"},"nextStep":{"type":"string","example":"POST /api/shopify/oauth/initiate"},"nextStepBody":{"type":"object","properties":{"shopDomain":{"type":"string"}},"required":["shopDomain"]}},"required":["message","shopDomain","nextStep","nextStepBody"]}},"required":["success","data"]},"SyncType":{"type":"string","enum":["full_products","full_orders","incremental_products","incremental_orders","inventory_levels","webhook_registration","shop_data"],"description":"Type of synchronization to perform."},"Priority":{"type":"string","enum":["low","normal","high"],"description":"Requested priority label for the sync job."},"StartSyncRequest":{"type":"object","properties":{"connectionId":{"type":"string","format":"uuid","example":"123e4567-e89b-12d3-a456-426614174000","description":"ID of the Shopify connection to sync."},"syncTypes":{"type":"array","items":{"type":"string","enum":["full_products","full_orders","incremental_products","incremental_orders","inventory_levels","webhook_registration","shop_data"],"description":"Type of synchronization to perform."},"minItems":1,"example":["full_products","inventory_levels"]},"fromDate":{"type":"string","format":"date-time","example":"2025-01-01T00:00:00.000Z","description":"Optional starting point for incremental syncs."},"batchSize":{"type":"integer","minimum":1,"maximum":1000,"default":250,"example":250},"priority":{"type":"string","enum":["low","normal","high"],"default":"normal","description":"Requested priority label for the sync job."}},"required":["connectionId","syncTypes"]},"StartSyncResponse":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"correlationId":{"type":"string","example":"sync_abc123xyz"},"connectionId":{"type":"string","format":"uuid"},"syncTypes":{"type":"array","items":{"type":"string","enum":["full_products","full_orders","incremental_products","incremental_orders","inventory_levels","webhook_registration","shop_data"],"description":"Type of synchronization to perform."}},"started":{"type":"boolean","enum":[true]},"queued":{"type":"boolean","enum":[true],"description":"The sync request was accepted into the durable background job queue."},"executionMode":{"type":"string","enum":["durable"],"description":"Sync processing is owned by the Shopify background worker, not the HTTP request."},"config":{"type":"object","properties":{"batchSize":{"type":"integer"},"priority":{"type":"string","enum":["low","normal","high"],"description":"Requested priority label for the sync job."},"fromDate":{"type":"string","format":"date-time"}},"required":["batchSize","priority"]}},"required":["correlationId","connectionId","syncTypes","started","queued","executionMode","config"]}},"required":["success","data"]},"SyncStatusResponse":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"syncs":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"connection_id":{"type":"string","format":"uuid"},"sync_type":{"type":"string","enum":["full_products","full_orders","incremental_products","incremental_orders","inventory_levels","webhook_registration","shop_data"],"description":"Type of synchronization to perform."},"sync_status":{"type":"string","enum":["pending","in_progress","retrying","completed","failed","cancelled","timeout"]},"direction":{"type":"string"},"correlation_id":{"type":"string","nullable":true},"started_at":{"type":"string","format":"date-time"},"completed_at":{"type":"string","nullable":true,"format":"date-time"},"error_message":{"type":"string","nullable":true},"retry_count":{"type":"integer"},"max_retries":{"type":"integer"}},"required":["id","connection_id","sync_type","sync_status","direction","started_at","retry_count","max_retries"]}},"summary":{"type":"object","properties":{"total":{"type":"integer"},"pending":{"type":"integer"},"running":{"type":"integer"},"completed":{"type":"integer"},"retrying":{"type":"integer"},"failed":{"type":"integer"}},"required":["total","pending","running","completed","retrying","failed"]}},"required":["syncs","summary"]}},"required":["success","data"]},"WebhookTopic":{"type":"string","example":"orders/paid","description":"Shopify webhook topic header value. Runtime accepts current and future topics as opaque strings."},"WebhookStatus":{"type":"string","enum":["pending","processing","completed","failed","retrying"],"description":"Processing status of a webhook event."},"ShopifyWebhookIngressResponseBody":{"type":"object","properties":{"ok":{"type":"boolean"},"correlationId":{"type":"string"},"eventId":{"type":"string"}},"required":["ok","correlationId"]},"DeadLetterItem":{"type":"object","properties":{"id":{"type":"string"},"webhookId":{"type":"string"},"topic":{"type":"string","example":"orders/paid","description":"Shopify webhook topic header value. Runtime accepts current and future topics as opaque strings."},"status":{"type":"string"},"severity":{"type":"string"},"shopDomain":{"type":"string"},"connectionId":{"type":"string"},"originalError":{"type":"string"},"failureReason":{"type":"string"},"failureCount":{"type":"integer"},"retryEligible":{"type":"boolean"},"backingEventId":{"type":"string","nullable":true},"payloadSummary":{"$ref":"#/components/schemas/DeadLetterPayloadSummary"},"payloadMode":{"type":"string","enum":["metadata_only","redacted_preview","processing_payload","encrypted_full_payload_exception"]},"retentionMode":{"type":"string","enum":["metadata_only","redacted_preview","processing_payload","encrypted_full_payload_exception"]},"bodySha256":{"type":"string"},"payloadSizeBytes":{"type":"integer","minimum":0},"redactedPreview":{"type":"object","additionalProperties":{"nullable":true}},"parseDiagnostics":{"type":"object","additionalProperties":{"nullable":true}},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}},"required":["id"]},"DeadLetterPayloadSummary":{"type":"object","properties":{"payloadMode":{"type":"string","enum":["metadata_only","redacted_preview","processing_payload","encrypted_full_payload_exception"]},"retentionMode":{"type":"string","enum":["metadata_only","redacted_preview","processing_payload","encrypted_full_payload_exception"]},"bodySha256":{"type":"string"},"payloadSizeBytes":{"type":"integer","minimum":0},"redactedPreview":{"type":"object","additionalProperties":{"nullable":true}},"parseDiagnostics":{"type":"object","additionalProperties":{"nullable":true}},"backingEventId":{"type":"string","nullable":true},"payloadShape":{"type":"string","enum":["object","array","primitive","null","unknown"]},"topLevelKeys":{"type":"array","items":{"type":"string"}},"redacted":{"type":"boolean","enum":[true]}},"required":["payloadMode","retentionMode","redacted"]},"DeadLetterQueueListResponse":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/DeadLetterItem"}},"count":{"type":"integer"},"filters":{"type":"object","properties":{"status":{"type":"string","enum":["pending_review","under_investigation","resolved","discarded"]},"topic":{"type":"string","maxLength":255},"severity":{"type":"string","enum":["low","medium","high","critical"]},"limit":{"type":"integer","minimum":1,"maximum":100,"default":50}}}},"required":["items","count","filters"]},"DeadLetterQueueActionRequest":{"oneOf":[{"$ref":"#/components/schemas/DeadLetterQueueRetryAction"},{"$ref":"#/components/schemas/DeadLetterQueuePermanentFailureAction"}],"discriminator":{"propertyName":"action","mapping":{"retry":"#/components/schemas/DeadLetterQueueRetryAction","mark_permanent_failure":"#/components/schemas/DeadLetterQueuePermanentFailureAction"}}},"DeadLetterQueueRetryAction":{"type":"object","properties":{"action":{"type":"string","enum":["retry"]},"deadLetterId":{"type":"string","maxLength":128},"operationType":{"type":"string","enum":["immediate_retry","scheduled_retry","force_retry"]},"scheduledTime":{"type":"string","format":"date-time","description":"Required when operationType is scheduled_retry."},"topic":{"type":"string","maxLength":255}},"required":["action","deadLetterId","operationType"]},"DeadLetterQueuePermanentFailureAction":{"type":"object","properties":{"action":{"type":"string","enum":["mark_permanent_failure"]},"deadLetterId":{"type":"string","maxLength":128},"reason":{"type":"string","maxLength":1000},"topic":{"type":"string","maxLength":255}},"required":["action","deadLetterId","reason"]},"DeadLetterQueueActionSuccess":{"anyOf":[{"$ref":"#/components/schemas/DeadLetterQueueRetrySuccess"},{"$ref":"#/components/schemas/DeadLetterQueuePermanentFailureSuccess"}]},"DeadLetterQueueRetrySuccess":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"retryId":{"type":"string"},"message":{"type":"string"}},"required":["success","retryId","message"]},"DeadLetterQueuePermanentFailureSuccess":{"type":"object","properties":{"success":{"type":"boolean"},"message":{"type":"string"}},"required":["success","message"]},"DeadLetterQueueActionError":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"retryId":{"type":"string"}},"required":["error"]},"DeadLetterQueueAnalysisResponse":{"type":"object","properties":{"deadLetterId":{"type":"string"},"analysis":{"anyOf":[{"type":"object","additionalProperties":{"nullable":true}},{"type":"object","properties":{},"additionalProperties":{"nullable":true}}]},"timestamp":{"type":"string","format":"date-time"}},"required":["deadLetterId","analysis","timestamp"]},"WebhookProcessorStats":{"type":"object","properties":{"webhooks":{"type":"object","properties":{"pending":{"type":"integer"},"processing":{"type":"integer"},"completed":{"type":"integer"},"failed":{"type":"integer"},"totalTime":{"type":"number"},"count":{"type":"integer"},"averageProcessingTime":{"type":"number"}},"required":["pending","processing","completed","failed","totalTime","count","averageProcessingTime"]},"jobs":{"type":"object","properties":{"pending":{"type":"integer"},"processing":{"type":"integer"},"completed":{"type":"integer"},"failed":{"type":"integer"}},"required":["pending","processing","completed","failed"]},"isRunning":{"type":"boolean"},"shopifySyncProcessor":{"$ref":"#/components/schemas/ShopifySyncProcessorStats"},"batchOrchestrator":{"$ref":"#/components/schemas/ProcessorBatchOrchestratorStatus"},"degraded":{"type":"boolean"},"componentErrors":{"type":"object","properties":{"webhookProcessor":{"type":"string"},"shopifySyncProcessor":{"type":"string"},"batchOrchestrator":{"type":"string"}}}},"required":["webhooks","jobs","isRunning"],"additionalProperties":{"nullable":true}},"ShopifySyncProcessorStats":{"type":"object","nullable":true,"properties":{"jobs":{"type":"object","properties":{"pending":{"type":"integer"},"processing":{"type":"integer"},"completed":{"type":"integer"},"failed":{"type":"integer"}},"required":["pending","processing","completed","failed"]},"isRunning":{"type":"boolean"}},"required":["jobs","isRunning"]},"ProcessorBatchOrchestratorStatus":{"type":"object","nullable":true,"properties":{"isRunning":{"type":"boolean"},"processingMetrics":{"type":"object","additionalProperties":{"nullable":true}},"queueStats":{"type":"object","nullable":true,"properties":{"pendingEvents":{"type":"integer"},"processingEvents":{"type":"integer"},"averageProcessingTime":{"type":"number"}},"required":["pendingEvents","processingEvents","averageProcessingTime"]},"batchStats":{"type":"object","nullable":true,"properties":{"pendingBatches":{"type":"integer"},"processingBatches":{"type":"integer"},"averageBatchSize":{"type":"number"}},"required":["pendingBatches","processingBatches","averageBatchSize"]},"healthChecks":{"type":"object","properties":{"databaseConnection":{"type":"boolean"},"batchProcessor":{"type":"boolean"},"webhookQueue":{"type":"boolean"}},"required":["databaseConnection","batchProcessor","webhookQueue"]}},"required":["isRunning","processingMetrics","queueStats","batchStats","healthChecks"]},"WebhookProcessorStatsError":{"type":"object","properties":{"error":{"type":"string"},"componentErrors":{"type":"object","properties":{"webhookProcessor":{"type":"string"},"shopifySyncProcessor":{"type":"string"},"batchOrchestrator":{"type":"string"}}}},"required":["error"]},"DefaultsUsed":{"type":"object","properties":{"lead_time":{"type":"boolean","example":false,"description":"True when the buying surface had to fall back to a default lead time."},"safety_stock":{"type":"boolean","example":true,"description":"True when the buying surface uses the default safety-stock assumption."}},"required":["lead_time","safety_stock"]},"ReorderSuggestion":{"type":"object","properties":{"id":{"type":"string","format":"uuid","example":"123e4567-e89b-12d3-a456-426614174000","description":"Inventory position row identifier."},"sku_id":{"type":"string","format":"uuid","example":"123e4567-e89b-12d3-a456-426614174001","description":"SKU identifier."},"sku_code":{"type":"string","example":"WIDGET-LRG","description":"SKU code/identifier."},"product_name":{"type":"string","nullable":true,"example":"Premium Widget - Large","description":"Product display name, if available."},"location_id":{"type":"string","format":"uuid","example":"123e4567-e89b-12d3-a456-426614174002","description":"Inventory location identifier."},"location_name":{"type":"string","example":"Main Warehouse","description":"Inventory location display name."},"on_hand_quantity":{"type":"integer","example":20,"description":"Units currently on hand."},"reserved_quantity":{"type":"integer","example":5,"description":"Units reserved for existing demand."},"available_quantity":{"type":"integer","example":15,"description":"Units currently available to sell or allocate."},"reorder_point":{"type":"integer","nullable":true,"example":25,"description":"Threshold at or below which the row is considered low stock."},"reorder_quantity":{"type":"integer","nullable":true,"example":40,"description":"Suggested reorder quantity. Pinned refresh rows that no longer qualify as low stock may return null to stay review-only."},"row_id":{"type":"string","format":"uuid","example":"123e4567-e89b-12d3-a456-426614174000","description":"Buying surface alias for the inventory position row id."},"source_inventory_row_id":{"type":"string","format":"uuid","example":"123e4567-e89b-12d3-a456-426614174000","description":"Inventory row backing the buying workbench row."},"inclusion_reason":{"$ref":"#/components/schemas/BuyingWorkbenchInclusionReason"},"matches_location_filter":{"type":"boolean","example":false,"description":"Buying surface only. False when a pinned refresh row is intentionally returned outside the active location_id filter."},"supplier_id":{"type":"string","nullable":true,"format":"uuid","example":"123e4567-e89b-12d3-a456-426614174010","description":"Resolved supplier id for the buying workbench row, if available."},"currency":{"type":"string","minLength":3,"maxLength":3,"example":"USD","description":"Default purchase-order currency for the row."},"supplier_sku_code":{"type":"string","nullable":true,"example":"SUP-001","description":"Supplier-facing SKU code, if mapped."},"unit_cost":{"type":"number","nullable":true,"example":12.5,"description":"Mapped supplier unit cost, if available."},"minimum_order_quantity":{"type":"integer","nullable":true,"example":24,"description":"Supplier minimum order quantity, if configured."},"lead_time_days":{"type":"integer","nullable":true,"example":14,"description":"Supplier lead time in days, if configured."},"using_defaults":{"allOf":[{"$ref":"#/components/schemas/DefaultsUsed"},{"description":"Buying surface only. Flags whether buying enrichment fell back to defaults."}]},"abc_category":{"type":"string","enum":["A","B","C","Unclassified"],"example":"A","description":"Buying surface only. ABC category used to prioritize workbench rows."},"abc_classification_day":{"type":"string","nullable":true,"example":"2026-03-20","description":"Buying surface only. Classification day for ABC enrichment."},"abc_is_stale":{"type":"boolean","example":true,"description":"Buying surface only. True when ABC enrichment came from the latest available stale snapshot."},"abc_source_contract":{"type":"string","enum":["fn30_row_enrichment_v1"],"example":"fn30_row_enrichment_v1","description":"Buying surface only. Versioned ABC enrichment contract."},"allowed_next_actions":{"type":"array","items":{"$ref":"#/components/schemas/BuyingWorkbenchAllowedAction"},"example":["inspect","select","filter"],"description":"Buying surface only. Actions the workbench can currently offer for the row."}},"required":["id","sku_id","sku_code","product_name","location_id","location_name","on_hand_quantity","reserved_quantity","available_quantity","reorder_point","reorder_quantity"]},"BuyingWorkbenchInclusionReason":{"type":"string","enum":["live_low_stock","pinned_refresh"],"description":"Buying surface only. live_low_stock rows come from the active low-stock query. pinned_refresh rows were re-included because the client pinned them for refresh continuity."},"BuyingWorkbenchAllowedAction":{"type":"string","enum":["inspect","select","filter"]},"ReorderSuggestionsResponse":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"suggestions":{"type":"array","items":{"$ref":"#/components/schemas/ReorderSuggestion"},"description":"Canonical low-stock rows, with additive buying-surface fields when surface=buying."},"metadata":{"type":"object","properties":{"limit":{"type":"integer","minimum":1,"maximum":100,"example":50,"description":"Applied server-side row limit."},"location_id":{"type":"string","nullable":true,"format":"uuid","example":"123e4567-e89b-12d3-a456-426614174002","description":"Active location filter, when present."},"surface":{"type":"string","enum":["inventory","buying"],"example":"buying","description":"Returned response surface. Present for buying-surface responses."}},"required":["limit"]}},"required":["suggestions","metadata"]}},"required":["success","data"]},"ApprovalRequest":{"type":"object","properties":{"sku_id":{"type":"string","format":"uuid","example":"123e4567-e89b-12d3-a456-426614174000","description":"SKU to approve reorder for"},"approved_quantity":{"type":"integer","minimum":0,"example":50,"description":"Approved reorder quantity."},"original_quantity":{"type":"integer","minimum":0,"example":40,"description":"Original suggested quantity captured for audit/reference."}},"required":["sku_id","approved_quantity","original_quantity"]},"BulkApproveRequest":{"type":"object","properties":{"approvals":{"type":"array","items":{"$ref":"#/components/schemas/ApprovalRequest"},"minItems":1,"maxItems":100,"description":"Array of approval requests"}},"required":["approvals"]},"BulkApproveResponse":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"approvals":{"type":"array","items":{"type":"object","properties":{"approval_id":{"type":"string","format":"uuid"},"sku_id":{"type":"string","format":"uuid"},"approved_quantity":{"type":"integer"},"approved_at":{"type":"string","format":"date-time"}},"required":["approval_id","sku_id","approved_quantity","approved_at"]},"description":"Successfully created approval records."},"failed":{"type":"array","items":{"type":"object","properties":{"sku_id":{"type":"string","format":"uuid"},"error":{"type":"string"}},"required":["sku_id","error"]},"description":"Items that failed to approve."},"total":{"type":"integer","example":2,"description":"Total approvals processed (successes + failures)."},"success_count":{"type":"integer","example":2,"description":"Count of successful approvals."},"failure_count":{"type":"integer","example":0,"description":"Count of failed approvals."},"batch_id":{"type":"string","format":"uuid","example":"456e7890-e89b-12d3-a456-426614174001","description":"Server-generated batch identifier for this approval request."}},"required":["success","approvals","failed","total","success_count","failure_count","batch_id"]},"UndoApprovalRequest":{"anyOf":[{"type":"object","properties":{"approval_id":{"type":"string","format":"uuid","example":"456e7890-e89b-12d3-a456-426614174001","description":"Approval record ID to undo."}},"required":["approval_id"]},{"type":"object","properties":{"batch_id":{"type":"string","format":"uuid","example":"89ae7890-e89b-12d3-a456-426614174001","description":"Batch ID whose approvals should be undone."}},"required":["batch_id"]}]},"UndoApprovalResponse":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"undo_type":{"type":"string","enum":["single","batch"]},"approval_id":{"type":"string","format":"uuid"},"undone":{"type":"boolean","enum":[true]},"undone_at":{"type":"string","format":"date-time","example":"2025-01-03T11:00:00.000Z"},"batch_id":{"type":"string","format":"uuid"},"undone_count":{"type":"integer"},"undone_approval_ids":{"type":"array","items":{"type":"string","format":"uuid"}}},"required":["success","undo_type"]}},"required":["success","data"]},"InventoryPositionSkuSummary":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"sku_code":{"type":"string","example":"WIDGET-LRG"},"product_name":{"type":"string","nullable":true,"example":"Premium Widget - Large"},"variant_title":{"type":"string","nullable":true,"example":"Blue / Large"},"reorder_point":{"type":"integer","nullable":true,"example":25},"reorder_quantity":{"type":"integer","nullable":true,"example":40}},"required":["id","sku_code","product_name","variant_title"]},"InventoryPositionLocationSummary":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string","example":"Main Warehouse"},"type":{"type":"string","enum":["warehouse","store","fulfillment_center","dropship"],"example":"warehouse"}},"required":["id","name","type"]},"InventoryPosition":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"sku_id":{"type":"string","format":"uuid"},"location_id":{"type":"string","format":"uuid"},"on_hand_quantity":{"type":"integer","example":25},"reserved_quantity":{"type":"integer","example":3},"available_quantity":{"type":"integer","example":22},"updated_at":{"type":"string","format":"date-time"},"reorder_point":{"type":"integer","nullable":true,"example":10},"reorder_quantity":{"type":"integer","nullable":true,"example":20},"skus":{"allOf":[{"$ref":"#/components/schemas/InventoryPositionSkuSummary"},{"nullable":true}]},"sku":{"allOf":[{"$ref":"#/components/schemas/InventoryPositionSkuSummary"},{"nullable":true}]},"locations":{"allOf":[{"$ref":"#/components/schemas/InventoryPositionLocationSummary"},{"nullable":true}]},"location":{"allOf":[{"$ref":"#/components/schemas/InventoryPositionLocationSummary"},{"nullable":true}]}},"required":["id","sku_id","location_id","on_hand_quantity","reserved_quantity","available_quantity","updated_at","reorder_point","reorder_quantity","skus","locations"]},"InventoryPositionsResponse":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"positions":{"type":"array","items":{"$ref":"#/components/schemas/InventoryPosition"}},"pagination":{"type":"object","properties":{"page":{"type":"integer","example":1},"limit":{"type":"integer","example":50},"total":{"type":"integer","example":120},"totalPages":{"type":"integer","example":3},"hasNext":{"type":"boolean","example":true},"hasPrev":{"type":"boolean","example":false}},"required":["page","limit","total","totalPages","hasNext","hasPrev"]}},"required":["positions","pagination"]}},"required":["success","data"]},"InventoryStats":{"type":"object","properties":{"totalSKUs":{"type":"integer","example":42},"totalPositions":{"type":"integer","example":120},"totalAvailable":{"type":"integer","example":820},"totalReserved":{"type":"integer","example":95},"totalOnHand":{"type":"integer","example":915},"lowStockCount":{"type":"integer","example":8},"outOfStockCount":{"type":"integer","example":3},"locationsWithStock":{"type":"integer","example":6},"utilizationRate":{"type":"number","example":10.38},"avgAvailablePerSKU":{"type":"number","example":19.52}},"required":["totalSKUs","totalPositions","totalAvailable","totalReserved","totalOnHand","lowStockCount","outOfStockCount","locationsWithStock","utilizationRate","avgAvailablePerSKU"]},"InventoryStatsResponse":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/InventoryStats"}},"required":["success","data"]},"InventoryLocation":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string","example":"Main Warehouse"},"type":{"type":"string","enum":["warehouse","store","fulfillment_center","dropship"],"example":"warehouse"},"merchant_id":{"type":"string","format":"uuid"},"is_active":{"type":"boolean","example":true},"address":{"type":"string","nullable":true,"example":"123 Market St"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}},"required":["id","name","type","merchant_id","is_active","created_at","updated_at"]},"InventoryLocationsListResponse":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"locations":{"type":"array","items":{"$ref":"#/components/schemas/InventoryLocation"}},"total":{"type":"integer","example":12}},"required":["locations","total"]}},"required":["success","data"]},"InventoryLocationsGroupedResponse":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"grouped":{"type":"object","additionalProperties":{"type":"array","items":{"$ref":"#/components/schemas/InventoryLocation"}}},"meta":{"type":"object","properties":{"totalLocations":{"type":"integer","example":12},"totalGroups":{"type":"integer","example":3},"groups":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string","example":"warehouse"},"count":{"type":"integer","example":4}},"required":["name","count"]}}},"required":["totalLocations","totalGroups","groups"]}},"required":["grouped","meta"]}},"required":["success","data"]},"InventoryCountSessionStatus":{"type":"string","enum":["open","review","committing","completed","completed_with_warnings","cancelled"]},"InventoryCountLineStatus":{"type":"string","enum":["pending","counted","skipped","committed"]},"InventoryCountType":{"type":"string","enum":["stock_take","cycle_count"]},"InventoryCountAbcCategory":{"type":"string","enum":["A","B","C","Unclassified"]},"InventoryCountEventOutcome":{"type":"string","enum":["not_required","pending","sent","failed","unknown"]},"InventoryCountPagination":{"type":"object","properties":{"page":{"type":"integer","example":1},"limit":{"type":"integer","example":50},"total":{"type":"integer","example":120},"totalPages":{"type":"integer","example":3},"hasNext":{"type":"boolean","example":true},"hasPrev":{"type":"boolean","example":false}},"required":["page","limit","total","totalPages","hasNext","hasPrev"]},"InventoryCountEventWarningSummary":{"type":"object","properties":{"kind":{"type":"string","enum":["event_outcome_unknown"],"example":"event_outcome_unknown"},"affectedLineIds":{"type":"array","items":{"type":"string","format":"uuid"},"example":["123e4567-e89b-12d3-a456-426614174099"],"description":"Committed non-zero lines whose downstream change-event outcome needs verification."},"failedLineIds":{"type":"array","items":{"type":"string","format":"uuid"}},"unknownLineIds":{"type":"array","items":{"type":"string","format":"uuid"}},"message":{"type":"string","example":"Inventory count committed, but one or more inventory change events require verification."}},"required":["kind","affectedLineIds","message"]},"InventoryCountProgressSummary":{"type":"object","properties":{"total":{"type":"integer","minimum":0,"example":25},"pending":{"type":"integer","minimum":0,"example":3},"counted":{"type":"integer","minimum":0,"example":20},"skipped":{"type":"integer","minimum":0,"example":2},"committed":{"type":"integer","minimum":0,"example":0},"complete":{"type":"boolean","example":false},"percentComplete":{"type":"number","minimum":0,"maximum":100,"example":88}},"required":["total","pending","counted","skipped","committed","complete","percentComplete"]},"InventoryCountVarianceSummary":{"type":"object","properties":{"countedLines":{"type":"integer","minimum":0,"example":22},"changedLines":{"type":"integer","minimum":0,"example":4},"positiveVarianceQuantity":{"type":"integer","minimum":0,"example":7},"negativeVarianceQuantity":{"type":"integer","minimum":0,"example":3},"netVarianceQuantity":{"type":"integer","example":4},"absoluteVarianceQuantity":{"type":"integer","minimum":0,"example":10}},"required":["countedLines","changedLines","positiveVarianceQuantity","negativeVarianceQuantity","netVarianceQuantity","absoluteVarianceQuantity"]},"InventoryCountLine":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"sessionId":{"type":"string","format":"uuid"},"inventoryPositionId":{"type":"string","nullable":true,"format":"uuid"},"skuId":{"type":"string","format":"uuid"},"locationId":{"type":"string","format":"uuid"},"skuCode":{"type":"string","example":"WIDGET-LRG"},"productName":{"type":"string","nullable":true,"example":"Premium Widget - Large"},"locationName":{"type":"string","example":"Main Warehouse"},"status":{"$ref":"#/components/schemas/InventoryCountLineStatus"},"snapshotOnHandQuantity":{"type":"integer","nullable":true,"example":12,"description":"Redacted to null while a blind-count session is open."},"snapshotReservedQuantity":{"type":"integer","nullable":true,"example":2},"snapshotAvailableQuantity":{"type":"integer","nullable":true,"example":10},"countedOnHandQuantity":{"type":"integer","nullable":true,"minimum":0,"example":11},"varianceQuantity":{"type":"integer","nullable":true,"example":-1,"description":"Redacted to null while a blind-count session is open."},"note":{"type":"string","nullable":true,"maxLength":1000},"skipReason":{"type":"string","nullable":true,"maxLength":1000},"lineVersion":{"type":"integer","minimum":1,"example":3},"abcCategory":{"allOf":[{"$ref":"#/components/schemas/InventoryCountAbcCategory"},{"nullable":true}]},"eventOutcome":{"$ref":"#/components/schemas/InventoryCountEventOutcome"}},"required":["id","sessionId","inventoryPositionId","skuId","locationId","skuCode","productName","locationName","status","snapshotOnHandQuantity","snapshotReservedQuantity","snapshotAvailableQuantity","countedOnHandQuantity","varianceQuantity","note","skipReason","lineVersion","abcCategory","eventOutcome"]},"InventoryCountSessionSummary":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"countType":{"$ref":"#/components/schemas/InventoryCountType"},"name":{"type":"string","example":"May cycle count - A items"},"status":{"$ref":"#/components/schemas/InventoryCountSessionStatus"},"blindCount":{"type":"boolean","example":true},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"completedAt":{"type":"string","nullable":true,"format":"date-time"},"progress":{"$ref":"#/components/schemas/InventoryCountProgressSummary"},"variance":{"$ref":"#/components/schemas/InventoryCountVarianceSummary"},"eventWarning":{"$ref":"#/components/schemas/InventoryCountEventWarningSummary"}},"required":["id","countType","name","status","blindCount","createdAt","updatedAt","completedAt","progress"]},"InventoryCountSessionDetail":{"allOf":[{"$ref":"#/components/schemas/InventoryCountSessionSummary"},{"type":"object","properties":{"locationIds":{"type":"array","items":{"type":"string","format":"uuid"}},"lines":{"type":"array","items":{"$ref":"#/components/schemas/InventoryCountLine"}}},"required":["locationIds","lines"]}]},"InventoryCountSessionsResponse":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"sessions":{"type":"array","items":{"$ref":"#/components/schemas/InventoryCountSessionSummary"}},"pagination":{"$ref":"#/components/schemas/InventoryCountPagination"}},"required":["sessions","pagination"]}},"required":["success","data"]},"InventoryCountCreateSessionResponse":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"session":{"$ref":"#/components/schemas/InventoryCountSessionSummary"},"lines":{"type":"array","items":{"$ref":"#/components/schemas/InventoryCountLine"}},"pagination":{"$ref":"#/components/schemas/InventoryCountPagination"}},"required":["session","lines","pagination"]}},"required":["success","data"]},"InventoryCountSessionDetailResponse":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"session":{"$ref":"#/components/schemas/InventoryCountSessionDetail"},"lines":{"type":"array","items":{"$ref":"#/components/schemas/InventoryCountLine"}},"pagination":{"$ref":"#/components/schemas/InventoryCountPagination"},"supportRedacted":{"type":"boolean"},"lineAccess":{"type":"string","enum":["denied"]}},"required":["session","lines","pagination"]}},"required":["success","data"]},"InventoryCountLinesResponse":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"lines":{"type":"array","items":{"$ref":"#/components/schemas/InventoryCountLine"}},"pagination":{"$ref":"#/components/schemas/InventoryCountPagination"}},"required":["lines","pagination"]}},"required":["success","data"]},"InventoryCountLineResponse":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"line":{"$ref":"#/components/schemas/InventoryCountLine"}},"required":["line"]}},"required":["success","data"]},"CountScanMatchedField":{"type":"string","enum":["barcode","upc"]},"CountScanLookupOutcome":{"type":"string","enum":["matched","multiple_count_lines","duplicate_skus","sku_not_in_session","unknown_code"]},"CountScanLookupRequest":{"type":"object","properties":{"code":{"type":"string","minLength":1,"example":"000123456789","description":"Raw scanned barcode/UPC submitted in the POST body only. The server rejects control characters, trims surrounding whitespace, rejects whitespace-only values, preserves leading zeros and punctuation, and requires the normalized trimmed value to be 100 characters or fewer. UPC matching is attempted only for normalized values 20 characters or fewer."},"locationId":{"type":"string","format":"uuid","description":"Optional operator-selected location hint for multi-location count sessions. If it matches exactly one count line, that line is returned; stale or non-matching hints fall back to normal single-line vs multiple-line outcome logic."}},"required":["code"]},"CountScanSkuMatchSummary":{"type":"object","properties":{"skuId":{"type":"string","format":"uuid"},"skuCode":{"type":"string","nullable":true,"example":"WIDGET-LRG"},"productName":{"type":"string","nullable":true,"example":"Premium Widget - Large"},"matchedFields":{"type":"array","items":{"$ref":"#/components/schemas/CountScanMatchedField"},"minItems":1,"maxItems":2}},"required":["skuId","skuCode","productName","matchedFields"]},"CountScanLineCandidate":{"type":"object","properties":{"line":{"$ref":"#/components/schemas/InventoryCountLine"},"skuMatches":{"type":"array","items":{"$ref":"#/components/schemas/CountScanSkuMatchSummary"},"minItems":1}},"required":["line","skuMatches"]},"CountScanLookupResponse":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"inputCode":{"type":"string","example":"  000123456789  ","description":"Original submitted code, returned only to the authenticated requester."},"normalizedCode":{"type":"string","example":"000123456789","description":"Trimmed barcode/UPC value; leading zeros are preserved."},"matchedFields":{"type":"array","items":{"$ref":"#/components/schemas/CountScanMatchedField"},"maxItems":2,"description":"Unique matched SKU fields. Empty only for unknown_code; otherwise a subset of barcode and upc."},"outcome":{"allOf":[{"$ref":"#/components/schemas/CountScanLookupOutcome"},{"description":"Determines which optional fields appear: matched includes line only; multiple_count_lines includes lineCandidates; duplicate_skus includes skuMatches and may include lineCandidates; sku_not_in_session includes skuMatches only; unknown_code has no line or SKU match fields."}]},"canUpdateLine":{"type":"boolean","description":"True only when the session is open and the actor has an inventory-writer role."},"line":{"allOf":[{"$ref":"#/components/schemas/InventoryCountLine"},{"description":"Present only when outcome is matched."}]},"lineCandidates":{"type":"array","items":{"$ref":"#/components/schemas/CountScanLineCandidate"},"minItems":1,"description":"Present when outcome is multiple_count_lines. May also be present for duplicate_skus when matched SKUs have lines in the count session."},"skuMatches":{"type":"array","items":{"$ref":"#/components/schemas/CountScanSkuMatchSummary"},"minItems":1,"description":"Present for duplicate_skus and sku_not_in_session outcomes; absent for matched, multiple_count_lines, and unknown_code."}},"required":["inputCode","normalizedCode","matchedFields","outcome","canUpdateLine"]}},"required":["success","data"]},"InventoryCountStatusTransitionResponse":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"sessionId":{"type":"string","format":"uuid"},"status":{"$ref":"#/components/schemas/InventoryCountSessionStatus"}},"required":["sessionId","status"]}},"required":["success","data"]},"InventoryCountCommitResult":{"type":"object","properties":{"session":{"$ref":"#/components/schemas/InventoryCountSessionSummary"},"committedLineCount":{"type":"integer","minimum":0,"example":4},"skippedLineCount":{"type":"integer","minimum":0,"example":2},"zeroDeltaLineCount":{"type":"integer","minimum":0,"example":16},"eventWarning":{"$ref":"#/components/schemas/InventoryCountEventWarningSummary"}},"required":["session","committedLineCount","skippedLineCount","zeroDeltaLineCount"]},"InventoryCountCommitResponse":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"replayed":{"type":"boolean","example":false,"description":"True when a completed operationKey response was replayed without reapplying inventory."},"result":{"$ref":"#/components/schemas/InventoryCountCommitResult"}},"required":["replayed","result"]}},"required":["success","data"]},"CreateInventoryCountSessionRequest":{"type":"object","properties":{"countType":{"$ref":"#/components/schemas/InventoryCountType"},"name":{"type":"string","minLength":1,"maxLength":120,"example":"May cycle count - A items"},"blindCount":{"type":"boolean","default":false},"locationIds":{"type":"array","items":{"type":"string","format":"uuid"},"maxItems":50},"selectedPairs":{"type":"array","items":{"type":"object","properties":{"skuId":{"type":"string","format":"uuid"},"locationId":{"type":"string","format":"uuid"}},"required":["skuId","locationId"]},"maxItems":500},"filters":{"type":"object","properties":{"lowStockOnly":{"type":"boolean"},"abcCategory":{"$ref":"#/components/schemas/InventoryCountAbcCategory"}}},"source":{"type":"string","enum":["counts_create_dialog","inventory_table_selection"]}},"required":["countType","name"]},"UpdateInventoryCountSessionMetadataRequest":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":120},"metadata":{"type":"object","additionalProperties":{"nullable":true}}}},"UpdateInventoryCountLineRequest":{"anyOf":[{"type":"object","properties":{"status":{"type":"string","enum":["counted"]},"countedOnHandQuantity":{"type":"integer","minimum":0},"note":{"type":"string","maxLength":1000},"expectedLineVersion":{"type":"integer","minimum":1}},"required":["status","countedOnHandQuantity","expectedLineVersion"]},{"type":"object","properties":{"status":{"type":"string","enum":["skipped"]},"skipReason":{"type":"string","maxLength":1000},"note":{"type":"string","maxLength":1000},"expectedLineVersion":{"type":"integer","minimum":1}},"required":["status","expectedLineVersion"]},{"type":"object","properties":{"status":{"type":"string","enum":["pending"]},"note":{"type":"string","maxLength":1000},"expectedLineVersion":{"type":"integer","minimum":1}},"required":["status","expectedLineVersion"]}]},"CancelInventoryCountSessionRequest":{"type":"object","properties":{"reason":{"type":"string","maxLength":1000}}},"CommitInventoryCountSessionRequest":{"type":"object","properties":{"operationKey":{"type":"string","minLength":8,"maxLength":128,"pattern":"^[A-Za-z0-9._:-]+$","example":"count-commit-01JEVYV2C6YQ0R4J9V9FXW9Q7K"}},"required":["operationKey"]},"InventoryCountConflictResponse":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string","enum":["BIZ_RESOURCE_CONFLICT","BIZ_OPERATION_NOT_ALLOWED"]},"message":{"type":"string"},"details":{"anyOf":[{"type":"object","properties":{"kind":{"type":"string","enum":["line_version_conflict"]},"currentLineVersion":{"type":"integer"},"lineId":{"type":"string","format":"uuid"}},"required":["kind"]},{"type":"object","properties":{"kind":{"type":"string","enum":["pending_lines"]},"pendingLineCount":{"type":"integer"}},"required":["kind"]},{"type":"object","properties":{"kind":{"type":"string","enum":["stale_lines"]},"conflicts":{"type":"array","items":{"type":"object","additionalProperties":{"nullable":true}}}},"required":["kind","conflicts"]},{"type":"object","properties":{"kind":{"type":"string","enum":["commit_in_progress"]},"retryAfterSeconds":{"type":"integer","minimum":1}},"required":["kind","retryAfterSeconds"]},{"type":"object","properties":{"kind":{"type":"string","enum":["commit_lease_expired"]}},"required":["kind"]},{"type":"object","properties":{"kind":{"type":"string","enum":["operation_key_conflict"]}},"required":["kind"]},{"type":"object","properties":{"kind":{"type":"string","enum":["incomplete_lines"]},"pendingLineCount":{"type":"integer","minimum":1}},"required":["kind","pendingLineCount"]},{"type":"object","properties":{"kind":{"type":"string","enum":["invalid_status"]},"status":{"type":"string"}},"required":["kind"]},{"type":"object","properties":{"kind":{"type":"string","enum":["commit_not_completed"]}},"required":["kind"]},{"type":"object","properties":{"kind":{"type":"string","enum":["line_not_found"]},"lineId":{"type":"string","format":"uuid"}},"required":["kind","lineId"]}],"description":"Conflict details for line-version, review-blocker, stale/missing-position, active lease, expired lease, operation-key mismatch, and invalid status outcomes."}},"required":["code","message","details"]}},"required":["success","error"]},"InventoryCountsFeatureDisabledResponse":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string","enum":["BIZ_OPERATION_NOT_ALLOWED"]},"message":{"type":"string","enum":["Inventory counts are not enabled for this workspace"]},"details":{"type":"object","properties":{"kind":{"type":"string","enum":["feature_disabled"]},"feature":{"type":"string","enum":["inventory-counts-mvp"]}},"required":["kind","feature"]}},"required":["code","message","details"]}},"required":["success","error"]},"InventoryCountPermissionDeniedResponse":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string","enum":["PERM_INSUFFICIENT_PERMISSIONS"]},"message":{"type":"string","example":"Forbidden: insufficient permissions"},"details":{"type":"object","additionalProperties":{"nullable":true}}},"required":["code","message"]}},"required":["success","error"]},"InventoryCountForbiddenResponse":{"anyOf":[{"$ref":"#/components/schemas/InventoryCountsFeatureDisabledResponse"},{"$ref":"#/components/schemas/InventoryCountPermissionDeniedResponse"}]},"StorefrontSellabilityState":{"type":"string","enum":["sellable","blocked"]},"StorefrontSellabilityMode":{"type":"string","enum":["automatic","manual_force_sellable"]},"StorefrontSellabilityHealth":{"type":"string","enum":["healthy","degraded","stale","unknown"]},"StorefrontSellabilityOutcome":{"type":"string","enum":["state_changed","noop","duplicate","stale_event","unsupported_capability","unmapped","apply_succeeded","apply_failed","repair_succeeded","repair_failed","repair_blocked"]},"StorefrontSellabilityReconcileStatus":{"type":"string","enum":["in_sync","drift_detected","repair_failed","repair_blocked","unknown"]},"StorefrontSellabilityAccessMatrix":{"type":"object","properties":{"role":{"type":"string","enum":["merchant_admin","fulfillment_staff","support_rep"],"example":"merchant_admin","description":"Role derived from the authenticated merchant context."},"canManagePolicy":{"type":"boolean","example":true},"canTriggerReconcile":{"type":"boolean","example":true},"canViewHistory":{"type":"boolean","example":true},"canViewDiagnostics":{"type":"boolean","example":true}},"required":["role","canManagePolicy","canTriggerReconcile","canViewHistory","canViewDiagnostics"]},"StorefrontSellabilityPolicyListItem":{"type":"object","properties":{"id":{"type":"string","example":"f8a7ff12-2f33-49aa-bf98-6d65ca902001","description":"Policy identifier when configured. Unconfigured mappings use a stable placeholder string such as unconfigured:<mappingId>."},"merchantId":{"type":"string","format":"uuid","example":"f8a7ff12-2f33-49aa-bf98-6d65ca902000"},"connectionId":{"type":"string","format":"uuid","example":"8a5ea4fe-e728-4604-8422-997d6087d310"},"mappingId":{"type":"string","format":"uuid","example":"550e8400-e29b-41d4-a716-446655440000"},"enabled":{"type":"boolean","example":true,"description":"True when the mapping participates in the native automatic baseline or override flow."},"enforcementMode":{"type":"string","enum":["inventory_policy_only"],"example":"inventory_policy_only","description":"Lane A only supports native Shopify inventory_policy enforcement."},"mode":{"$ref":"#/components/schemas/StorefrontSellabilityMode"},"disableThreshold":{"type":"number","enum":[0],"example":0,"description":"Frozen Lane A native disable threshold."},"reenableThreshold":{"type":"number","enum":[1],"example":1,"description":"Frozen Lane A native re-enable threshold."},"desiredState":{"allOf":[{"$ref":"#/components/schemas/StorefrontSellabilityState"},{"nullable":true,"example":"blocked","description":"Desired storefront sellability state derived from the current policy mode and effective inventory."}]},"lastAppliedState":{"allOf":[{"$ref":"#/components/schemas/StorefrontSellabilityState"},{"nullable":true,"example":"blocked"}]},"lastObservedExternalState":{"allOf":[{"$ref":"#/components/schemas/StorefrontSellabilityState"},{"nullable":true,"example":"blocked"}]},"lastReconcileStatus":{"allOf":[{"$ref":"#/components/schemas/StorefrontSellabilityReconcileStatus"},{"nullable":true,"example":"in_sync"}]},"lastReconcileErrorCode":{"type":"string","nullable":true,"example":null},"lastReconcileErrorMessage":{"type":"string","nullable":true,"example":null},"lastTransitionAt":{"type":"string","nullable":true,"format":"date-time","example":"2026-04-03T13:05:10.000Z"},"lastEvaluatedAt":{"type":"string","nullable":true,"format":"date-time","example":"2026-04-03T13:05:08.000Z"},"lastReconciledAt":{"type":"string","nullable":true,"format":"date-time","example":"2026-04-03T13:05:10.000Z"},"lastObservedExternalAt":{"type":"string","nullable":true,"format":"date-time","example":"2026-04-03T13:05:09.000Z"},"createdAt":{"type":"string","nullable":true,"format":"date-time","example":"2026-04-03T12:55:00.000Z"},"updatedAt":{"type":"string","nullable":true,"format":"date-time","example":"2026-04-03T13:05:10.000Z"},"hasPolicy":{"type":"boolean","example":true},"mappingLabel":{"type":"string","example":"SKU-1234"},"productTitle":{"type":"string","nullable":true,"example":"Classic Tee"},"variantTitle":{"type":"string","nullable":true,"example":"Black / Medium"},"skuCode":{"type":"string","nullable":true,"example":"TEE-BLK-M"},"shopDomain":{"type":"string","nullable":true,"example":"merchant-demo.myshopify.com"},"shopName":{"type":"string","nullable":true,"example":"Merchant Demo"},"shopifyVariantId":{"type":"integer","nullable":true,"example":445566778899},"inventoryItemId":{"type":"integer","nullable":true,"example":998877665544},"health":{"$ref":"#/components/schemas/StorefrontSellabilityHealth"},"warnings":{"type":"array","items":{"type":"string"},"example":["Lane A is native-only. Thresholds are fixed at disable=0 and re-enable=1."]}},"required":["id","merchantId","connectionId","mappingId","enabled","enforcementMode","mode","disableThreshold","reenableThreshold","desiredState","lastAppliedState","lastObservedExternalState","lastReconcileStatus","lastReconcileErrorCode","lastReconcileErrorMessage","lastTransitionAt","lastEvaluatedAt","lastReconciledAt","lastObservedExternalAt","createdAt","updatedAt","hasPolicy","mappingLabel","productTitle","variantTitle","skuCode","shopDomain","shopName","shopifyVariantId","inventoryItemId","health","warnings"]},"StorefrontSellabilityOverviewSummary":{"type":"object","properties":{"totalMappings":{"type":"integer","example":12},"configuredPolicies":{"type":"integer","example":8},"enabledPolicies":{"type":"integer","example":7},"manualOverridePolicies":{"type":"integer","example":1},"healthyPolicies":{"type":"integer","example":5},"degradedPolicies":{"type":"integer","example":1},"stalePolicies":{"type":"integer","example":1},"unknownPolicies":{"type":"integer","example":5},"openUnmappedInputs":{"type":"integer","example":2},"unmappedHealth":{"$ref":"#/components/schemas/StorefrontSellabilityHealth"}},"required":["totalMappings","configuredPolicies","enabledPolicies","manualOverridePolicies","healthyPolicies","degradedPolicies","stalePolicies","unknownPolicies","openUnmappedInputs","unmappedHealth"]},"StorefrontSellabilityOverviewData":{"type":"object","properties":{"lane":{"type":"string","enum":["native_only"],"example":"native_only","description":"Current rollout lane. App-enforced storefront_gate behavior is not part of this contract."},"access":{"$ref":"#/components/schemas/StorefrontSellabilityAccessMatrix"},"summary":{"$ref":"#/components/schemas/StorefrontSellabilityOverviewSummary"},"policies":{"type":"array","items":{"$ref":"#/components/schemas/StorefrontSellabilityPolicyListItem"}},"warnings":{"type":"array","items":{"type":"string"},"example":["Lane A is native-only. Gated controls remain blocked until a reusable storefront_gate contract exists.","Native automatic mode preserves Shopify DENY as the baseline. Only manual force sellable may switch Shopify to CONTINUE."]}},"required":["lane","access","summary","policies","warnings"]},"StorefrontSellabilityOverviewResponse":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/StorefrontSellabilityOverviewData"}},"required":["success","data"]},"StorefrontSellabilitySyncResult":{"type":"object","properties":{"policyId":{"type":"string","format":"uuid","example":"f8a7ff12-2f33-49aa-bf98-6d65ca902001"},"outcome":{"$ref":"#/components/schemas/StorefrontSellabilityOutcome"},"reconcileStatus":{"$ref":"#/components/schemas/StorefrontSellabilityReconcileStatus"},"desiredActuatorState":{"$ref":"#/components/schemas/StorefrontSellabilityState"},"observedActuatorState":{"allOf":[{"$ref":"#/components/schemas/StorefrontSellabilityState"},{"nullable":true,"example":"blocked"}]},"health":{"$ref":"#/components/schemas/StorefrontSellabilityHealth"}},"required":["policyId","outcome","reconcileStatus","desiredActuatorState","observedActuatorState","health"]},"StorefrontSellabilityPolicyMutationData":{"type":"object","properties":{"policy":{"$ref":"#/components/schemas/StorefrontSellabilityPolicyListItem"},"syncResult":{"allOf":[{"$ref":"#/components/schemas/StorefrontSellabilitySyncResult"},{"nullable":true}]},"warnings":{"type":"array","items":{"type":"string"}}},"required":["policy","syncResult","warnings"]},"StorefrontSellabilityPolicyMutationResponse":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/StorefrontSellabilityPolicyMutationData"}},"required":["success","data"]},"StorefrontSellabilityTransitionHistoryItem":{"type":"object","properties":{"id":{"type":"string","format":"uuid","example":"9d639665-eb27-4548-a275-8fc38425803a"},"policyId":{"type":"string","format":"uuid","example":"f8a7ff12-2f33-49aa-bf98-6d65ca902001"},"merchantId":{"type":"string","format":"uuid","example":"f8a7ff12-2f33-49aa-bf98-6d65ca902000"},"mappingId":{"type":"string","format":"uuid","example":"550e8400-e29b-41d4-a716-446655440000"},"previousState":{"allOf":[{"$ref":"#/components/schemas/StorefrontSellabilityState"},{"nullable":true,"example":"blocked"}]},"nextState":{"allOf":[{"$ref":"#/components/schemas/StorefrontSellabilityState"},{"nullable":true,"example":"sellable"}]},"availableQuantity":{"type":"integer","nullable":true,"example":0},"source":{"type":"string","example":"storefront-sellability/apply"},"reason":{"type":"string","example":"manual_force_sellable override applied"},"action":{"type":"string","enum":["state_transition","set_override","clear_override","reconcile","config_update"],"example":"set_override"},"outcome":{"$ref":"#/components/schemas/StorefrontSellabilityOutcome"},"correlationId":{"type":"string","example":"corr-storefront-123"},"actorUserId":{"type":"string","nullable":true,"format":"uuid","example":"f0f12cf2-f2f0-45e8-9aa5-adff2e400db7"},"actorEmail":{"type":"string","nullable":true,"format":"email","example":"owner@merchant.example"},"note":{"type":"string","nullable":true,"example":"Allow temporary oversell during launch weekend."},"metadata":{"type":"object","nullable":true,"additionalProperties":{"nullable":true},"example":{"desiredInventoryPolicy":"continue","trigger":"post_apply"}},"actedAt":{"type":"string","format":"date-time","example":"2026-04-03T13:12:00.000Z"}},"required":["id","policyId","merchantId","mappingId","previousState","nextState","availableQuantity","source","reason","action","outcome","correlationId","actorUserId","actorEmail","note","metadata","actedAt"]},"StorefrontSellabilityTransitionHistoryResponse":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/StorefrontSellabilityTransitionHistoryItem"}}},"required":["items"]}},"required":["success","data"]},"StorefrontSellabilityUnmappedInput":{"type":"object","properties":{"id":{"type":"string","format":"uuid","example":"b9a4bc5e-dcb8-4960-95e3-f4e3df68f388"},"merchantId":{"type":"string","format":"uuid","example":"f8a7ff12-2f33-49aa-bf98-6d65ca902000"},"connectionId":{"type":"string","format":"uuid","example":"8a5ea4fe-e728-4604-8422-997d6087d310"},"inventoryItemId":{"type":"integer","example":998877665544},"shopifyLocationId":{"type":"integer","example":11223344},"correlationId":{"type":"string","example":"corr-unmapped-123"},"sourceEventKey":{"type":"string","example":"inventory_levels/update:gid://shopify/InventoryLevel/1"},"reason":{"type":"string","example":"mapping_not_found"},"sourcePayloadDigest":{"type":"string","example":"sha256:abcdef1234567890"},"lookupContext":{"type":"object","additionalProperties":{"nullable":true},"example":{"shopDomain":"merchant-demo.myshopify.com"}},"status":{"type":"string","enum":["open","acknowledged","resolved"],"example":"open"},"firstSeenAt":{"type":"string","format":"date-time","example":"2026-04-03T12:40:00.000Z"},"lastSeenAt":{"type":"string","format":"date-time","example":"2026-04-03T13:10:00.000Z"},"occurrenceCount":{"type":"integer","example":3}},"required":["id","merchantId","connectionId","inventoryItemId","shopifyLocationId","correlationId","sourceEventKey","reason","sourcePayloadDigest","lookupContext","status","firstSeenAt","lastSeenAt","occurrenceCount"]},"StorefrontSellabilityUnmappedInputsResponse":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/StorefrontSellabilityUnmappedInput"}},"summary":{"type":"object","properties":{"openCount":{"type":"integer","example":2},"health":{"$ref":"#/components/schemas/StorefrontSellabilityHealth"}},"required":["openCount","health"]}},"required":["items","summary"]}},"required":["success","data"]},"UpdateStorefrontSellabilityUnmappedInputStatusRequest":{"type":"object","properties":{"id":{"type":"string","format":"uuid","example":"b9a4bc5e-dcb8-4960-95e3-f4e3df68f388"},"status":{"type":"string","enum":["acknowledged","resolved"],"example":"acknowledged","description":"Lifecycle status operators may set for one unmapped diagnostic row."}},"required":["id","status"]},"StorefrontSellabilityUnmappedInputMutationResponse":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/StorefrontSellabilityUnmappedInput"}},"required":["success","data"]},"UpdateStorefrontSellabilityPolicyRequest":{"type":"object","properties":{"enabled":{"type":"boolean","example":true,"description":"Enables or disables the native automatic baseline for the mapping."},"disableThreshold":{"type":"number","enum":[0],"example":0,"description":"Lane A only supports disableThreshold=0."},"reenableThreshold":{"type":"number","enum":[1],"example":1,"description":"Lane A only supports reenableThreshold=1."},"note":{"type":"string","maxLength":1000,"example":"Enable native deny baseline for launch cohort.","description":"Optional operator note stored alongside the resulting transition."}}},"SetStorefrontSellabilityOverrideRequest":{"type":"object","properties":{"mode":{"type":"string","enum":["manual_force_sellable"],"example":"manual_force_sellable","description":"The only supported manual override in Lane A."},"note":{"type":"string","maxLength":1000,"example":"Allow checkout during manual inventory recount."}},"required":["mode"]},"OrderStatus":{"type":"string","enum":["pending","cancelled","inventory_reserved","preparing","shipped","delivered"]},"Channel":{"type":"string","enum":["shopify","amazon","shipstation","manual"]},"OrderItem":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"sku_id":{"type":"string","format":"uuid"},"quantity":{"type":"integer","minimum":0,"exclusiveMinimum":true},"unit_price":{"type":"number","nullable":true},"total_price":{"type":"number","nullable":true},"skus":{"type":"object","nullable":true,"properties":{"sku_code":{"type":"string"},"product_name":{"type":"string","nullable":true},"variant_title":{"type":"string","nullable":true}},"required":["sku_code","product_name","variant_title"]}},"required":["id","sku_id","quantity","unit_price","skus"]},"OrderCustomer":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"email":{"type":"string","nullable":true,"format":"email"},"first_name":{"type":"string","nullable":true},"last_name":{"type":"string","nullable":true},"phone":{"type":"string","nullable":true}},"required":["id","email","first_name","last_name"]},"Order":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"merchant_id":{"type":"string","format":"uuid"},"customer_id":{"type":"string","nullable":true,"format":"uuid"},"order_number":{"type":"string"},"channel_order_id":{"type":"string"},"channel":{"type":"string","enum":["shopify","amazon","shipstation","manual"]},"status":{"type":"string","enum":["pending","cancelled","inventory_reserved","preparing","shipped","delivered"]},"total_amount":{"type":"number","nullable":true},"subtotal_amount":{"type":"number","nullable":true},"tax_amount":{"type":"number","nullable":true},"shipping_amount":{"type":"number","nullable":true},"currency":{"type":"string"},"customer_email":{"type":"string","nullable":true,"format":"email"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"},"order_items":{"type":"array","nullable":true,"items":{"$ref":"#/components/schemas/OrderItem"}},"customers":{"allOf":[{"$ref":"#/components/schemas/OrderCustomer"},{"nullable":true}]}},"required":["id","merchant_id","customer_id","order_number","channel","status","total_amount","subtotal_amount","tax_amount","shipping_amount","created_at","updated_at","order_items","customers"]},"OrderListResponse":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"orders":{"type":"array","items":{"$ref":"#/components/schemas/Order"}},"pagination":{"type":"object","properties":{"page":{"type":"integer"},"limit":{"type":"integer"},"total":{"type":"integer"},"totalPages":{"type":"integer"},"hasNext":{"type":"boolean"},"hasPrev":{"type":"boolean"}},"required":["page","limit","total","totalPages","hasNext","hasPrev"]}},"required":["orders","pagination"]}},"required":["success","data"]},"OrderStatsResponse":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"totalOrders":{"type":"integer"},"pendingOrders":{"type":"integer"},"processingOrders":{"type":"integer"},"shippedOrders":{"type":"integer"},"deliveredOrders":{"type":"integer"},"cancelledOrders":{"type":"integer"},"totalRevenue":{"type":"number"}},"required":["totalOrders","pendingOrders","processingOrders","shippedOrders","deliveredOrders","cancelledOrders","totalRevenue"]}},"required":["success","data"]},"StatusUpdateRequest":{"type":"object","properties":{"status":{"type":"string","enum":["pending","cancelled","inventory_reserved","preparing","shipped","delivered"]},"note":{"type":"string","maxLength":500}},"required":["status"]},"BulkStatusUpdateRequest":{"type":"object","properties":{"orderIds":{"type":"array","items":{"type":"string","format":"uuid"},"minItems":1,"maxItems":100},"status":{"type":"string","enum":["pending","cancelled","inventory_reserved","preparing","shipped","delivered"]}},"required":["orderIds","status"]},"DailyRevenueData":{"type":"object","properties":{"date":{"type":"string","example":"2025-01-15","description":"Business date in YYYY-MM-DD format"},"revenue":{"type":"number","example":1250.5,"description":"Total revenue for the day"},"orderCount":{"type":"integer","example":25,"description":"Number of orders for the day"}},"required":["date","revenue","orderCount"]},"RevenueAnalyticsResponse":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"dailyData":{"type":"array","items":{"$ref":"#/components/schemas/DailyRevenueData"},"description":"Array of daily revenue data points"},"totalRevenue":{"type":"number","example":45000,"description":"Total revenue for the period"},"totalOrders":{"type":"integer","example":850,"description":"Total orders for the period"},"averageOrderValue":{"type":"number","example":52.94,"description":"Average order value for the period"},"revenueChange":{"type":"number","example":12.5,"description":"Percentage change from previous period"},"period":{"type":"string","enum":["7d","30d","90d"],"example":"30d","description":"Time period for analytics"},"startDate":{"type":"string","format":"date-time","example":"2024-12-16T00:00:00.000Z","description":"Start of the analytics period"},"endDate":{"type":"string","format":"date-time","example":"2025-01-15T23:59:59.999Z","description":"End of the analytics period"}},"required":["dailyData","totalRevenue","totalOrders","averageOrderValue","revenueChange","period","startDate","endDate"]}},"required":["success","data"]},"HourlyActivityData":{"type":"object","properties":{"hour":{"type":"integer","minimum":0,"maximum":23,"example":14,"description":"Hour of day (0-23)"},"dayOfWeek":{"type":"integer","minimum":0,"maximum":6,"example":1,"description":"Day of week (0=Sunday, 6=Saturday)"},"count":{"type":"integer","example":15,"description":"Total activity count for this hour/day combination"},"businessHours":{"type":"integer","example":15,"description":"Activity count during business hours"}},"required":["hour","dayOfWeek","count","businessHours"]},"ActivityHeatmapResponse":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"hourlyActivity":{"type":"array","items":{"$ref":"#/components/schemas/HourlyActivityData"},"description":"Array of hourly activity data (168 elements for 7 days × 24 hours)"},"totalActivities":{"type":"integer","example":2500,"description":"Total activity count for the period"},"businessHoursActivities":{"type":"integer","example":2100,"description":"Activity count during business hours"},"businessHoursPercentage":{"type":"integer","example":84,"description":"Percentage of activities during business hours"},"period":{"type":"integer","example":30,"description":"Number of days analyzed"}},"required":["hourlyActivity","totalActivities","businessHoursActivities","businessHoursPercentage","period"]}},"required":["success","data"]},"ComplianceViolation":{"type":"object","properties":{"id":{"type":"string","format":"uuid","example":"123e4567-e89b-12d3-a456-426614174000","description":"Activity log row ID"},"occurred_at":{"type":"string","format":"date-time","example":"2025-01-15T22:30:00.000Z","description":"When the violation occurred (maps to activity_timestamp)"},"severity":{"type":"string","enum":["high","medium","low"],"example":"low","description":"Violation severity coerced from metadata (unknown values default to low)"}},"required":["id","occurred_at","severity"],"additionalProperties":{"nullable":true},"description":"A compliance violation. Metadata keys from the activity log are spread first, then canonical fields (id, occurred_at, severity) overwrite them."},"ComplianceAnalyticsResponse":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"totalViolations":{"type":"integer","example":12,"description":"Total violations in the period"},"highSeverityViolations":{"type":"integer","example":2,"description":"Count of high severity violations"},"mediumSeverityViolations":{"type":"integer","example":5,"description":"Count of medium severity violations"},"lowSeverityViolations":{"type":"integer","example":5,"description":"Count of low severity violations"},"complianceScore":{"type":"integer","minimum":0,"maximum":100,"example":76,"description":"Compliance score (0-100)"},"hasBusinessHoursConfig":{"type":"boolean","example":true,"description":"Whether business hours are configured"},"violations":{"type":"array","items":{"$ref":"#/components/schemas/ComplianceViolation"},"description":"List of violations in the period"},"period":{"type":"string","example":"30d","description":"Time period for analytics"},"startDate":{"type":"string","format":"date-time"},"endDate":{"type":"string","format":"date-time"}},"required":["totalViolations","highSeverityViolations","mediumSeverityViolations","lowSeverityViolations","complianceScore","hasBusinessHoursConfig","violations","period","startDate","endDate"]}},"required":["success","data"]},"BusinessHoursSettings":{"type":"object","properties":{"merchant_id":{"type":"string","format":"uuid"},"monday_enabled":{"type":"boolean"},"monday_open_time":{"type":"string","nullable":true,"example":"09:00"},"monday_close_time":{"type":"string","nullable":true,"example":"17:00"},"monday_lunch_start_time":{"type":"string","nullable":true},"monday_lunch_end_time":{"type":"string","nullable":true},"tuesday_enabled":{"type":"boolean"},"tuesday_open_time":{"type":"string","nullable":true},"tuesday_close_time":{"type":"string","nullable":true},"tuesday_lunch_start_time":{"type":"string","nullable":true},"tuesday_lunch_end_time":{"type":"string","nullable":true},"wednesday_enabled":{"type":"boolean"},"wednesday_open_time":{"type":"string","nullable":true},"wednesday_close_time":{"type":"string","nullable":true},"wednesday_lunch_start_time":{"type":"string","nullable":true},"wednesday_lunch_end_time":{"type":"string","nullable":true},"thursday_enabled":{"type":"boolean"},"thursday_open_time":{"type":"string","nullable":true},"thursday_close_time":{"type":"string","nullable":true},"thursday_lunch_start_time":{"type":"string","nullable":true},"thursday_lunch_end_time":{"type":"string","nullable":true},"friday_enabled":{"type":"boolean"},"friday_open_time":{"type":"string","nullable":true},"friday_close_time":{"type":"string","nullable":true},"friday_lunch_start_time":{"type":"string","nullable":true},"friday_lunch_end_time":{"type":"string","nullable":true},"saturday_enabled":{"type":"boolean"},"saturday_open_time":{"type":"string","nullable":true},"saturday_close_time":{"type":"string","nullable":true},"saturday_lunch_start_time":{"type":"string","nullable":true},"saturday_lunch_end_time":{"type":"string","nullable":true},"sunday_enabled":{"type":"boolean"},"sunday_open_time":{"type":"string","nullable":true},"sunday_close_time":{"type":"string","nullable":true},"sunday_lunch_start_time":{"type":"string","nullable":true},"sunday_lunch_end_time":{"type":"string","nullable":true},"timezone":{"type":"string","example":"America/New_York"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}},"required":["merchant_id","monday_enabled","monday_open_time","monday_close_time","tuesday_enabled","tuesday_open_time","tuesday_close_time","wednesday_enabled","wednesday_open_time","wednesday_close_time","thursday_enabled","thursday_open_time","thursday_close_time","friday_enabled","friday_open_time","friday_close_time","saturday_enabled","saturday_open_time","saturday_close_time","sunday_enabled","sunday_open_time","sunday_close_time","timezone","created_at","updated_at"]},"AbcSummaryCategory":{"type":"object","properties":{"skuCount":{"type":"integer","example":42,"description":"Number of SKUs in this ABC category"},"revenue":{"type":"number","example":12345.67,"description":"Total 90-day revenue for this ABC category"},"revenuePct":{"type":"number","example":80.25,"description":"Revenue share percentage for this category"}},"required":["skuCount","revenue","revenuePct"]},"AbcSummaryRun":{"type":"object","properties":{"classificationDay":{"type":"string","example":"2026-03-01","description":"Classification day for the selected run"},"lookbackDays":{"type":"integer","example":90,"description":"Lookback window used to compute the selected run"},"status":{"type":"string","enum":["completed"],"description":"Selected run status (completed runs are returned only)"},"runAt":{"type":"string","format":"date-time","example":"2026-03-01T05:00:00.000Z","description":"Timestamp when the selected run completed"},"isStale":{"type":"boolean","example":false,"description":"True when selected classificationDay is earlier than requested day"}},"required":["classificationDay","lookbackDays","status","runAt","isStale"]},"AbcSummaryResponse":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"notReady":{"type":"boolean","example":false,"description":"True when no completed run exists at-or-before the requested day"},"run":{"allOf":[{"$ref":"#/components/schemas/AbcSummaryRun"},{"nullable":true}]},"eligible":{"type":"boolean","example":true,"description":"Merchant eligibility state for ABC methodology"},"categories":{"type":"object","properties":{"A":{"$ref":"#/components/schemas/AbcSummaryCategory"},"B":{"$ref":"#/components/schemas/AbcSummaryCategory"},"C":{"$ref":"#/components/schemas/AbcSummaryCategory"},"Unclassified":{"$ref":"#/components/schemas/AbcSummaryCategory"}},"required":["A","B","C","Unclassified"]},"totals":{"type":"object","properties":{"skuCount":{"type":"integer","example":120,"description":"Total SKUs represented in the selected run"},"revenue":{"type":"number","example":45678.9,"description":"Total revenue across all categories"}},"required":["skuCount","revenue"]}},"required":["notReady","run","eligible","categories","totals"]}},"required":["success","data"]},"InventoryPositionSummary":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"location_id":{"type":"string","format":"uuid"},"available_quantity":{"type":"integer","nullable":true},"reserved_quantity":{"type":"integer","nullable":true},"reorder_point":{"type":"integer","nullable":true},"reorder_quantity":{"type":"integer","nullable":true},"locations":{"type":"object","nullable":true,"properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"type":{"type":"string"}},"required":["id","name","type"]}},"required":["id","location_id","available_quantity","reserved_quantity","reorder_point","reorder_quantity","locations"]},"ShopifyMapping":{"type":"object","properties":{"shopify_product_id":{"type":"string","nullable":true},"shopify_title":{"type":"string","nullable":true},"shopify_handle":{"type":"string","nullable":true}},"required":["shopify_product_id","shopify_title","shopify_handle"]},"SKU":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"merchant_id":{"type":"string","format":"uuid"},"sku_code":{"type":"string"},"product_name":{"type":"string","nullable":true},"variant_title":{"type":"string","nullable":true},"description":{"type":"string","nullable":true},"category":{"type":"string","nullable":true},"unit_cost":{"type":"number","nullable":true},"unit_price":{"type":"number","nullable":true},"weight":{"type":"number","nullable":true},"dimensions":{"type":"object","nullable":true,"properties":{"length":{"type":"number"},"width":{"type":"number"},"height":{"type":"number"}}},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"},"abcCategory":{"type":"string","nullable":true,"enum":["A","B","C","Unclassified",null],"description":"ABC classification category for the selected completed run"},"abcRevenue":{"type":"number","nullable":true,"description":"Revenue used for ABC classification for the selected run"},"abcCumulativeRevenuePct":{"type":"number","nullable":true,"description":"Cumulative revenue percentage for this SKU in the selected run"},"inventory_positions":{"type":"array","nullable":true,"items":{"$ref":"#/components/schemas/InventoryPositionSummary"}},"shopify_product_mappings":{"type":"array","nullable":true,"items":{"$ref":"#/components/schemas/ShopifyMapping"}}},"required":["id","merchant_id","sku_code","product_name","variant_title","description","category","unit_cost","unit_price","weight","dimensions","created_at","updated_at","abcCategory","abcRevenue","abcCumulativeRevenuePct","inventory_positions","shopify_product_mappings"]},"SKUListResponse":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"skus":{"type":"array","items":{"$ref":"#/components/schemas/SKU"}},"pagination":{"type":"object","properties":{"page":{"type":"integer"},"limit":{"type":"integer"},"total":{"type":"integer"},"totalPages":{"type":"integer"},"hasNext":{"type":"boolean"},"hasPrev":{"type":"boolean"}},"required":["page","limit","total","totalPages","hasNext","hasPrev"]}},"required":["skus","pagination"]}},"required":["success","data"]},"ProductStatsResponse":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"totalProducts":{"type":"integer"},"activeProducts":{"type":"integer"},"totalSKUs":{"type":"integer"},"totalInventory":{"type":"integer"},"lowStockItems":{"type":"integer"},"lowStockProducts":{"type":"integer"},"outOfStockProducts":{"type":"integer"},"totalValue":{"type":"integer","description":"Total inventory value in cents using the canonical supplier-cost precedence: primary active supplier cost, then any active supplier cost, otherwise 0."},"outOfStockItems":{"type":"integer"},"categoryStats":{"type":"object","additionalProperties":{"type":"integer"}}},"required":["totalProducts","activeProducts","totalSKUs","totalInventory","lowStockItems","lowStockProducts","outOfStockProducts","totalValue","outOfStockItems","categoryStats"]}},"required":["success","data"]},"SKUUpdateRequest":{"type":"object","properties":{"product_name":{"type":"string","minLength":1,"maxLength":255},"variant_title":{"type":"string","maxLength":255},"description":{"type":"string","maxLength":2000},"category":{"type":"string","maxLength":100},"unit_cost":{"type":"number","minimum":0},"unit_price":{"type":"number","minimum":0},"weight":{"type":"number","minimum":0},"dimensions":{"type":"object","properties":{"length":{"type":"number","minimum":0},"width":{"type":"number","minimum":0},"height":{"type":"number","minimum":0}}}}},"Supplier":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"email":{"type":"string","nullable":true,"format":"email"},"phone":{"type":"string","nullable":true},"address":{"type":"string","nullable":true},"city":{"type":"string","nullable":true},"state":{"type":"string","nullable":true},"postal_code":{"type":"string","nullable":true},"country":{"type":"string","nullable":true},"payment_terms":{"type":"string","nullable":true},"notes":{"type":"string","nullable":true},"is_active":{"type":"boolean"},"contact_person":{"type":"string","nullable":true},"contact_phone":{"type":"string","nullable":true},"contact_email":{"type":"string","nullable":true,"format":"email"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}},"required":["id","name","email","phone","address","city","state","postal_code","country","payment_terms","notes","is_active","contact_person","contact_phone","contact_email","created_at","updated_at"]},"CreateSupplierRequest":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":200},"email":{"type":"string","nullable":true,"format":"email"},"phone":{"type":"string","nullable":true,"maxLength":50},"address":{"type":"string","nullable":true,"maxLength":500},"city":{"type":"string","nullable":true,"maxLength":100},"state":{"type":"string","nullable":true,"maxLength":100},"postal_code":{"type":"string","nullable":true,"maxLength":20},"country":{"type":"string","maxLength":2},"payment_terms":{"type":"string","maxLength":100},"notes":{"type":"string","nullable":true,"maxLength":2000},"contact_person":{"type":"string","nullable":true,"maxLength":200},"contact_phone":{"type":"string","nullable":true,"maxLength":50},"contact_email":{"type":"string","nullable":true,"format":"email"}},"required":["name"]},"UpdateSupplierRequest":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":200},"email":{"type":"string","nullable":true,"format":"email"},"phone":{"type":"string","nullable":true,"maxLength":50},"address":{"type":"string","nullable":true,"maxLength":500},"city":{"type":"string","nullable":true,"maxLength":100},"state":{"type":"string","nullable":true,"maxLength":100},"postal_code":{"type":"string","nullable":true,"maxLength":20},"country":{"type":"string","maxLength":2},"payment_terms":{"type":"string","maxLength":100},"notes":{"type":"string","nullable":true,"maxLength":2000},"contact_person":{"type":"string","nullable":true,"maxLength":200},"contact_phone":{"type":"string","nullable":true,"maxLength":50},"contact_email":{"type":"string","nullable":true,"format":"email"},"is_active":{"type":"boolean"}}},"SupplierListResponse":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"$ref":"#/components/schemas/Supplier"}},"pagination":{"type":"object","properties":{"page":{"type":"integer"},"limit":{"type":"integer"},"total":{"type":"integer"},"totalPages":{"type":"integer"},"hasNext":{"type":"boolean"},"hasPrev":{"type":"boolean"}},"required":["page","limit","total","totalPages","hasNext","hasPrev"]}},"required":["success","data","pagination"]},"SupplierDetailResponse":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/Supplier"}},"required":["success","data"]},"StockyImportRun":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"import_reference":{"type":"string","example":"STOCKY-20260509-ABC123"},"status":{"type":"string","enum":["draft","previewed","needs_review","committing","completed","failed","abandoned","expired","purged"]},"source":{"type":"string","example":"dashboard"},"summary":{"type":"object","additionalProperties":{"nullable":true}},"file_count":{"type":"integer","minimum":0},"row_count":{"type":"integer","minimum":0},"ready_row_count":{"type":"integer","minimum":0},"needs_decision_row_count":{"type":"integer","minimum":0},"duplicate_row_count":{"type":"integer","minimum":0},"archive_only_row_count":{"type":"integer","minimum":0},"failed_row_count":{"type":"integer","minimum":0},"raw_retention_expires_at":{"type":"string","nullable":true,"format":"date-time"},"raw_purge_state":{"type":"string","nullable":true,"enum":["not_due","queued","in_progress","purged","failed",null]},"delete_requested_at":{"type":"string","nullable":true,"format":"date-time"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"},"previewed_at":{"type":"string","nullable":true,"format":"date-time"}},"required":["id","import_reference","status","source","summary","file_count","row_count","ready_row_count","needs_decision_row_count","duplicate_row_count","archive_only_row_count","failed_row_count","raw_retention_expires_at","delete_requested_at","created_at","updated_at","previewed_at"]},"StockyImportFile":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"run_id":{"type":"string","format":"uuid"},"upload_index":{"type":"integer","minimum":0},"original_filename":{"type":"string","description":"Sanitized display filename returned only from authenticated Stocky import routes."},"safe_filename":{"type":"string"},"file_role":{"type":"string","enum":["stocky_stocktake","shopify_inventory","supplier_like","po_like","report","unknown_csv","zip_manifest"]},"parse_status":{"type":"string","enum":["pending","detected","parsed","failed","archived","purged"]},"content_type":{"type":"string","nullable":true},"byte_size":{"type":"integer","minimum":0},"checksum_sha256":{"type":"string"},"detected_at":{"type":"string","nullable":true,"format":"date-time"},"row_count":{"type":"integer","minimum":0},"summary":{"type":"object","additionalProperties":{"nullable":true}},"error":{"type":"object","nullable":true,"additionalProperties":{"nullable":true}},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}},"required":["id","run_id","upload_index","original_filename","safe_filename","file_role","parse_status","content_type","byte_size","checksum_sha256","detected_at","row_count","summary","error","created_at","updated_at"]},"StockyImportRow":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"run_id":{"type":"string","format":"uuid"},"file_id":{"type":"string","format":"uuid"},"row_index":{"type":"integer","minimum":1},"segment":{"type":"string","enum":["supplier","stocktake","purchase_order","shopify_inventory","archive","unknown"]},"row_outcome":{"type":"string","enum":["ready","needs_decision","duplicate","skipped","archive_only","created","failed"]},"external_row_key":{"type":"string","nullable":true},"normalized_row":{"type":"object","additionalProperties":{"nullable":true},"description":"Sanitized normalized row values for authenticated preview; raw uploaded row values are never returned."},"validation_errors":{"type":"array","items":{"$ref":"#/components/schemas/StockyImportValidationIssue"}},"decision_required":{"type":"boolean"},"decision_key":{"type":"string","nullable":true},"report_metadata":{"type":"object","additionalProperties":{"nullable":true}},"created_at":{"type":"string","format":"date-time"}},"required":["id","run_id","file_id","row_index","segment","row_outcome","external_row_key","normalized_row","validation_errors","decision_required","decision_key","report_metadata","created_at"]},"StockyImportValidationIssue":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"row":{"type":"integer"},"column":{"type":"string"},"file":{"type":"string"},"kind":{"type":"string"}},"required":["code","message"]},"StockyImportPreviewSummary":{"type":"object","properties":{"file_count":{"type":"integer","minimum":0},"row_count":{"type":"integer","minimum":0},"ready_row_count":{"type":"integer","minimum":0},"needs_decision_row_count":{"type":"integer","minimum":0},"duplicate_row_count":{"type":"integer","minimum":0},"archive_only_row_count":{"type":"integer","minimum":0},"failed_row_count":{"type":"integer","minimum":0},"roles":{"type":"object","additionalProperties":{"type":"integer","minimum":0}},"segments":{"type":"object","additionalProperties":{"type":"integer","minimum":0}}},"required":["file_count","row_count","ready_row_count","needs_decision_row_count","duplicate_row_count","archive_only_row_count","failed_row_count","roles","segments"]},"StockyImportFeatureDisabledError":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string","enum":["BIZ_OPERATION_NOT_ALLOWED"]},"message":{"type":"string","example":"Stocky import assistant is not enabled for this workspace"},"details":{"type":"object","properties":{"kind":{"type":"string","enum":["feature_disabled"]},"feature":{"type":"string","enum":["stocky-import-assistant"]}},"required":["kind","feature"]}},"required":["code","message","details"]}},"required":["success","error"]},"StockyImportConflictError":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string","enum":["BIZ_OPERATION_NOT_ALLOWED","BIZ_RESOURCE_CONFLICT","BIZ_RESOURCE_NOT_FOUND","VALIDATION_FAILED","SYS_DATABASE_ERROR"]},"message":{"type":"string"},"details":{"type":"object","properties":{"kind":{"type":"string","enum":["invalid_status","operation_key_conflict","commit_in_progress","operation_previously_failed","supplier_commit_validation_failed","supplier_commit_failed","supplier_commit_rpc_failed","supplier_rows_not_found","supplier_row_ids_not_found","stocktake_commit_validation_failed","stocktake_count_session_rpc_rejected","stocktake_count_session_rpc_failed","stocktake_resolution_invalid_rows","stocktake_resolution_stale_rows","stocktake_duplicate_choice_invalid","stocktake_duplicate_choice_stale_group","stocktake_unresolved_duplicates","stocktake_rows_not_found","stocktake_row_ids_not_found","stocktake_ready_rows_not_found"]},"status":{"type":"string","enum":["draft","previewed","needs_review","committing","completed","failed","abandoned","expired","purged"]},"mismatch_fields":{"type":"array","items":{"type":"string"}},"errors":{"type":"array","items":{"nullable":true}},"row_outcomes":{"type":"array","items":{"nullable":true}},"row_ids":{"type":"array","items":{"type":"string","format":"uuid"}},"missing_row_ids":{"type":"array","items":{"type":"string","format":"uuid"}},"row_id":{"type":"string","format":"uuid"},"duplicate_key":{"type":"string"},"duplicate_keys":{"type":"array","items":{"type":"string"}},"duplicate_row_ids":{"type":"array","items":{"type":"string","format":"uuid"}}},"additionalProperties":{"nullable":true}}},"required":["code","message"]}},"required":["success","error"]},"StockySupplierMappingDecision":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"run_id":{"type":"string","format":"uuid"},"row_id":{"type":"string","nullable":true,"format":"uuid"},"segment":{"type":"string","enum":["supplier"]},"decision_type":{"type":"string","enum":["supplier_mapping_confirmation"]},"decision_key":{"type":"string"},"decision_status":{"type":"string","enum":["accepted","rejected"]},"decision_payload":{"type":"object","additionalProperties":{"nullable":true}},"decision_summary":{"type":"object","additionalProperties":{"nullable":true}},"decided_at":{"type":"string","nullable":true,"format":"date-time"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}},"required":["id","run_id","row_id","segment","decision_type","decision_key","decision_status","decision_payload","decision_summary","decided_at","created_at","updated_at"]},"StockyStocktakeMappingPreview":{"type":"object","properties":{"noSideEffects":{"type":"boolean","enum":[true],"description":"The mapping preview does not create or modify inventory, count sessions, suppliers, POs, or Shopify writes. It may refresh run-level review state and row outcome counters so the returned run metadata reflects the latest preview."},"rows":{"type":"array","items":{"type":"object","additionalProperties":{"nullable":true}},"description":"Merchant admins receive full matching details. Fulfillment staff receive the same row shape with normalizedRow and sensitive quantity cost fields omitted."},"summary":{"type":"object","additionalProperties":{"nullable":true}}},"required":["noSideEffects","rows","summary"]},"HealthCheckResponse":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"status":{"type":"string","enum":["healthy","degraded","unhealthy"],"example":"healthy","description":"Overall system health status"},"timestamp":{"type":"string","format":"date-time","example":"2025-01-01T00:00:00.000Z"},"version":{"type":"string","example":"1.0.0"},"uptime":{"type":"number","example":3600,"description":"Server uptime in seconds"}},"required":["status","timestamp"]}},"required":["success","data"]},"DetailedHealthResponse":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"status":{"type":"string","enum":["healthy","degraded","unhealthy"]},"timestamp":{"type":"string","format":"date-time"},"version":{"type":"string"},"uptime":{"type":"number"},"checks":{"type":"object","properties":{"database":{"type":"object","properties":{"status":{"type":"string","enum":["healthy","unhealthy"]},"latency":{"type":"number","description":"Database response time in ms"}},"required":["status"]},"memory":{"type":"object","properties":{"status":{"type":"string","enum":["healthy","warning","critical"]},"used":{"type":"number","description":"Memory used in MB"},"total":{"type":"number","description":"Total memory in MB"},"percentage":{"type":"number","description":"Memory usage percentage"}},"required":["status","used","total","percentage"]},"external":{"type":"object","properties":{"shopify":{"type":"object","properties":{"status":{"type":"string","enum":["healthy","unhealthy","unknown"]},"lastCheck":{"type":"string","format":"date-time"}},"required":["status"]},"stripe":{"type":"object","properties":{"status":{"type":"string","enum":["healthy","unhealthy","unknown"]},"lastCheck":{"type":"string","format":"date-time"}},"required":["status"]}}}},"required":["database"]}},"required":["status","timestamp","checks"]}},"required":["success","data"]},"BillingSnapshotResponse":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"billing":{"$ref":"#/components/schemas/BillingSnapshot"}},"required":["billing"]}},"required":["success","data"]},"BillingSnapshot":{"type":"object","properties":{"plan":{"type":"string","enum":["starter","growth","enterprise"],"example":"starter"},"subscriptionTier":{"type":"string","enum":["starter","growth","enterprise"],"example":"starter"},"stripePriceId":{"type":"string","nullable":true,"example":"price_123"},"billingStatus":{"type":"string","enum":["inactive","incomplete","trialing","active","past_due","unpaid","payment_action_required","canceled"],"example":"active"},"nextAction":{"type":"string","enum":["none","select_plan","manage_subscription","update_payment_method","confirm_payment","pending_setup"],"example":"manage_subscription"},"cancelAtPeriodEnd":{"type":"boolean","example":false},"currentPeriodStartAt":{"type":"string","nullable":true,"format":"date-time","example":"2026-04-01T00:00:00.000Z"},"currentPeriodEndAt":{"type":"string","nullable":true,"format":"date-time","example":"2026-05-01T00:00:00.000Z"},"billingProblemStartedAt":{"type":"string","nullable":true,"format":"date-time","example":"2026-04-10T12:00:00.000Z"},"hasStripeCustomer":{"type":"boolean","example":true},"hasStripeSubscription":{"type":"boolean","example":true},"capabilities":{"$ref":"#/components/schemas/BillingCapabilities"},"currentPlan":{"$ref":"#/components/schemas/BillingPlanSummary"},"availablePlans":{"type":"array","items":{"$ref":"#/components/schemas/BillingPlanSummary"}}},"required":["plan","subscriptionTier","stripePriceId","billingStatus","nextAction","cancelAtPeriodEnd","currentPeriodStartAt","currentPeriodEndAt","billingProblemStartedAt","hasStripeCustomer","hasStripeSubscription","capabilities","currentPlan","availablePlans"]},"BillingCapabilities":{"type":"object","properties":{"canManageBilling":{"type":"boolean","example":true},"canStartCheckout":{"type":"boolean","example":true},"canOpenPortal":{"type":"boolean","example":false}},"required":["canManageBilling","canStartCheckout","canOpenPortal"]},"BillingPlanSummary":{"type":"object","nullable":true,"properties":{"lookupKey":{"type":"string","enum":["starter","growth","enterprise"],"example":"growth"},"plan":{"type":"string","enum":["starter","growth","enterprise"],"example":"growth"},"subscriptionTier":{"type":"string","enum":["starter","growth","enterprise"],"example":"growth"},"stripePriceId":{"type":"string","example":"price_123"},"displayName":{"type":"string","example":"Growth"},"description":{"type":"string","example":"Advanced forecasting and team workflows."},"intervalLabel":{"type":"string","example":"Billed monthly"}},"required":["lookupKey","plan","subscriptionTier","stripePriceId","displayName","description","intervalLabel"]},"BillingRateLimitResponse":{"type":"object","properties":{"error":{"type":"string","example":"Rate limit exceeded"},"message":{"type":"string","example":"Too many requests, please try again later."},"retryAfter":{"type":"integer","example":60}},"required":["error","message","retryAfter"]},"BillingServiceUnavailableResponse":{"anyOf":[{"$ref":"#/components/schemas/ErrorResponse"},{"$ref":"#/components/schemas/BillingRateLimitResponse"}]},"BillingSessionUrlResponse":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"url":{"type":"string","format":"uri","example":"https://billing.stripe.com/session/test_123"}},"required":["url"]}},"required":["success","data"]},"BillingCheckoutRequest":{"type":"object","properties":{"lookupKey":{"type":"string","enum":["starter","growth","enterprise"],"example":"growth"}},"required":["lookupKey"]},"ShopifyWebhookPayload":{"type":"object","properties":{"id":{"anyOf":[{"type":"number"},{"type":"string"}]}},"additionalProperties":{"nullable":true}},"ReviewInventoryCountSessionRequest":{"type":"object","properties":{}},"SkuSupplierListResponse":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"$ref":"#/components/schemas/SkuSupplier"}},"pagination":{"type":"object","properties":{"page":{"type":"integer"},"limit":{"type":"integer"},"total":{"type":"integer"},"totalPages":{"type":"integer"},"hasNext":{"type":"boolean"},"hasPrev":{"type":"boolean"}},"required":["page","limit","total","totalPages","hasNext","hasPrev"]}},"required":["success","data","pagination"]},"SkuSupplier":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"supplier_id":{"type":"string","format":"uuid"},"sku_id":{"type":"string","format":"uuid"},"supplier_sku_code":{"type":"string","nullable":true},"unit_cost":{"type":"number","nullable":true},"lead_time_days":{"type":"integer","nullable":true},"minimum_order_quantity":{"type":"number","nullable":true},"is_primary":{"type":"boolean"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"},"supplier":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"is_active":{"type":"boolean"}},"required":["id","name","is_active"]},"sku":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"sku_code":{"type":"string"},"product_name":{"type":"string"}},"required":["id","sku_code","product_name"]}},"required":["id","supplier_id","sku_id","supplier_sku_code","unit_cost","lead_time_days","minimum_order_quantity","is_primary","created_at","updated_at","supplier","sku"]},"SkuSupplierDetailResponse":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/SkuSupplier"}},"required":["success","data"]},"CreateSkuSupplierRequest":{"type":"object","properties":{"supplier_id":{"type":"string","format":"uuid"},"sku_id":{"type":"string","format":"uuid"},"supplier_sku_code":{"type":"string","nullable":true,"maxLength":100},"unit_cost":{"type":"number","nullable":true,"minimum":0},"lead_time_days":{"type":"integer","nullable":true,"minimum":0,"maximum":365},"minimum_order_quantity":{"type":"number","nullable":true,"minimum":0}},"required":["supplier_id","sku_id"]},"UpdateSkuSupplierRequest":{"type":"object","properties":{"supplier_sku_code":{"type":"string","nullable":true,"maxLength":100},"unit_cost":{"type":"number","nullable":true,"minimum":0},"lead_time_days":{"type":"integer","nullable":true,"minimum":0,"maximum":365},"minimum_order_quantity":{"type":"number","nullable":true,"minimum":0}}},"StockyImportRunsResponse":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"runs":{"type":"array","items":{"$ref":"#/components/schemas/StockyImportRun"}}},"required":["runs"]}},"required":["success","data"]},"StockyImportRunResponse":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"run":{"$ref":"#/components/schemas/StockyImportRun"}},"required":["run"]}},"required":["success","data"]},"StockyImportFilesResponse":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"files":{"type":"array","items":{"$ref":"#/components/schemas/StockyImportFile"}}},"required":["files"]}},"required":["success","data"]},"StockyImportUploadResponse":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"run":{"$ref":"#/components/schemas/StockyImportRun"},"files":{"type":"array","items":{"$ref":"#/components/schemas/StockyImportFile"}},"rows":{"type":"array","items":{"$ref":"#/components/schemas/StockyImportRow"},"maxItems":500,"description":"First 500 persisted preview rows; use the preview route for the full persisted preview."},"summary":{"$ref":"#/components/schemas/StockyImportPreviewSummary"}},"required":["run","files","rows","summary"]}},"required":["success","data"]},"StockyImportCsvValidationError":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string","enum":["VALID_INVALID_INPUT_FORMAT"]},"message":{"type":"string"},"details":{"type":"object","properties":{"issues":{"type":"array","items":{"$ref":"#/components/schemas/StockyImportValidationIssue"}}},"required":["issues"]}},"required":["code","message","details"]}},"required":["success","error"]},"StockyImportPreviewResponse":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"run":{"$ref":"#/components/schemas/StockyImportRun"},"files":{"type":"array","items":{"$ref":"#/components/schemas/StockyImportFile"}},"rows":{"type":"array","items":{"$ref":"#/components/schemas/StockyImportRow"}},"page":{"$ref":"#/components/schemas/StockyImportPreviewPage"}},"required":["run","files","rows","page"]}},"required":["success","data"]},"StockyImportPreviewPage":{"type":"object","properties":{"limit":{"type":"integer","minimum":1,"maximum":50000},"offset":{"type":"integer","minimum":0},"returned_row_count":{"type":"integer","minimum":0},"total_row_count":{"type":"integer","minimum":0},"has_more":{"type":"boolean"},"truncated":{"type":"boolean"}},"required":["limit","offset","returned_row_count","total_row_count","has_more","truncated"]},"StockySupplierMappingsResponse":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"run":{"$ref":"#/components/schemas/StockyImportRun"},"rows":{"type":"array","items":{"$ref":"#/components/schemas/StockySupplierPreviewRow"}},"decisions":{"type":"array","items":{"$ref":"#/components/schemas/StockySupplierMappingDecision"}}},"required":["run","decisions"]}},"required":["success","data"]},"StockySupplierPreviewRow":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"row_index":{"type":"integer","minimum":1},"row_outcome":{"type":"string","enum":["ready","needs_decision","duplicate","skipped","archive_only","created","failed"]},"source_label":{"type":"string","enum":["merchant_csv","cpfrapp_template","stocky_po_report_hint","shopify_vendor_signal"]},"source_label_text":{"type":"string"},"mapping_confidence":{"type":"number","minimum":0,"maximum":1},"confirmation_required":{"type":"boolean"},"decision_key":{"type":"string"},"import_row":{"type":"object","nullable":true,"additionalProperties":{"nullable":true}},"errors":{"type":"array","items":{"$ref":"#/components/schemas/StockyImportValidationIssue"}}},"required":["id","row_index","row_outcome","source_label","source_label_text","mapping_confidence","confirmation_required","decision_key","import_row","errors"]},"StockySupplierMappingRequest":{"type":"object","properties":{"decisions":{"type":"array","items":{"type":"object","properties":{"rowId":{"type":"string","nullable":true,"format":"uuid"},"decisionKey":{"type":"string","minLength":1,"maxLength":200},"decisionStatus":{"type":"string","enum":["accepted","rejected"]},"sourceLabel":{"type":"string","enum":["merchant_csv","cpfrapp_template","stocky_po_report_hint","shopify_vendor_signal"]},"mappedColumns":{"type":"object","additionalProperties":{"type":"string"}},"notes":{"type":"string","nullable":true,"maxLength":500}},"required":["decisionKey","decisionStatus","sourceLabel"]},"minItems":1,"maxItems":500}},"required":["decisions"]},"StockySupplierCommitResponse":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"replayed":{"type":"boolean"},"segment":{"type":"string","enum":["supplier"]},"success":{"type":"boolean","enum":[true]},"operation_key":{"type":"string"},"created_suppliers":{"type":"integer","minimum":0},"created_mappings":{"type":"integer","minimum":0},"suppliers":{"type":"array","items":{"nullable":true}},"row_outcomes":{"type":"array","items":{"$ref":"#/components/schemas/StockyRowOutcomeResult"}}},"required":["replayed","segment","success","operation_key","created_suppliers","created_mappings","suppliers","row_outcomes"]}},"required":["success","data"]},"StockyRowOutcomeResult":{"type":"object","properties":{"row_id":{"type":"string","format":"uuid"},"outcome":{"type":"string","enum":["ready","needs_decision","duplicate","skipped","archive_only","created","failed"]},"message":{"type":"string"}},"required":["row_id","outcome"]},"StockySupplierCommitRequest":{"type":"object","properties":{"operationKey":{"type":"string","minLength":8,"maxLength":128,"pattern":"^[A-Za-z0-9._:-]+$"},"rowIds":{"type":"array","items":{"type":"string","format":"uuid"},"minItems":1,"maxItems":5000}},"required":["operationKey"]},"StockyStocktakeMappingResponse":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"run":{"$ref":"#/components/schemas/StockyImportRun"},"stocktake":{"$ref":"#/components/schemas/StockyStocktakeMappingPreview"}},"required":["run","stocktake"]}},"required":["success","data"]},"StockyStocktakeResolutionRequest":{"oneOf":[{"type":"object","properties":{"rowIds":{"type":"array","items":{"type":"string","format":"uuid"},"minItems":1,"maxItems":500},"decisionStatus":{"type":"string","enum":["skipped"]}},"required":["rowIds","decisionStatus"]},{"type":"object","properties":{"chosenRowId":{"type":"string","format":"uuid"},"decisionStatus":{"type":"string","enum":["chosen_duplicate"]}},"required":["chosenRowId","decisionStatus"]}],"description":"Resolve stocktake review rows by either skipping selected ambiguous rows or choosing one row from a duplicate SKU/location group."},"StockyStocktakeCommitResponse":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"replayed":{"type":"boolean"},"segment":{"type":"string","enum":["stocktake"]},"success":{"type":"boolean","enum":[true]},"operation_key":{"type":"string"},"count_session_id":{"type":"string","format":"uuid"},"created_lines":{"type":"integer","minimum":0},"session":{"$ref":"#/components/schemas/StockyCreatedCountSession"},"lines":{"type":"array","items":{"$ref":"#/components/schemas/StockyCreatedCountLine"}},"row_outcomes":{"type":"array","items":{"$ref":"#/components/schemas/StockyRowOutcomeResult"}}},"required":["replayed","segment","success","operation_key","count_session_id","created_lines","session","lines","row_outcomes"]}},"required":["success","data"]},"StockyCreatedCountSession":{"type":"object","additionalProperties":{"nullable":true},"description":"Serialized inventory count session returned by the existing count-session serializer."},"StockyCreatedCountLine":{"type":"object","additionalProperties":{"nullable":true},"description":"Serialized inventory count line returned by the existing count-line serializer."},"StockyStocktakeCommitRequest":{"type":"object","properties":{"operationKey":{"type":"string","minLength":8,"maxLength":128,"pattern":"^[A-Za-z0-9._:-]+$"},"rowIds":{"type":"array","items":{"type":"string","format":"uuid"},"minItems":1,"maxItems":500},"name":{"type":"string","minLength":1,"maxLength":120}},"required":["operationKey"]}},"parameters":{}},"paths":{"/api/docs/openapi.json":{"get":{"tags":["Documentation"],"summary":"Public OpenAPI JSON specification","description":"Returns the public unversioned OpenAPI JSON document used by `/docs` and other external consumers.","security":[],"responses":{"200":{"description":"OpenAPI specification as JSON","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpenApiDocument"}}}},"500":{"description":"Failed to generate the OpenAPI specification","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DocumentationFlatError"}}}}}}},"/api/docs/openapi.yaml":{"get":{"tags":["Documentation"],"summary":"Authenticated OpenAPI YAML specification","description":"Returns the OpenAPI document serialized as YAML for authenticated same-site users.","security":[{"BearerAuth":[]}],"responses":{"200":{"description":"OpenAPI specification serialized as YAML","content":{"application/yaml":{"schema":{"type":"string","example":"openapi: 3.0.3"}}}},"401":{"description":"Unauthorized - Missing or invalid authentication","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/docs/openapi":{"get":{"tags":["Documentation"],"summary":"Versioned OpenAPI JSON mirror","description":"Returns the versioned OpenAPI JSON document through the canonical `/api/v1/**` wrapper, including standard v1 headers and rate limiting.","security":[],"responses":{"200":{"description":"OpenAPI specification as JSON","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpenApiDocument"}}}},"429":{"description":"Too Many Requests - Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Failed to generate the OpenAPI specification","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DocumentationFlatError"}}}},"503":{"description":"OpenAPI generation is temporarily unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DocumentationFlatError"}}}}}}},"/api/v1/docs/swagger":{"get":{"tags":["Documentation"],"summary":"Authenticated Swagger UI shell","description":"Returns the authenticated HTML shell for Swagger UI. The page loads its spec from `/api/v1/docs/openapi`.","security":[{"BearerAuth":[]}],"responses":{"200":{"description":"Swagger UI HTML shell","content":{"text/html":{"schema":{"type":"string","example":"openapi: 3.0.3"}}}},"401":{"description":"Unauthorized - Missing or invalid authentication","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/docs/changelog":{"get":{"tags":["Documentation"],"summary":"API changelog document","description":"Returns the rendered API changelog document sourced from `docs/api/changelog.md` via the canonical v1 wrapper.","security":[],"responses":{"200":{"description":"API changelog document","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DocumentationChangelogResponse"}}}},"404":{"description":"Not Found - Resource does not exist","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/health":{"get":{"tags":["Health"],"summary":"Basic health check","description":"Returns basic health status of the API server. Used for load balancer health checks.","security":[],"responses":{"200":{"description":"Service is healthy","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HealthCheckResponse"}}}},"503":{"description":"Service unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/health/detailed":{"get":{"tags":["Health"],"summary":"Detailed health check","description":"Returns detailed health status including database, memory, and external service checks.","security":[{"BearerAuth":[]}],"responses":{"200":{"description":"Detailed health status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DetailedHealthResponse"}}}},"400":{"description":"Bad Request - Invalid input parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Missing or invalid authentication","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden - CSRF violation or insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource does not exist","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too Many Requests - Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"503":{"description":"Service Unavailable - Rate limiting service is temporarily unavailable","headers":{"Retry-After":{"schema":{"type":"string"},"description":"Seconds until the client should retry the request."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/health/live":{"get":{"tags":["Health"],"summary":"Liveness probe","description":"Kubernetes liveness probe endpoint. Returns 200 if the server is running.","security":[],"responses":{"200":{"description":"Server is alive","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","enum":["alive"]}},"required":["status"]}}}}}}},"/api/health/ready":{"get":{"tags":["Health"],"summary":"Readiness probe","description":"Kubernetes readiness probe endpoint. Returns 200 if the server is ready to accept traffic based on internal dependencies and required configuration. External dependency visibility remains available through /api/health/external and /api/health/shopify.","security":[],"responses":{"200":{"description":"Server is ready","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","enum":["ready"]},"checks":{"type":"object","properties":{"database":{"type":"boolean"}},"required":["database"]}},"required":["status","checks"]}}}},"503":{"description":"Server not ready","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","enum":["not_ready"]},"reason":{"type":"string"}},"required":["status","reason"]}}}}}}},"/api/health/database":{"get":{"tags":["Health"],"summary":"Database health check","description":"Check database connectivity and response time.","security":[{"BearerAuth":[]}],"responses":{"200":{"description":"Database is healthy","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"status":{"type":"string","enum":["healthy","unhealthy"]},"latency":{"type":"number","description":"Response time in ms"},"connectionPool":{"type":"object","properties":{"active":{"type":"number"},"idle":{"type":"number"},"total":{"type":"number"}},"required":["active","idle","total"]}},"required":["status","latency"]}},"required":["success","data"]}}}},"400":{"description":"Bad Request - Invalid input parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Missing or invalid authentication","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden - CSRF violation or insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource does not exist","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too Many Requests - Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"503":{"description":"Service Unavailable - Rate limiting service is temporarily unavailable","headers":{"Retry-After":{"schema":{"type":"string"},"description":"Seconds until the client should retry the request."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/auth/me":{"get":{"tags":["Authentication"],"summary":"Get current user","description":"Returns the currently authenticated user profile along with merchant information and permissions.","security":[{"BearerAuth":[]}],"responses":{"200":{"description":"Current user information","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"profile":{"type":"object","properties":{"id":{"type":"string"},"email":{"type":"string","format":"email"},"role":{"type":"string","enum":["merchant_admin","fulfillment_staff","support_rep"]},"merchant_id":{"type":"string","nullable":true},"is_active":{"type":"boolean"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}},"required":["id","email","role","merchant_id","is_active","created_at","updated_at"],"additionalProperties":false},"merchant":{"type":"object","nullable":true,"properties":{"id":{"type":"string"},"name":{"type":"string"},"domain":{"type":"string","nullable":true},"settings":{"type":"object","nullable":true,"additionalProperties":{"nullable":true}},"is_active":{"type":"boolean"}},"required":["id","name","domain","settings","is_active"],"additionalProperties":false},"permissions":{"type":"object","nullable":true,"properties":{"can_view_merchant":{"type":"boolean"},"can_edit_merchant":{"type":"boolean"},"can_manage_users":{"type":"boolean"},"can_view_inventory":{"type":"boolean"},"can_edit_inventory":{"type":"boolean"},"can_manage_orders":{"type":"boolean"},"can_access_analytics":{"type":"boolean"},"merchant_id":{"type":"string"}},"required":["can_view_merchant","can_edit_merchant","can_manage_users","can_view_inventory","can_edit_inventory","can_manage_orders","can_access_analytics","merchant_id"],"additionalProperties":false}},"required":["profile","merchant","permissions"],"additionalProperties":false},"meta":{"type":"object","properties":{"version":{"type":"string"},"timestamp":{"type":"string","format":"date-time"},"requestId":{"type":"string"},"correlationId":{"type":"string"}},"required":["timestamp"]},"pagination":{"type":"object","properties":{"page":{"type":"integer"},"limit":{"type":"integer"},"total":{"type":"integer"},"totalPages":{"type":"integer"},"hasNext":{"type":"boolean"},"hasPrev":{"type":"boolean"}},"required":["page","limit","total","totalPages","hasNext","hasPrev"]}},"required":["success","data"],"additionalProperties":false}}}},"401":{"description":"Unauthorized - Missing or invalid authentication","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/billing":{"get":{"tags":["Billing"],"summary":"Get merchant billing snapshot","description":"Returns the authenticated merchant billing snapshot, including Stripe linkage state, derived next action, and available catalog plans. Merchant context is always derived from an authenticated bearer token or same-site browser session.","security":[{"BearerAuth":[]},{"SessionCookieAuth":[]}],"responses":{"200":{"description":"Billing snapshot for the authenticated merchant","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BillingSnapshotResponse"}}}},"401":{"description":"Unauthorized - Missing or invalid authentication","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden - CSRF violation or insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too Many Requests - Rate limit exceeded for this billing endpoint","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BillingRateLimitResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"503":{"description":"Stripe billing is disabled or misconfigured in this environment, or the route-level rate-limiting service is temporarily unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BillingServiceUnavailableResponse"}}}}}}},"/api/v1/billing/checkout":{"post":{"tags":["Billing"],"summary":"Create Stripe Checkout session","description":"Creates a Stripe-hosted Checkout session for the authenticated merchant admin. Callers may authenticate with a bearer token or a same-site browser session; browser-session callers must include a valid CSRF token.","security":[{"BearerAuth":[]},{"SessionCookieAuth":[],"CSRFToken":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BillingCheckoutRequest"}}}},"responses":{"200":{"description":"Stripe Checkout session created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BillingSessionUrlResponse"}}}},"400":{"description":"Bad Request - Invalid input parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Missing or invalid authentication","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden - CSRF violation or insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Conflict - Merchant billing state does not allow the requested action","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too Many Requests - Rate limit exceeded for this billing endpoint","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BillingRateLimitResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"503":{"description":"Stripe billing is disabled or misconfigured in this environment, or the route-level rate-limiting service is temporarily unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BillingServiceUnavailableResponse"}}}}}}},"/api/v1/billing/portal":{"post":{"tags":["Billing"],"summary":"Create Stripe Billing Portal session","description":"Creates a Stripe-hosted Billing Portal session for the authenticated merchant admin. Callers may authenticate with a bearer token or a same-site browser session; browser-session callers must include a valid CSRF token.","security":[{"BearerAuth":[]},{"SessionCookieAuth":[],"CSRFToken":[]}],"responses":{"200":{"description":"Stripe Billing Portal session created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BillingSessionUrlResponse"}}}},"401":{"description":"Unauthorized - Missing or invalid authentication","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden - CSRF violation or insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Conflict - Merchant billing state does not allow the requested action","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too Many Requests - Rate limit exceeded for this billing endpoint","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BillingRateLimitResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"503":{"description":"Stripe billing is disabled or misconfigured in this environment, or the route-level rate-limiting service is temporarily unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BillingServiceUnavailableResponse"}}}}}}},"/api/v1/shopify/oauth/initiate":{"post":{"tags":["Shopify OAuth"],"summary":"Initiate Shopify OAuth","description":"Starts the canonical Shopify OAuth flow. Merchant identity is derived from the authenticated session, and request-body `merchantId` is rejected.","security":[{"BearerAuth":[]}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OAuthInitiateRequest"}}}},"responses":{"200":{"description":"OAuth initiation successful","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OAuthInitiateResponse"}}}},"400":{"description":"Bad Request - Invalid input parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Missing or invalid authentication","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too Many Requests - Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/shopify/connect":{"post":{"tags":["Shopify OAuth"],"summary":"Connect Shopify store","description":"Starts the canonical v1 connect flow. This route returns `authUrl`, while `/api/v1/shopify/oauth/initiate` returns `authorizationUrl`.","security":[{"BearerAuth":[]}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ShopifyConnectRequest"}}}},"responses":{"200":{"description":"Connection initiation successful","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ShopifyConnectResponse"}}}},"400":{"description":"Bad Request - Invalid input parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Missing or invalid authentication","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too Many Requests - Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/shopify/oauth/callback":{"get":{"tags":["Shopify OAuth"],"summary":"Canonical Shopify OAuth callback","description":"Callback endpoint invoked by Shopify. The runtime requires `code`, `shop`, `state`, `host`, `hmac`, and `timestamp`, then redirects to the appropriate application route.","security":[],"parameters":[{"name":"code","in":"query","required":true,"schema":{"type":"string"},"description":"Authorization code from Shopify."},{"name":"hmac","in":"query","required":true,"schema":{"type":"string"},"description":"HMAC signature for Shopify callback verification."},{"name":"shop","in":"query","required":true,"schema":{"type":"string"},"description":"Shopify shop domain."},{"name":"state","in":"query","required":true,"schema":{"type":"string"},"description":"OAuth state token generated during initiation."},{"name":"timestamp","in":"query","required":true,"schema":{"type":"string"},"description":"Callback timestamp from Shopify."},{"name":"host","in":"query","required":true,"schema":{"type":"string"},"description":"Encoded Shopify host parameter required by the runtime callback handler."}],"responses":{"307":{"description":"Redirect response. The callback redirects to `/onboarding/claim`, `/install/error`, or `/auth/login` depending on claimability and recovery state.","headers":{"Location":{"schema":{"type":"string"},"description":"Redirect target selected by the callback flow."}}}}}},"/api/shopify/connect":{"post":{"tags":["Shopify OAuth"],"summary":"Legacy Shopify connect compatibility route","description":"Deprecated compatibility shim for existing integrations. New integrations should use `POST /api/v1/shopify/connect`.","deprecated":true,"security":[{"BearerAuth":[]}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ShopifyConnectRequest"}}}},"responses":{"200":{"description":"Legacy compatibility success envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LegacyShopifyConnectResponse"}}}},"400":{"description":"Bad Request - Invalid input parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Missing or invalid authentication","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too Many Requests - Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/shopify/oauth/callback":{"get":{"tags":["Shopify OAuth"],"summary":"Legacy Shopify OAuth callback alias","description":"Deprecated compatibility alias that proxies to the canonical v1 OAuth callback and preserves redirect-only behavior.","deprecated":true,"security":[],"parameters":[{"name":"code","in":"query","required":true,"schema":{"type":"string"},"description":"Authorization code from Shopify."},{"name":"hmac","in":"query","required":true,"schema":{"type":"string"},"description":"HMAC signature for Shopify callback verification."},{"name":"shop","in":"query","required":true,"schema":{"type":"string"},"description":"Shopify shop domain."},{"name":"state","in":"query","required":true,"schema":{"type":"string"},"description":"OAuth state token generated during initiation."},{"name":"timestamp","in":"query","required":true,"schema":{"type":"string"},"description":"Callback timestamp from Shopify."},{"name":"host","in":"query","required":true,"schema":{"type":"string"},"description":"Encoded Shopify host parameter required by the runtime callback handler."}],"responses":{"307":{"description":"Redirect response. The callback redirects to `/onboarding/claim`, `/install/error`, or `/auth/login` depending on claimability and recovery state.","headers":{"Location":{"schema":{"type":"string"},"description":"Redirect target selected by the callback flow."}}}}}},"/api/shopify/callback":{"get":{"tags":["Shopify OAuth"],"summary":"Legacy Shopify callback alias","description":"Deprecated compatibility alias for the canonical v1 OAuth callback.","deprecated":true,"security":[],"parameters":[{"name":"code","in":"query","required":true,"schema":{"type":"string"},"description":"Authorization code from Shopify."},{"name":"hmac","in":"query","required":true,"schema":{"type":"string"},"description":"HMAC signature for Shopify callback verification."},{"name":"shop","in":"query","required":true,"schema":{"type":"string"},"description":"Shopify shop domain."},{"name":"state","in":"query","required":true,"schema":{"type":"string"},"description":"OAuth state token generated during initiation."},{"name":"timestamp","in":"query","required":true,"schema":{"type":"string"},"description":"Callback timestamp from Shopify."},{"name":"host","in":"query","required":true,"schema":{"type":"string"},"description":"Encoded Shopify host parameter required by the runtime callback handler."}],"responses":{"307":{"description":"Redirect response. The callback redirects to `/onboarding/claim`, `/install/error`, or `/auth/login` depending on claimability and recovery state.","headers":{"Location":{"schema":{"type":"string"},"description":"Redirect target selected by the callback flow."}}}}}},"/api/v1/shopify/connections":{"get":{"tags":["Shopify Connections"],"summary":"List Shopify connections","description":"Returns canonical v1 Shopify connections for the authenticated merchant using limit/offset pagination and optional enrichment flags.","security":[{"BearerAuth":[]}],"parameters":[{"name":"status","in":"query","required":false,"schema":{"type":"string","enum":["connected","disconnected","error","pending"]},"description":"Optional connection status filter."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":20,"minimum":1,"maximum":100},"description":"Maximum number of connections to return."},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","default":0,"minimum":0},"description":"Number of rows to skip before returning results."},{"name":"includeHealth","in":"query","required":false,"schema":{"type":"boolean","default":false},"description":"Include per-connection health details when available."},{"name":"includeWebhooks","in":"query","required":false,"schema":{"type":"boolean","default":false},"description":"Include webhook count metadata for each connection."}],"responses":{"200":{"description":"Canonical v1 Shopify connections response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1ShopifyConnectionsListResponse"}}}},"400":{"description":"Invalid query parameter values","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ShopifyConnectionsCompatError"}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ShopifyConnectionsCompatError"}}}},"429":{"description":"Too Many Requests - Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Connections fetch failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ShopifyConnectionsCompatStructuredError"}}}}}}},"/api/shopify/connections":{"get":{"tags":["Shopify Connections"],"summary":"Legacy Shopify connections collection route","description":"Deprecated compatibility route. Returns the legacy nested collection envelope under `data.connections`.","deprecated":true,"security":[{"BearerAuth":[]}],"parameters":[{"name":"status","in":"query","required":false,"schema":{"type":"string","enum":["connected","disconnected","error","pending"]},"description":"Optional connection status filter."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":20,"minimum":1,"maximum":100},"description":"Maximum number of connections to return."},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","default":0,"minimum":0},"description":"Number of rows to skip before returning results."},{"name":"includeHealth","in":"query","required":false,"schema":{"type":"boolean","default":false},"description":"Include per-connection health details when available."},{"name":"includeWebhooks","in":"query","required":false,"schema":{"type":"boolean","default":false},"description":"Include webhook count metadata for each connection."}],"responses":{"200":{"description":"Legacy compatibility list response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LegacyShopifyConnectionsListResponse"}}}},"400":{"description":"Invalid query parameter values","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ShopifyConnectionsCompatError"}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ShopifyConnectionsCompatError"}}}},"429":{"description":"Too Many Requests - Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Connections fetch failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ShopifyConnectionsCompatStructuredError"}}}}}},"post":{"tags":["Shopify Connections"],"summary":"Legacy Shopify connection creation route","description":"Deprecated compatibility route for validating a shop domain before starting OAuth. New integrations should use the canonical v1 connect or initiate endpoints.","deprecated":true,"security":[{"BearerAuth":[]}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LegacyCreateShopifyConnectionRequest"}}}},"responses":{"200":{"description":"Shop domain validated for OAuth hand-off","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LegacyCreateShopifyConnectionResponse"}}}},"400":{"description":"Bad Request - Invalid input parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Missing or invalid authentication","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource does not exist","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Shop already connected","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too Many Requests - Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/shopify/connections/{id}":{"delete":{"tags":["Shopify Connections"],"summary":"Disconnect a Shopify connection","description":"Current authoritative manual disconnect route for a Shopify store connection. This operation remains unversioned until a versioned delete endpoint exists, returns 204 on success, preserves anti-enumeration with 404 for missing or cross-merchant IDs, and can still return 403 for role/profile or explicit access-denied failures.","security":[{"BearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"Connection ID."}],"responses":{"204":{"description":"Connection disconnected successfully"},"400":{"description":"Bad Request - Invalid input parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Missing or invalid authentication","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden - CSRF violation or insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource does not exist","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too Many Requests - Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/shopify/sync/start":{"post":{"tags":["Sync"],"summary":"Start Shopify synchronization","description":"Starts the canonical v1 Shopify sync job by enqueueing durable background work. The response preserves `started: true` for compatibility and adds `queued: true` plus `executionMode: durable`; it does not return an estimated duration.","security":[{"BearerAuth":[]}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StartSyncRequest"}}}},"responses":{"200":{"description":"Sync job started successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StartSyncResponse"}}}},"400":{"description":"Bad Request - Invalid input parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Missing or invalid authentication","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource does not exist","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too Many Requests - Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"get":{"tags":["Sync"],"summary":"Get Shopify sync status","description":"Returns canonical Shopify sync log history and aggregate status for a connection, optionally filtered by correlation ID. Webhook-processing audit rows are excluded from this sync-status contract.","security":[{"BearerAuth":[]}],"parameters":[{"name":"connectionId","in":"query","required":true,"schema":{"type":"string","format":"uuid"},"description":"Shopify connection ID to inspect."},{"name":"correlationId","in":"query","required":false,"schema":{"type":"string"},"description":"Optional correlation ID returned from the start route."}],"responses":{"200":{"description":"Current sync status for the requested connection.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SyncStatusResponse"}}}},"400":{"description":"Bad Request - Invalid input parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Missing or invalid authentication","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource does not exist","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too Many Requests - Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/shopify/sync/start":{"post":{"tags":["Sync"],"summary":"Legacy Shopify sync start compatibility route","description":"Deprecated compatibility shim that proxies directly to `POST /api/v1/shopify/sync/start` and preserves the canonical response body.","deprecated":true,"security":[{"BearerAuth":[]}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StartSyncRequest"}}}},"responses":{"200":{"description":"Compatibility success response from the canonical v1 handler","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StartSyncResponse"}}}},"400":{"description":"Bad Request - Invalid input parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Missing or invalid authentication","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource does not exist","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too Many Requests - Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"get":{"tags":["Sync"],"summary":"Legacy Shopify sync status compatibility route","description":"Deprecated compatibility shim that proxies directly to `GET /api/v1/shopify/sync/start`.","deprecated":true,"security":[{"BearerAuth":[]}],"parameters":[{"name":"connectionId","in":"query","required":true,"schema":{"type":"string","format":"uuid"},"description":"Shopify connection ID to inspect."},{"name":"correlationId","in":"query","required":false,"schema":{"type":"string"},"description":"Optional correlation ID returned from the start route."}],"responses":{"200":{"description":"Compatibility status response from the canonical v1 handler","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SyncStatusResponse"}}}},"400":{"description":"Bad Request - Invalid input parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Missing or invalid authentication","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource does not exist","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too Many Requests - Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/shopify/webhooks":{"post":{"tags":["Webhooks"],"summary":"Canonical Shopify webhook ingress","description":"\n**Internal endpoint - called by Shopify**\n\nCanonical ingress for Shopify webhook delivery.\nThe topic is provided in the `x-shopify-topic` header and routed internally.\n","security":[],"parameters":[{"name":"x-shopify-topic","in":"header","required":true,"schema":{"type":"string"},"description":"Shopify webhook topic (for example: orders/create or orders/paid)."},{"name":"x-shopify-shop-domain","in":"header","required":true,"schema":{"type":"string"},"description":"Shop domain that sent the webhook."},{"name":"x-shopify-webhook-id","in":"header","required":false,"schema":{"type":"string"},"description":"Optional unique webhook delivery identifier."},{"name":"x-shopify-hmac-sha256","in":"header","required":true,"schema":{"type":"string"},"description":"HMAC signature for request authenticity verification."}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ShopifyWebhookPayload"}}}},"responses":{"200":{"description":"Webhook ingress completed without a retryable durability failure. Inspect the ingress response headers for decision, outcome, durability, and dedupe context; HTTP 200 alone does not imply enqueue.","headers":{"x-ingress-topic":{"schema":{"type":"string"},"description":"Resolved Shopify webhook topic from the incoming x-shopify-topic header."},"X-Correlation-ID":{"schema":{"type":"string"},"description":"Correlation ID for tracing ingress handling and support investigations."},"x-ingress-decision":{"schema":{"type":"string","enum":["accepted","accepted_degraded","blocked","blocked_rate_limited"]},"description":"Top-level ingress decision. HTTP 200 alone does not imply enqueue or durable persistence."},"x-ingress-enqueued":{"schema":{"type":"boolean"},"description":"Boolean convenience flag indicating whether the delivery was enqueued."},"x-ingress-outcome":{"schema":{"type":"string","enum":["enqueued","dropped","degraded","validated_only"]},"description":"Resolved ingress outcome after decision, durability, and deduplication are applied."},"x-ingress-durability":{"schema":{"type":"string","enum":["not_required","persisted","failed","skipped_disabled"]},"description":"Durability state for persist-before-ack handling."},"x-processing-detail":{"schema":{"type":"string","enum":["processed_full","processed_partial","duplicate_skipped","rejected","degraded"]},"description":"Processing detail for accepted, degraded, duplicate, or rejected deliveries."},"x-ingress-blocked-reason":{"schema":{"type":"string","enum":["rate_limited","replay_detected","replay_protection_unavailable","payload_invalid_json","route_topic_mismatch","ambiguous_shop_domain","shop_domain_mismatch"]},"description":"Specific public blocked-reason header value when ingress exposes one, including ambiguous_shop_domain for accepted_degraded tenant-resolution ambiguity."},"x-ingress-enqueue-status":{"schema":{"type":"string","enum":["enqueued","duplicate_rejected"]},"description":"Enqueue state when ingress needs to distinguish a deduplicated duplicate from a fresh enqueue."},"x-ingress-incident":{"schema":{"type":"string"},"description":"Optional incident identifier emitted when ingress surfaces an incident-aware degraded or recovery path."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ShopifyWebhookIngressResponseBody"}}}},"503":{"description":"Ingress could not safely acknowledge delivery. Shopify should retry this delivery after the indicated delay.","headers":{"x-ingress-topic":{"schema":{"type":"string"},"description":"Resolved Shopify webhook topic from the incoming x-shopify-topic header."},"X-Correlation-ID":{"schema":{"type":"string"},"description":"Correlation ID for tracing ingress handling and support investigations."},"x-ingress-decision":{"schema":{"type":"string","enum":["accepted","accepted_degraded","blocked","blocked_rate_limited"]},"description":"Top-level ingress decision. HTTP 200 alone does not imply enqueue or durable persistence."},"x-ingress-enqueued":{"schema":{"type":"boolean"},"description":"Boolean convenience flag indicating whether the delivery was enqueued."},"x-ingress-outcome":{"schema":{"type":"string","enum":["enqueued","dropped","degraded","validated_only"]},"description":"Resolved ingress outcome after decision, durability, and deduplication are applied."},"x-ingress-durability":{"schema":{"type":"string","enum":["not_required","persisted","failed","skipped_disabled"]},"description":"Durability state for persist-before-ack handling."},"x-processing-detail":{"schema":{"type":"string","enum":["processed_full","processed_partial","duplicate_skipped","rejected","degraded"]},"description":"Processing detail for accepted, degraded, duplicate, or rejected deliveries."},"x-ingress-blocked-reason":{"schema":{"type":"string","enum":["rate_limited","replay_detected","replay_protection_unavailable","payload_invalid_json","route_topic_mismatch","ambiguous_shop_domain","shop_domain_mismatch"]},"description":"Specific public blocked-reason header value when ingress exposes one, including ambiguous_shop_domain for accepted_degraded tenant-resolution ambiguity."},"x-ingress-enqueue-status":{"schema":{"type":"string","enum":["enqueued","duplicate_rejected"]},"description":"Enqueue state when ingress needs to distinguish a deduplicated duplicate from a fresh enqueue."},"x-ingress-incident":{"schema":{"type":"string"},"description":"Optional incident identifier emitted when ingress surfaces an incident-aware degraded or recovery path."},"Retry-After":{"schema":{"type":"string"},"description":"Seconds Shopify should wait before retrying the webhook delivery."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ShopifyWebhookIngressResponseBody"}}}}}}},"/api/webhooks/monitoring":{"get":{"tags":["Webhooks"],"summary":"Webhook monitoring dashboard","description":"Returns the authenticated webhook monitoring dashboard payload with performance metrics, health, dead-letter-queue statistics, and active alerts.","security":[{"BearerAuth":[]}],"parameters":[{"name":"timeframe","in":"query","required":false,"schema":{"type":"string","enum":["1h","24h","7d"],"default":"24h"},"description":"Time window for monitoring metrics and dashboard health."},{"name":"dlqScope","in":"query","required":false,"schema":{"type":"string","enum":["merchant","global"],"default":"merchant"},"description":"Dead-letter queue statistics scope. Global scope requires an active support_rep role."}],"responses":{"200":{"description":"Webhook monitoring dashboard payload.","content":{"application/json":{"schema":{"type":"object","properties":{"metrics":{"type":"object","properties":{"totalWebhooks":{"type":"integer"},"successRate":{"type":"number"},"averageProcessingTime":{"type":"number"},"queueDepth":{"type":"integer"},"throughputPerMinute":{"type":"number"},"errorRate":{"type":"number"},"circuitBreakersOpen":{"type":"integer"},"processingLatency":{"type":"object","properties":{"p50":{"type":"number"},"p90":{"type":"number"},"p99":{"type":"number"}},"required":["p50","p90","p99"]},"topicBreakdown":{"type":"array","items":{"type":"object","properties":{"topic":{"type":"string"},"count":{"type":"integer"},"successRate":{"type":"number"},"avgProcessingTime":{"type":"number"},"errorRate":{"type":"number"}},"required":["topic","count","successRate","avgProcessingTime","errorRate"]}}},"required":["totalWebhooks","successRate","averageProcessingTime","queueDepth","throughputPerMinute","errorRate","circuitBreakersOpen","processingLatency","topicBreakdown"]},"health":{"type":"object","properties":{"status":{"type":"string","enum":["healthy","degraded","critical"]},"issues":{"type":"array","items":{"type":"string"}},"recommendations":{"type":"array","items":{"type":"string"}},"lastChecked":{"type":"string","format":"date-time"}},"required":["status","issues","recommendations","lastChecked"]},"dlqStats":{"type":"object","properties":{"totalDeadLetters":{"type":"integer"},"pendingReview":{"type":"integer"},"underInvestigation":{"type":"integer"},"retryScheduled":{"type":"integer"},"recovered":{"type":"integer"},"permanentFailure":{"type":"integer"},"failureReasonsBreakdown":{"type":"array","items":{"type":"object","properties":{"reason":{"type":"string"},"count":{"type":"integer"},"severity":{"type":"string"}},"required":["reason","count","severity"]}},"topicBreakdown":{"type":"array","items":{"type":"object","properties":{"topic":{"type":"string"},"count":{"type":"integer"},"recoveryRate":{"type":"number"}},"required":["topic","count","recoveryRate"]}},"shopBreakdown":{"type":"array","items":{"type":"object","properties":{"shopDomain":{"type":"string"},"count":{"type":"integer"},"lastFailure":{"type":"string","format":"date-time"}},"required":["shopDomain","count","lastFailure"]}},"recentTrends":{"type":"array","items":{"type":"object","properties":{"date":{"type":"string"},"count":{"type":"integer"},"recovered":{"type":"integer"}},"required":["date","count","recovered"]}}},"required":["totalDeadLetters","pendingReview","underInvestigation","retryScheduled","recovered","permanentFailure","failureReasonsBreakdown","topicBreakdown","shopBreakdown","recentTrends"]},"activeAlerts":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"ruleId":{"type":"string"},"ruleName":{"type":"string"},"severity":{"type":"string","enum":["low","medium","high","critical"]},"status":{"type":"string","enum":["active","acknowledged","resolved"]},"message":{"type":"string"},"details":{"type":"object","additionalProperties":{"nullable":true}},"triggeredAt":{"type":"string","format":"date-time"},"acknowledgedAt":{"type":"string","format":"date-time"},"resolvedAt":{"type":"string","format":"date-time"},"acknowledgedBy":{"type":"string"},"merchantId":{"type":"string"}},"required":["id","ruleId","ruleName","severity","status","message","details","triggeredAt"]}},"timeframe":{"type":"string","enum":["1h","24h","7d"]},"dlqScope":{"type":"string","enum":["merchant","global"]},"scopes":{"type":"object","properties":{"monitoring":{"type":"string","enum":["merchant"]},"dlq":{"type":"string","enum":["merchant","global"]}},"required":["monitoring","dlq"]},"merchantId":{"type":"string","nullable":true},"timestamp":{"type":"string","format":"date-time"}},"required":["metrics","health","dlqStats","activeAlerts","timeframe","dlqScope","scopes","merchantId","timestamp"]}}}},"400":{"description":"Invalid timeframe or DLQ scope query parameter","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string","enum":["VALIDATION_FAILED"]}},"required":["error","code"]}}}},"401":{"description":"Authentication required to read webhook monitoring data","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string","enum":["AUTHENTICATION_FAILED"]}},"required":["error","code"]}}}},"403":{"description":"Authenticated caller lacks the required monitoring or DLQ scope access","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string","enum":["AUTHORIZATION_FAILED"]}},"required":["error","code"]}}}},"429":{"description":"Webhook monitoring rate limit exceeded","headers":{"Retry-After":{"schema":{"type":"string"},"description":"Seconds until the client should retry the request."}},"content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string","enum":["RATE_LIMIT_EXCEEDED"]}},"required":["error","code"]}}}},"500":{"description":"Unexpected failure while fetching webhook monitoring data","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"503":{"description":"Webhook monitoring rate limiting is temporarily unavailable","headers":{"Retry-After":{"schema":{"type":"string"},"description":"Seconds until the client should retry the request."}},"content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string","enum":["INTERNAL_ERROR"]}},"required":["error","code"]}}}}}}},"/api/webhooks/monitoring/metrics":{"get":{"tags":["Webhooks"],"summary":"Webhook metrics","description":"Returns detailed webhook processing metrics, merchant-scoped retry statistics, process-memory circuit breaker state, and optional in-memory time-series data.","security":[{"BearerAuth":[]}],"parameters":[{"name":"timeframe","in":"query","required":false,"schema":{"type":"string","enum":["1h","24h","7d"],"default":"24h"},"description":"Time window for performance and retry statistics"},{"name":"metric","in":"query","required":false,"schema":{"type":"string","enum":["queueDepth","throughputPerMinute","errorRate","latencyP50","latencyP90","latencyP99"],"default":"errorRate"},"description":"Metric to project into timeSeriesData"},{"name":"includeTimeSeries","in":"query","required":false,"schema":{"type":"boolean","default":true},"description":"Set to false to skip timeSeriesData collection"}],"responses":{"200":{"description":"Webhook metrics payload","content":{"application/json":{"schema":{"type":"object","properties":{"performanceMetrics":{"type":"object","properties":{"totalWebhooks":{"type":"integer"},"successRate":{"type":"number"},"averageProcessingTime":{"type":"number"},"queueDepth":{"type":"integer"},"throughputPerMinute":{"type":"number"},"errorRate":{"type":"number"},"circuitBreakersOpen":{"type":"integer"},"processingLatency":{"type":"object","properties":{"p50":{"type":"number"},"p90":{"type":"number"},"p99":{"type":"number"}},"required":["p50","p90","p99"]},"topicBreakdown":{"type":"array","items":{"type":"object","properties":{"topic":{"type":"string"},"count":{"type":"integer"},"successRate":{"type":"number"},"avgProcessingTime":{"type":"number"},"errorRate":{"type":"number"}},"required":["topic","count","successRate","avgProcessingTime","errorRate"]}}},"required":["totalWebhooks","successRate","averageProcessingTime","queueDepth","throughputPerMinute","errorRate","circuitBreakersOpen","processingLatency","topicBreakdown"]},"retryStats":{"type":"object","properties":{"totalRetries":{"type":"integer"},"successRate":{"type":"number"},"averageRetryCount":{"type":"number"},"endpointsByFailureRate":{"type":"array","items":{"type":"object","properties":{"endpoint":{"type":"string"},"failureRate":{"type":"number"},"totalAttempts":{"type":"integer"}},"required":["endpoint","failureRate","totalAttempts"]}}},"required":["totalRetries","successRate","averageRetryCount","endpointsByFailureRate"]},"circuitBreakerState":{"type":"object","properties":{"openCircuitBreakers":{"type":"integer"},"endpoints":{"type":"array","items":{"type":"object","properties":{"endpoint":{"type":"string"},"isOpen":{"type":"boolean"}},"required":["endpoint","isOpen"]}}},"required":["openCircuitBreakers","endpoints"]},"timeSeriesData":{"type":"array","items":{"type":"object","properties":{"timestamp":{"type":"string","format":"date-time"},"value":{"type":"number"}},"required":["timestamp","value"]}},"timeframe":{"type":"string","enum":["1h","24h","7d"]},"metric":{"type":"string","enum":["queueDepth","throughputPerMinute","errorRate","latencyP50","latencyP90","latencyP99"]},"includeTimeSeries":{"type":"boolean"},"scopes":{"type":"object","properties":{"monitoring":{"type":"string","enum":["merchant"]},"retryStats":{"type":"string","enum":["merchant"]},"circuitBreakerState":{"type":"string","enum":["process-memory"]},"timeSeries":{"type":"string","enum":["process-memory"]}},"required":["monitoring","retryStats","circuitBreakerState","timeSeries"]},"warnings":{"type":"array","items":{"type":"string"}},"timestamp":{"type":"string","format":"date-time"}},"required":["performanceMetrics","retryStats","circuitBreakerState","timeSeriesData","timeframe","metric","includeTimeSeries","scopes","warnings","timestamp"]}}}},"400":{"description":"Invalid timeframe or metric query parameter","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string","enum":["VALIDATION_FAILED"]}},"required":["error","code"]}}}},"401":{"description":"Authentication required to read webhook metrics","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string","enum":["AUTHENTICATION_FAILED"]}},"required":["error","code"]}}}},"403":{"description":"Authenticated caller lacks the required monitoring access","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string","enum":["AUTHORIZATION_FAILED"]}},"required":["error","code"]}}}},"429":{"description":"Webhook monitoring rate limit exceeded","headers":{"Retry-After":{"schema":{"type":"string"},"description":"Seconds until the client should retry the request."}},"content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string","enum":["RATE_LIMIT_EXCEEDED"]}},"required":["error","code"]}}}},"500":{"description":"Unexpected failure while fetching webhook metrics","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"503":{"description":"Webhook monitoring rate limiting is temporarily unavailable","headers":{"Retry-After":{"schema":{"type":"string"},"description":"Seconds until the client should retry the request."}},"content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string","enum":["INTERNAL_ERROR"]}},"required":["error","code"]}}}}}}},"/api/webhooks/monitoring/health":{"get":{"tags":["Webhooks"],"summary":"Webhook health status","description":"Returns the lightweight webhook dashboard health payload as `{ health, timestamp }` for the authenticated merchant.","security":[{"BearerAuth":[]}],"responses":{"200":{"description":"Webhook system health as the runtime `{ health, timestamp }` payload.","content":{"application/json":{"schema":{"type":"object","properties":{"health":{"type":"object","properties":{"status":{"type":"string","enum":["healthy","degraded","critical"]},"issues":{"type":"array","items":{"type":"string"}},"recommendations":{"type":"array","items":{"type":"string"}},"lastChecked":{"type":"string","format":"date-time"}},"required":["status","issues","recommendations","lastChecked"]},"timestamp":{"type":"string","format":"date-time"}},"required":["health","timestamp"]}}}},"401":{"description":"Unauthorized - Missing or invalid authentication","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden - CSRF violation or insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Webhook monitoring health rate limit exceeded","headers":{"Retry-After":{"schema":{"type":"string"},"description":"Seconds until the client should retry the request."},"X-RateLimit-Limit":{"schema":{"type":"string"},"description":"Configured request limit for the current rate-limit window."},"X-RateLimit-Remaining":{"schema":{"type":"string"},"description":"Remaining requests in the current rate-limit window."},"X-RateLimit-Reset":{"schema":{"type":"string"},"description":"ISO timestamp indicating when the current window resets."}},"content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"retryAfter":{"type":"integer"}},"required":["error","retryAfter"]}}}},"500":{"description":"Unexpected failure while fetching webhook health status","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"503":{"description":"Webhook monitoring health rate limiting is temporarily unavailable","headers":{"Retry-After":{"schema":{"type":"string"},"description":"Seconds until the client should retry the request."}},"content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"retryAfter":{"type":"integer"}},"required":["error","retryAfter"]}}}}}}},"/api/webhooks/dead-letter-queue":{"get":{"tags":["Webhooks"],"summary":"List dead letter queue items","description":"Non-v1 webhook control-plane route. Returns support-safe raw JSON dead-letter queue DTOs for the authenticated operator, filtered by status, topic, severity, and limit. Items do not include the raw DLQ payload by default; use payloadSummary/payloadMode/retentionMode and related metadata for triage.","security":[{"BearerAuth":[]}],"parameters":[{"name":"status","in":"query","required":false,"schema":{"type":"string","enum":["pending_review","under_investigation","resolved","discarded"]}},{"name":"topic","in":"query","required":false,"schema":{"type":"string","maxLength":255}},{"name":"severity","in":"query","required":false,"schema":{"type":"string","enum":["low","medium","high","critical"]}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":50,"minimum":1,"maximum":100}}],"responses":{"200":{"description":"Current dead-letter queue items","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeadLetterQueueListResponse"}}}},"401":{"description":"Unauthorized - Missing or invalid authentication","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden - CSRF violation or insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too Many Requests - Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Failed to fetch dead letter queue items","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"503":{"description":"Service Unavailable - Rate limiting service is temporarily unavailable","headers":{"Retry-After":{"schema":{"type":"string"},"description":"Seconds until the client should retry the request."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"post":{"tags":["Webhooks"],"summary":"Run dead letter queue action","description":"Non-v1 webhook control-plane route. Performs an action-based dead-letter queue operation. Use `retry` to schedule a retry or `mark_permanent_failure` to close the item out.","security":[{"BearerAuth":[]}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeadLetterQueueActionRequest"}}}},"responses":{"200":{"description":"Dead-letter queue action accepted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeadLetterQueueActionSuccess"}}}},"400":{"description":"Invalid action request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeadLetterQueueActionError"}}}},"401":{"description":"Unauthorized - Missing or invalid authentication","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden - CSRF violation or insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Dead-letter item not found or not visible to the current operator (anti-enumeration)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too Many Requests - Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Failed to process the dead-letter queue action","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeadLetterQueueActionError"}}}},"503":{"description":"Service Unavailable - Rate limiting service is temporarily unavailable","headers":{"Retry-After":{"schema":{"type":"string"},"description":"Seconds until the client should retry the request."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/webhooks/dead-letter-queue/{id}/analysis":{"get":{"tags":["Webhooks"],"summary":"Get dead letter queue recovery analysis","description":"Non-v1 webhook control-plane route. Returns raw JSON recovery analysis and recommendations for a specific dead-letter item.","security":[{"BearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","maxLength":128},"description":"Dead letter item identifier."}],"responses":{"200":{"description":"Recovery analysis for the requested dead-letter item","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeadLetterQueueAnalysisResponse"}}}},"400":{"description":"Bad Request - Invalid input parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Missing or invalid authentication","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden - CSRF violation or insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Dead-letter item not found or not visible to the current operator (anti-enumeration)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too Many Requests - Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"503":{"description":"Service Unavailable - Rate limiting service is temporarily unavailable","headers":{"Retry-After":{"schema":{"type":"string"},"description":"Seconds until the client should retry the request."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/webhooks/processor":{"get":{"tags":["Webhooks"],"summary":"Get webhook processor stats","description":"Support-only operational route that returns current webhook processor stats plus batch orchestrator status when available.","security":[{"BearerAuth":[]}],"responses":{"200":{"description":"Current webhook processor stats","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookProcessorStats"}}}},"401":{"description":"Unauthorized - Missing or invalid authentication","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden - CSRF violation or insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too Many Requests - Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Failed to fetch webhook processor stats","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookProcessorStatsError"}}}},"503":{"description":"Service Unavailable - Rate limiting service is temporarily unavailable","headers":{"Retry-After":{"schema":{"type":"string"},"description":"Seconds until the client should retry the request."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"post":{"tags":["Webhooks"],"summary":"Inspect webhook processor stats via POST","description":"Support-only operational route. `action=stats` returns current webhook processor stats. `action=start` and `action=stop` are recognized for audit logging but intentionally return 403.","security":[{"BearerAuth":[]}],"parameters":[{"name":"action","in":"query","required":true,"schema":{"type":"string","enum":["stats"]},"description":"Supported processor action to perform. `stats` is the only documented POST action; `start` and `stop` are intentionally forbidden."}],"responses":{"200":{"description":"Current webhook processor stats","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookProcessorStats"}}}},"400":{"description":"Invalid processor action","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"401":{"description":"Unauthorized - Missing or invalid authentication","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden - CSRF violation or insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too Many Requests - Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Failed to fetch webhook processor stats","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookProcessorStatsError"}}}},"503":{"description":"Service Unavailable - Rate limiting service is temporarily unavailable","headers":{"Retry-After":{"schema":{"type":"string"},"description":"Seconds until the client should retry the request."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/inventory/reorder-suggestions":{"get":{"tags":["Inventory","Reorder Management"],"summary":"Get reorder suggestions","description":"\nReturns low-stock inventory rows for the authenticated merchant.\n\n## Surface behavior\n\n- **surface=inventory** returns the canonical low-stock row contract.\n- **surface=buying** returns the same base row plus supplier, ABC, and workbench metadata.\n\n## Buying pinned refresh behavior\n\nThe buying workbench can repeat **include_row_id** query params to keep selected rows refreshable while the rest of the grid updates.\n\n- Pinned rows may still be returned even when they no longer match the active **location_id** filter.\n- Those rows are marked with:\n  - **inclusion_reason = pinned_refresh**\n  - **matches_location_filter = false**\n- Rows returned by the live low-stock query remain **inclusion_reason = live_low_stock**.\n\n## Example buying response\n\n```json\n{\n  \"success\": true,\n  \"data\": {\n    \"suggestions\": [\n      {\n        \"id\": \"123e4567-e89b-12d3-a456-426614174000\",\n        \"sku_id\": \"123e4567-e89b-12d3-a456-426614174001\",\n        \"sku_code\": \"WIDGET-LRG\",\n        \"product_name\": \"Premium Widget - Large\",\n        \"location_id\": \"123e4567-e89b-12d3-a456-426614174002\",\n        \"location_name\": \"Main Warehouse\",\n        \"on_hand_quantity\": 20,\n        \"reserved_quantity\": 5,\n        \"available_quantity\": 15,\n        \"reorder_point\": 25,\n        \"reorder_quantity\": 40,\n        \"row_id\": \"123e4567-e89b-12d3-a456-426614174000\",\n        \"source_inventory_row_id\": \"123e4567-e89b-12d3-a456-426614174000\",\n        \"inclusion_reason\": \"pinned_refresh\",\n        \"matches_location_filter\": false,\n        \"supplier_id\": \"123e4567-e89b-12d3-a456-426614174010\",\n        \"currency\": \"USD\",\n        \"supplier_sku_code\": \"SUP-001\",\n        \"unit_cost\": 12.5,\n        \"minimum_order_quantity\": 24,\n        \"lead_time_days\": 14,\n        \"using_defaults\": {\n          \"lead_time\": false,\n          \"safety_stock\": true\n        },\n        \"abc_category\": \"A\",\n        \"abc_classification_day\": \"2026-03-20\",\n        \"abc_is_stale\": true,\n        \"abc_source_contract\": \"fn30_row_enrichment_v1\",\n        \"allowed_next_actions\": [\"inspect\", \"filter\"]\n      }\n    ],\n    \"metadata\": {\n      \"limit\": 50,\n      \"location_id\": \"123e4567-e89b-12d3-a456-426614174002\",\n      \"surface\": \"buying\"\n    }\n  }\n}\n```\n  ","security":[{"BearerAuth":[]}],"parameters":[{"schema":{"type":"integer","minimum":1,"maximum":100,"example":50,"description":"Maximum number of low-stock rows returned before buying pinned rows are merged in."},"required":false,"description":"Maximum number of low-stock rows returned before buying pinned rows are merged in.","name":"limit","in":"query"},{"schema":{"type":"string","format":"uuid","example":"123e4567-e89b-12d3-a456-426614174002","description":"Optional location scope applied before the live low-stock result is limited."},"required":false,"description":"Optional location scope applied before the live low-stock result is limited.","name":"location_id","in":"query"},{"schema":{"type":"string","enum":["inventory","buying"],"example":"buying","description":"Response surface. buying adds workbench enrichment fields to each row."},"required":false,"description":"Response surface. buying adds workbench enrichment fields to each row.","name":"surface","in":"query"},{"schema":{"type":"array","items":{"type":"string","format":"uuid"},"example":["123e4567-e89b-12d3-a456-426614174000","123e4567-e89b-12d3-a456-426614174099"],"description":"Buying workbench only. Repeat the include_row_id query parameter to pin selected rows into refresh responses, including rows that no longer match location_id."},"required":false,"description":"Buying workbench only. Repeat the include_row_id query parameter to pin selected rows into refresh responses, including rows that no longer match location_id.","name":"include_row_id","in":"query"}],"responses":{"200":{"description":"Successful reorder suggestions response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReorderSuggestionsResponse"}}}},"400":{"description":"Bad Request - Invalid input parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Missing or invalid authentication","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden - CSRF violation or insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/inventory/bulk-approve":{"post":{"tags":["Inventory","Approvals"],"summary":"Bulk approve reorder suggestions","description":"\nApproves multiple reorder suggestions in a single transaction.\n\n## Behavior\n\n- Creates approval records in the database\n- Can be undone via `POST /api/v1/inventory/undo-approval`\n- Supports partial success: failed approval rows are returned alongside created approvals\n- Returns `207` when at least one approval fails\n\n## Request Limits\n\n- Minimum: 1 approval per request\n- Maximum: 100 approvals per request\n\n## Example Request\n\n```json\n{\n  \"approvals\": [\n    {\n      \"sku_id\": \"123e4567-e89b-12d3-a456-426614174000\",\n      \"approved_quantity\": 50,\n      \"original_quantity\": 40\n    },\n    {\n      \"sku_id\": \"234e5678-e89b-12d3-a456-426614174001\",\n      \"approved_quantity\": 25,\n      \"original_quantity\": 25\n    }\n  ]\n}\n```\n\n## Example Response\n\n```json\n{\n  \"success\": true,\n  \"approvals\": [\n    {\n      \"approval_id\": \"456e7890-e89b-12d3-a456-426614174001\",\n      \"sku_id\": \"123e4567-e89b-12d3-a456-426614174000\",\n      \"approved_quantity\": 50,\n      \"approved_at\": \"2025-01-03T11:00:00.000Z\"\n    }\n  ],\n  \"failed\": [],\n  \"total\": 1,\n  \"success_count\": 1,\n  \"failure_count\": 0,\n  \"batch_id\": \"567e8901-e89b-12d3-a456-426614174002\"\n}\n```\n  ","security":[{"BearerAuth":[],"CSRFToken":[]}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkApproveRequest"}}}},"responses":{"200":{"description":"Approvals processed successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkApproveResponse"}}}},"207":{"description":"Approvals processed with partial success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkApproveResponse"}}}},"400":{"description":"Bad Request - Invalid input parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Missing or invalid authentication","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden - CSRF violation or insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/inventory/undo-approval":{"post":{"tags":["Inventory","Approvals"],"summary":"Undo a previous approval","description":"\nReverts a previously approved reorder suggestion.\n\n## Behavior\n\n- Supports exactly one of `approval_id` or `batch_id`\n- Single undo returns the approval id and undo timestamp\n- Batch undo returns the batch id, count, and affected approval ids\n\n## Example Request\n\n```json\n{\n  \"approval_id\": \"456e7890-e89b-12d3-a456-426614174001\"\n}\n```\n\n## Example Response\n\n```json\n{\n  \"success\": true,\n  \"data\": {\n    \"success\": true,\n    \"undo_type\": \"single\",\n    \"approval_id\": \"456e7890-e89b-12d3-a456-426614174001\",\n    \"undone\": true,\n    \"undone_at\": \"2025-01-03T11:00:00.000Z\"\n  }\n}\n```\n  ","security":[{"BearerAuth":[],"CSRFToken":[]}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UndoApprovalRequest"}}}},"responses":{"200":{"description":"Approval undone successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UndoApprovalResponse"}}}},"400":{"description":"Bad Request - Invalid input parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Missing or invalid authentication","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden - CSRF violation or insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource does not exist","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/inventory/positions":{"get":{"tags":["Inventory"],"summary":"List inventory positions","description":"Returns inventory positions joined with SKU and location summaries. Supports optional multi-location, SKU, and low-stock filtering plus page/limit pagination.","security":[{"BearerAuth":[]},{"SessionCookieAuth":[]}],"parameters":[{"schema":{"type":"string","example":"123e4567-e89b-12d3-a456-426614174002,123e4567-e89b-12d3-a456-426614174003","description":"Optional comma-separated location ID filter. Values are trimmed, deduped, sorted, and capped at 50 normalized IDs. Empty CSV values, repeated locationIds query params, and mixing with locationId are rejected."},"required":false,"description":"Optional comma-separated location ID filter. Values are trimmed, deduped, sorted, and capped at 50 normalized IDs. Empty CSV values, repeated locationIds query params, and mixing with locationId are rejected.","name":"locationIds","in":"query"},{"schema":{"type":"string","format":"uuid","example":"123e4567-e89b-12d3-a456-426614174002","description":"Compatibility-only single location filter. Cannot be mixed with locationIds."},"required":false,"description":"Compatibility-only single location filter. Cannot be mixed with locationIds.","name":"locationId","in":"query"},{"schema":{"type":"string","format":"uuid","example":"123e4567-e89b-12d3-a456-426614174001","description":"Optional SKU filter."},"required":false,"description":"Optional SKU filter.","name":"skuId","in":"query"},{"schema":{"type":"boolean","nullable":true,"example":true,"description":"When true, only low-stock positions are returned after transformation."},"required":false,"description":"When true, only low-stock positions are returned after transformation.","name":"lowStock","in":"query"},{"schema":{"type":"integer","minimum":1,"example":1,"description":"1-based page number."},"required":false,"description":"1-based page number.","name":"page","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":100,"example":50,"description":"Maximum positions per page."},"required":false,"description":"Maximum positions per page.","name":"limit","in":"query"}],"responses":{"200":{"description":"Inventory positions response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InventoryPositionsResponse"}}}},"400":{"description":"Bad Request - Invalid input parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Missing or invalid authentication","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden - CSRF violation or insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too Many Requests - Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"503":{"description":"Service Unavailable - Rate limiting service is temporarily unavailable","headers":{"Retry-After":{"schema":{"type":"string"},"description":"Seconds until the client should retry the request."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/inventory/stats":{"get":{"tags":["Inventory"],"summary":"Get inventory summary statistics","description":"Returns aggregated inventory counts and utilization metrics for the authenticated merchant.","security":[{"BearerAuth":[]},{"SessionCookieAuth":[]}],"responses":{"200":{"description":"Inventory statistics response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InventoryStatsResponse"}}}},"400":{"description":"Bad Request - Invalid input parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Missing or invalid authentication","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden - CSRF violation or insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too Many Requests - Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"503":{"description":"Service Unavailable - Rate limiting service is temporarily unavailable","headers":{"Retry-After":{"schema":{"type":"string"},"description":"Seconds until the client should retry the request."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/inventory/locations":{"get":{"tags":["Inventory"],"summary":"List inventory locations","description":"Returns merchant locations as either a flat list or grouped-by-type response based on the optional groupBy query parameter.","security":[{"BearerAuth":[]},{"SessionCookieAuth":[]}],"parameters":[{"schema":{"type":"string","example":"warehouse","description":"Optional case-insensitive location name search."},"required":false,"description":"Optional case-insensitive location name search.","name":"search","in":"query"},{"schema":{"type":"boolean","nullable":true,"example":true,"description":"When true, only active locations are returned."},"required":false,"description":"When true, only active locations are returned.","name":"activeOnly","in":"query"},{"schema":{"type":"string","enum":["type"],"example":"type","description":"When set to type, the response groups locations by location type."},"required":false,"description":"When set to type, the response groups locations by location type.","name":"groupBy","in":"query"}],"responses":{"200":{"description":"Inventory locations response","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/InventoryLocationsListResponse"},{"$ref":"#/components/schemas/InventoryLocationsGroupedResponse"}]}}}},"400":{"description":"Bad Request - Invalid input parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Missing or invalid authentication","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden - CSRF violation or insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too Many Requests - Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"503":{"description":"Service Unavailable - Rate limiting service is temporarily unavailable","headers":{"Retry-After":{"schema":{"type":"string"},"description":"Seconds until the client should retry the request."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/inventory/counts":{"get":{"tags":["Inventory"],"summary":"List inventory count sessions","description":"Lists stock-take and cycle-count sessions for the authenticated merchant. Cancelled sessions are hidden by default unless includeCancelled=true or an explicit status filter includes them. Feature disabled returns 403 BIZ_OPERATION_NOT_ALLOWED.","security":[{"BearerAuth":[]},{"SessionCookieAuth":[]}],"parameters":[{"schema":{"type":"string","example":"open,review,completed_with_warnings","description":"Optional comma-separated session statuses."},"required":false,"description":"Optional comma-separated session statuses.","name":"status","in":"query"},{"schema":{"$ref":"#/components/schemas/InventoryCountType"},"required":false,"name":"countType","in":"query"},{"schema":{"type":"string","example":"123e4567-e89b-12d3-a456-426614174002","description":"Optional comma-separated location IDs, capped at 50 normalized IDs."},"required":false,"description":"Optional comma-separated location IDs, capped at 50 normalized IDs.","name":"locationIds","in":"query"},{"schema":{"type":"boolean","nullable":true,"example":false},"required":false,"name":"includeCancelled","in":"query"},{"schema":{"type":"integer","minimum":1,"example":1},"required":false,"name":"page","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":100,"example":25},"required":false,"name":"limit","in":"query"}],"responses":{"200":{"description":"Inventory count sessions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InventoryCountSessionsResponse"}}}},"400":{"description":"Bad Request - Invalid input parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Missing or invalid authentication","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden. Either inventory counts are disabled for the workspace, the actor lacks the inventory writer role required by mutations, or support users are denied raw line access.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InventoryCountForbiddenResponse"}}}},"429":{"description":"Too Many Requests - Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"503":{"description":"Service Unavailable - Rate limiting service is temporarily unavailable","headers":{"Retry-After":{"schema":{"type":"string"},"description":"Seconds until the client should retry the request."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"post":{"tags":["Inventory"],"summary":"Create an inventory count session","description":"Creates and atomically seeds a stock-take or cycle-count session from server-owned candidate selection. Requires an inventory writer role. Seeds existing inventory positions only, rejects zero candidates and scopes above 500 candidates, and keeps merchant scope server-derived.","security":[{"BearerAuth":[]},{"SessionCookieAuth":[]}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateInventoryCountSessionRequest"}}}},"responses":{"200":{"description":"Inventory count session created with first page of lines","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InventoryCountCreateSessionResponse"}}}},"400":{"description":"Bad Request - Invalid input parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Missing or invalid authentication","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden. Either inventory counts are disabled for the workspace, the actor lacks the inventory writer role required by mutations, or support users are denied raw line access.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InventoryCountForbiddenResponse"}}}},"409":{"description":"Conflict: line-version mismatch, review blockers, stale/missing current positions, commit lease, expired lease, operation-key mismatch, replay guard, or invalid lifecycle status.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InventoryCountConflictResponse"}}}},"429":{"description":"Too Many Requests - Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"503":{"description":"Service Unavailable - Rate limiting service is temporarily unavailable","headers":{"Retry-After":{"schema":{"type":"string"},"description":"Seconds until the client should retry the request."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/inventory/counts/{id}":{"get":{"tags":["Inventory"],"summary":"Get inventory count session detail","description":"Returns session detail and lines for merchant users. Support users receive redacted session summary metadata without raw line access. Blind-count sessions redact snapshot and variance fields while open.","security":[{"BearerAuth":[]},{"SessionCookieAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Inventory count session detail","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InventoryCountSessionDetailResponse"}}}},"400":{"description":"Bad Request - Invalid input parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Missing or invalid authentication","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden. Either inventory counts are disabled for the workspace, the actor lacks the inventory writer role required by mutations, or support users are denied raw line access.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InventoryCountForbiddenResponse"}}}},"404":{"description":"Not Found - Resource does not exist","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too Many Requests - Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"503":{"description":"Service Unavailable - Rate limiting service is temporarily unavailable","headers":{"Retry-After":{"schema":{"type":"string"},"description":"Seconds until the client should retry the request."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"patch":{"tags":["Inventory"],"summary":"Update inventory count session metadata","description":"Updates mutable session metadata such as name. Requires an inventory writer role and does not allow clients to mutate audit, lifecycle, commit, or event fields.","security":[{"BearerAuth":[]},{"SessionCookieAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateInventoryCountSessionMetadataRequest"}}}},"responses":{"200":{"description":"Updated session detail","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InventoryCountSessionDetailResponse"}}}},"400":{"description":"Bad Request - Invalid input parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Missing or invalid authentication","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden. Either inventory counts are disabled for the workspace, the actor lacks the inventory writer role required by mutations, or support users are denied raw line access.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InventoryCountForbiddenResponse"}}}},"404":{"description":"Not Found - Resource does not exist","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Conflict: line-version mismatch, review blockers, stale/missing current positions, commit lease, expired lease, operation-key mismatch, replay guard, or invalid lifecycle status.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InventoryCountConflictResponse"}}}},"429":{"description":"Too Many Requests - Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"503":{"description":"Service Unavailable - Rate limiting service is temporarily unavailable","headers":{"Retry-After":{"schema":{"type":"string"},"description":"Seconds until the client should retry the request."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/inventory/counts/{id}/lines":{"get":{"tags":["Inventory"],"summary":"List inventory count lines","description":"Lists paginated lines for a count session. Supports status, location, ABC category, variance-only, and search filters. Support users are denied raw line access. Blind-count sessions redact expected/snapshot/variance fields while open.","security":[{"BearerAuth":[]},{"SessionCookieAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"id","in":"path"},{"schema":{"type":"string","example":"pending,counted"},"required":false,"name":"status","in":"query"},{"schema":{"type":"string","description":"Optional comma-separated location IDs."},"required":false,"description":"Optional comma-separated location IDs.","name":"locationIds","in":"query"},{"schema":{"$ref":"#/components/schemas/InventoryCountAbcCategory"},"required":false,"name":"abcCategory","in":"query"},{"schema":{"type":"boolean","nullable":true,"example":true},"required":false,"name":"varianceOnly","in":"query"},{"schema":{"type":"string","minLength":1,"maxLength":100,"example":"WIDGET"},"required":false,"name":"search","in":"query"},{"schema":{"type":"integer","minimum":1,"example":1},"required":false,"name":"page","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":200,"example":50},"required":false,"name":"limit","in":"query"}],"responses":{"200":{"description":"Inventory count lines","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InventoryCountLinesResponse"}}}},"400":{"description":"Bad Request - Invalid input parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Missing or invalid authentication","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden. Either inventory counts are disabled for the workspace, the actor lacks the inventory writer role required by mutations, or support users are denied raw line access.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InventoryCountForbiddenResponse"}}}},"404":{"description":"Not Found - Resource does not exist","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too Many Requests - Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"503":{"description":"Service Unavailable - Rate limiting service is temporarily unavailable","headers":{"Retry-After":{"schema":{"type":"string"},"description":"Seconds until the client should retry the request."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/inventory/counts/{id}/scan-lookup":{"post":{"tags":["Inventory"],"summary":"Resolve a scanned barcode or UPC for an inventory count session","description":"Resolves a normalized barcode/UPC against tenant-scoped SKU barcode and UPC equality lookups, then maps the result to count-session-specific outcomes without updating count lines. Raw scanned values are accepted only in the POST body and are not path/query parameters. Blind-count sessions redact snapshot and variance fields while open.","security":[{"BearerAuth":[]},{"SessionCookieAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CountScanLookupRequest"}}}},"responses":{"200":{"description":"Scan lookup result: matched line, duplicate SKUs, multiple count lines, SKU not in session, or unknown code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CountScanLookupResponse"}}}},"400":{"description":"Bad Request - Invalid input parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Missing or invalid authentication","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden. Either inventory counts are disabled for the workspace, the actor lacks the inventory writer role required by mutations, or support users are denied raw line access.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InventoryCountForbiddenResponse"}}}},"404":{"description":"Not Found - Resource does not exist","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too Many Requests - Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"503":{"description":"Service Unavailable - Rate limiting service is temporarily unavailable","headers":{"Retry-After":{"schema":{"type":"string"},"description":"Seconds until the client should retry the request."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/inventory/counts/{id}/lines/{lineId}":{"patch":{"tags":["Inventory"],"summary":"Update an inventory count line","description":"Saves a counted, skipped, or reset/pending line state using optimistic expectedLineVersion. Requests may set only operator-owned count inputs; server-owned audit, lifecycle, commit, and event fields are rejected by the strict body schema.","security":[{"BearerAuth":[]},{"SessionCookieAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"id","in":"path"},{"schema":{"type":"string","format":"uuid"},"required":true,"name":"lineId","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateInventoryCountLineRequest"}}}},"responses":{"200":{"description":"Updated inventory count line","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InventoryCountLineResponse"}}}},"400":{"description":"Bad Request - Invalid input parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Missing or invalid authentication","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden. Either inventory counts are disabled for the workspace, the actor lacks the inventory writer role required by mutations, or support users are denied raw line access.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InventoryCountForbiddenResponse"}}}},"404":{"description":"Not Found - Resource does not exist","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Conflict: line-version mismatch, review blockers, stale/missing current positions, commit lease, expired lease, operation-key mismatch, replay guard, or invalid lifecycle status.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InventoryCountConflictResponse"}}}},"429":{"description":"Too Many Requests - Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"503":{"description":"Service Unavailable - Rate limiting service is temporarily unavailable","headers":{"Retry-After":{"schema":{"type":"string"},"description":"Seconds until the client should retry the request."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/inventory/counts/{id}/review":{"post":{"tags":["Inventory"],"summary":"Move an inventory count session into review","description":"Transitions an open count session to review after all lines are counted or skipped. Pending lines return 409 conflict details and must be completed before review.","security":[{"BearerAuth":[]},{"SessionCookieAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReviewInventoryCountSessionRequest"}}}},"responses":{"200":{"description":"Session entered review","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InventoryCountStatusTransitionResponse"}}}},"400":{"description":"Bad Request - Invalid input parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Missing or invalid authentication","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden. Either inventory counts are disabled for the workspace, the actor lacks the inventory writer role required by mutations, or support users are denied raw line access.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InventoryCountForbiddenResponse"}}}},"404":{"description":"Not Found - Resource does not exist","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Conflict: line-version mismatch, review blockers, stale/missing current positions, commit lease, expired lease, operation-key mismatch, replay guard, or invalid lifecycle status.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InventoryCountConflictResponse"}}}},"429":{"description":"Too Many Requests - Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"503":{"description":"Service Unavailable - Rate limiting service is temporarily unavailable","headers":{"Retry-After":{"schema":{"type":"string"},"description":"Seconds until the client should retry the request."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/inventory/counts/{id}/cancel":{"post":{"tags":["Inventory"],"summary":"Cancel an inventory count session","description":"Cancels an open or review count session with an optional reason. Terminal and committing sessions are immutable.","security":[{"BearerAuth":[]},{"SessionCookieAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CancelInventoryCountSessionRequest"}}}},"responses":{"200":{"description":"Session cancelled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InventoryCountStatusTransitionResponse"}}}},"400":{"description":"Bad Request - Invalid input parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Missing or invalid authentication","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden. Either inventory counts are disabled for the workspace, the actor lacks the inventory writer role required by mutations, or support users are denied raw line access.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InventoryCountForbiddenResponse"}}}},"404":{"description":"Not Found - Resource does not exist","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Conflict: line-version mismatch, review blockers, stale/missing current positions, commit lease, expired lease, operation-key mismatch, replay guard, or invalid lifecycle status.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InventoryCountConflictResponse"}}}},"429":{"description":"Too Many Requests - Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"503":{"description":"Service Unavailable - Rate limiting service is temporarily unavailable","headers":{"Retry-After":{"schema":{"type":"string"},"description":"Seconds until the client should retry the request."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/inventory/counts/{id}/commit":{"post":{"tags":["Inventory"],"summary":"Commit an inventory count session","description":"Commits reviewed count lines with an idempotent operationKey. The commit locks session, lines, and current positions; aborts on stale or missing positions; computes deltas against current on-hand; replays completed operation keys; and returns completed_with_warnings/event_outcome_unknown when downstream inventory change events need verification.","security":[{"BearerAuth":[]},{"SessionCookieAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommitInventoryCountSessionRequest"}}}},"responses":{"200":{"description":"Commit result, including replayed and completed-with-warnings shapes","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InventoryCountCommitResponse"}}}},"400":{"description":"Bad Request - Invalid input parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Missing or invalid authentication","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden. Either inventory counts are disabled for the workspace, the actor lacks the inventory writer role required by mutations, or support users are denied raw line access.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InventoryCountForbiddenResponse"}}}},"404":{"description":"Not Found - Resource does not exist","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Conflict: line-version mismatch, review blockers, stale/missing current positions, commit lease, expired lease, operation-key mismatch, replay guard, or invalid lifecycle status.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InventoryCountConflictResponse"}}}},"429":{"description":"Too Many Requests - Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"503":{"description":"Service Unavailable - Rate limiting service is temporarily unavailable","headers":{"Retry-After":{"schema":{"type":"string"},"description":"Seconds until the client should retry the request."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/inventory/storefront-sellability":{"get":{"tags":["Inventory","Storefront Sellability"],"summary":"Get the storefront sellability overview for the authenticated merchant","description":"\nReturns the merchant-scoped Lane A storefront sellability overview.\n\n## Capability boundary\n\n- The returned rollout lane is always **native_only**.\n- Automatic support is limited to **inventory_policy_only** with **disableThreshold=0** and **reenableThreshold=1**.\n- Support and fulfillment roles may see different capabilities in the returned access matrix.\n  ","security":[{"BearerAuth":[]}],"responses":{"200":{"description":"Successful storefront sellability overview response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StorefrontSellabilityOverviewResponse"}}}},"401":{"description":"Unauthorized - Missing or invalid authentication","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too Many Requests - Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/inventory/storefront-sellability/{mappingId}":{"patch":{"tags":["Inventory","Storefront Sellability"],"summary":"Update native-only storefront sellability policy configuration for one mapping","description":"\nUpdates the mapping-owned policy configuration for one Shopify product mapping.\n\n## Lane A restrictions\n\n- Only **merchant_admin** may call this route successfully.\n- This route documents configuration changes only; use the override endpoint for **manual_force_sellable**.\n- Thresholds are frozen to **disableThreshold=0** and **reenableThreshold=1**.\n  ","security":[{"BearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","example":"550e8400-e29b-41d4-a716-446655440000","description":"Shopify product mapping id owned by the authenticated merchant."},"required":true,"description":"Shopify product mapping id owned by the authenticated merchant.","name":"mappingId","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateStorefrontSellabilityPolicyRequest"}}}},"responses":{"200":{"description":"Policy updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StorefrontSellabilityPolicyMutationResponse"}}}},"400":{"description":"Bad Request - Invalid input parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Missing or invalid authentication","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden - CSRF violation or insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource does not exist","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Conflict - Lane A write conflict, unresolved mapping, sync in progress, or active override disable constraint blocked the request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too Many Requests - Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/inventory/storefront-sellability/{mappingId}/override":{"post":{"tags":["Inventory","Storefront Sellability"],"summary":"Set the oversell override for one mapping","description":"\nSets the only supported manual override in Lane A.\n\n## Behavior\n\n- Only **merchant_admin** may call this route successfully.\n- **manual_force_sellable** maps to Shopify **CONTINUE** and can allow checkout beyond currently available stock.\n- The response returns the refreshed mapping plus the latest sync result.\n  ","security":[{"BearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","example":"550e8400-e29b-41d4-a716-446655440000"},"required":true,"name":"mappingId","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetStorefrontSellabilityOverrideRequest"}}}},"responses":{"200":{"description":"Override set successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StorefrontSellabilityPolicyMutationResponse"}}}},"400":{"description":"Bad Request - Invalid input parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Missing or invalid authentication","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden - CSRF violation or insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource does not exist","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Conflict - mapping unresolved, sync lease active, or policy state changed during write while processing override mutations.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too Many Requests - Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"delete":{"tags":["Inventory","Storefront Sellability"],"summary":"Clear the oversell override for one mapping","description":"\nClears **manual_force_sellable** and returns the mapping to automatic native mode.\n\n## Behavior\n\n- Only **merchant_admin** may call this route successfully.\n- Clearing the override does not enable forced blocking or storefront_gate behavior.\n  ","security":[{"BearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","example":"550e8400-e29b-41d4-a716-446655440000"},"required":true,"name":"mappingId","in":"path"}],"responses":{"200":{"description":"Override cleared successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StorefrontSellabilityPolicyMutationResponse"}}}},"400":{"description":"Bad Request - Invalid input parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Missing or invalid authentication","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden - CSRF violation or insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource does not exist","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Conflict - mapping unresolved, sync lease active, or policy state changed during write while processing override mutations.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too Many Requests - Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/inventory/storefront-sellability/{mappingId}/reconcile":{"post":{"tags":["Inventory","Storefront Sellability"],"summary":"Trigger on-demand native-state reconciliation for one mapping","description":"\nTriggers an on-demand reconcile of the mapping’s native Shopify state.\n\n## Behavior\n\n- Only **merchant_admin** may call this route successfully.\n- The route operates on one mapping-owned policy at a time.\n- This route does not widen the capability boundary beyond the current native-only contract.\n  ","security":[{"BearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","example":"550e8400-e29b-41d4-a716-446655440000"},"required":true,"name":"mappingId","in":"path"}],"responses":{"200":{"description":"Reconcile completed successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StorefrontSellabilityPolicyMutationResponse"}}}},"400":{"description":"Bad Request - Invalid input parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Missing or invalid authentication","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden - CSRF violation or insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource does not exist","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Conflict - mapping unresolved or sync already in progress for this mapping during reconcile.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too Many Requests - Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/inventory/storefront-sellability/{mappingId}/history":{"get":{"tags":["Inventory","Storefront Sellability"],"summary":"Get operator-facing transition history for one mapping","description":"\nReturns durable operator-facing history rows for overrides, configuration changes, and reconcile actions.\n\n## Access\n\n- **merchant_admin** and **support_rep** may view history.\n- **fulfillment_staff** receives a permission error.\n  ","security":[{"BearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","example":"550e8400-e29b-41d4-a716-446655440000"},"required":true,"name":"mappingId","in":"path"}],"responses":{"200":{"description":"Successful history response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StorefrontSellabilityTransitionHistoryResponse"}}}},"400":{"description":"Bad Request - Invalid input parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Missing or invalid authentication","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden - CSRF violation or insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource does not exist","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Conflict - mapping is unresolved, so transition history cannot be returned until the SKU mapping is restored.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too Many Requests - Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/inventory/storefront-sellability/unmapped":{"get":{"tags":["Inventory","Storefront Sellability"],"summary":"Get durable unmapped storefront-sellability diagnostics for the authenticated merchant","description":"\nReturns durable unmapped webhook-input diagnostics when sellability evaluation could not reach a mapping-owned policy target.\n\n## Access\n\n- **merchant_admin** and **support_rep** may view diagnostics.\n- Use the sibling PATCH route to acknowledge or resolve an operator-reviewed diagnostic.\n  ","security":[{"BearerAuth":[]}],"responses":{"200":{"description":"Successful unmapped diagnostics response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StorefrontSellabilityUnmappedInputsResponse"}}}},"401":{"description":"Unauthorized - Missing or invalid authentication","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden - CSRF violation or insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too Many Requests - Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"patch":{"tags":["Inventory","Storefront Sellability"],"summary":"Acknowledge or resolve an unmapped storefront-sellability diagnostic","description":"\nUpdates the operator lifecycle status for a single durable unmapped diagnostic row.\n\n## Access\n\n- **merchant_admin** and **support_rep** may acknowledge or resolve diagnostics.\n- **fulfillment_staff** receives a permission error.\n- Resolved diagnostics cannot transition back to acknowledged.\n  ","security":[{"BearerAuth":[]}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateStorefrontSellabilityUnmappedInputStatusRequest"}}}},"responses":{"200":{"description":"Successful unmapped diagnostic lifecycle mutation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StorefrontSellabilityUnmappedInputMutationResponse"}}}},"400":{"description":"Bad Request - Invalid input parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Missing or invalid authentication","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden - CSRF violation or insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource does not exist","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Conflict - the unmapped diagnostic changed or the requested lifecycle transition is not allowed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too Many Requests - Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/orders":{"get":{"tags":["Orders"],"summary":"List orders with filters","description":"\nFetches orders for the authenticated merchant with optional filtering and pagination.\n\n## Query Parameters\n\n- **status**: Filter by order status (comma-separated)\n- **channel**: Filter by sales channel (comma-separated)\n- **search**: Search by order ID or customer email\n- **page**: Page number (default: 1)\n- **limit**: Items per page (default: 20, max: 100)\n  ","security":[{"BearerAuth":[]}],"parameters":[{"schema":{"type":"string"},"required":false,"name":"status","in":"query"},{"schema":{"type":"string"},"required":false,"name":"channel","in":"query"},{"schema":{"type":"string"},"required":false,"name":"search","in":"query"},{"schema":{"type":"integer","minimum":1},"required":false,"name":"page","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":100},"required":false,"name":"limit","in":"query"}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrderListResponse"}}}},"400":{"description":"Bad Request - Invalid input parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Missing or invalid authentication","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/orders/{id}":{"get":{"tags":["Orders"],"summary":"Get order details","description":"Fetches a single order with full details including items, customer, and fulfillments.","security":[{"BearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/Order"}},"required":["success","data"]}}}},"400":{"description":"Bad Request - Invalid input parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Missing or invalid authentication","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource does not exist","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/orders/{id}/status":{"patch":{"tags":["Orders"],"summary":"Update order status","description":"Updates the status of an order.","security":[{"BearerAuth":[],"CSRFToken":[]}],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StatusUpdateRequest"}}}},"responses":{"200":{"description":"Status updated successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["pending","cancelled","inventory_reserved","preparing","shipped","delivered"]},"updated_at":{"type":"string","format":"date-time"}},"required":["id","status","updated_at"]}},"required":["success","data"]}}}},"400":{"description":"Bad Request - Invalid input parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Missing or invalid authentication","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource does not exist","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/orders/bulk-status":{"post":{"tags":["Orders"],"summary":"Bulk update order status","description":"Updates the status of multiple orders at once.","security":[{"BearerAuth":[],"CSRFToken":[]}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkStatusUpdateRequest"}}}},"responses":{"200":{"description":"Statuses updated successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"updated":{"type":"integer"},"orders":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["pending","cancelled","inventory_reserved","preparing","shipped","delivered"]}},"required":["id","status"]}}},"required":["updated","orders"]}},"required":["success","data"]}}}},"400":{"description":"Bad Request - Invalid input parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Missing or invalid authentication","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/orders/stats":{"get":{"tags":["Orders","Analytics"],"summary":"Get order statistics","description":"Fetches aggregated order statistics for the authenticated merchant.","security":[{"BearerAuth":[]}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrderStatsResponse"}}}},"401":{"description":"Unauthorized - Missing or invalid authentication","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/analytics/revenue":{"get":{"tags":["Analytics"],"summary":"Get revenue analytics","description":"\nFetches revenue analytics for the authenticated merchant using optimized database aggregation.\n\n## Query Parameters\n\n- **period**: Time period for analytics (7d, 30d, 90d). Default: 30d\n\n## Response\n\nReturns daily revenue data, totals, and comparison with previous period.\n\n## Performance\n\nUses pre-aggregated RPC function for sub-500ms response times.\n  ","security":[{"BearerAuth":[]}],"parameters":[{"schema":{"type":"string","enum":["7d","30d","90d"],"example":"30d","description":"Time period for analytics"},"required":false,"description":"Time period for analytics","name":"period","in":"query"}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RevenueAnalyticsResponse"}}}},"400":{"description":"Bad Request - Invalid input parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Missing or invalid authentication","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/analytics/activity-heatmap":{"get":{"tags":["Analytics"],"summary":"Get activity heatmap","description":"\nFetches hourly activity heatmap data for the authenticated merchant.\n\n## Query Parameters\n\n- **period**: Number of days to analyze (7-90). Default: 30\n\n## Response\n\nReturns a 7×24 matrix of activity counts by day of week and hour.\n\n## Use Cases\n\n- Visualize peak order times\n- Identify business hours compliance\n- Resource planning\n  ","security":[{"BearerAuth":[]}],"parameters":[{"schema":{"type":"integer","minimum":7,"maximum":90,"example":30,"description":"Number of days to analyze"},"required":false,"description":"Number of days to analyze","name":"period","in":"query"}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ActivityHeatmapResponse"}}}},"400":{"description":"Bad Request - Invalid input parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Missing or invalid authentication","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/analytics/compliance":{"get":{"tags":["Analytics","Compliance"],"summary":"Get compliance analytics","description":"\nFetches compliance analytics including business hours violations.\n\n## Query Parameters\n\n- **period**: Time period for analytics (7d, 30d, 90d). Default: 30d\n\n## Response\n\nReturns violation counts by severity, compliance score, and violation details.\n\n## Compliance Score\n\nScore is calculated as: 100 - (totalViolations × 2), minimum 0.\n  ","security":[{"BearerAuth":[]}],"parameters":[{"schema":{"type":"string","enum":["7d","30d","90d"],"example":"30d","description":"Time period for analytics"},"required":false,"description":"Time period for analytics","name":"period","in":"query"}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ComplianceAnalyticsResponse"}}}},"400":{"description":"Bad Request - Invalid input parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Missing or invalid authentication","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/analytics/abc/summary":{"get":{"tags":["Analytics"],"summary":"Get ABC classification summary","description":"\nFetches ABC category summary metrics from the latest completed classification run at-or-before the requested day.\n\n## Query Parameters\n\n- **lookbackDays**: Lookback window in days. Default: 90\n- **classificationDay**: Requested day in YYYY-MM-DD (UTC). Default: current UTC day\n\n## Read Semantics\n\n- Ignores `running` and `failed` runs\n- Selects latest `completed` run where `classification_day <= requested_day`\n- Returns `isStale=true` when selected classification day is earlier than requested day\n\n## Not Ready Behavior\n\nWhen no completed run exists, response returns `notReady=true` with `run=null`.\n  ","security":[{"BearerAuth":[]}],"parameters":[{"schema":{"type":"integer","minimum":1,"maximum":365,"example":90,"description":"Lookback window in days (max 365)"},"required":false,"description":"Lookback window in days (max 365)","name":"lookbackDays","in":"query"},{"schema":{"type":"string","format":"date","pattern":"^\\d{4}-\\d{2}-\\d{2}$","example":"2026-03-01","description":"Requested UTC day in YYYY-MM-DD (must be calendar-valid)"},"required":false,"description":"Requested UTC day in YYYY-MM-DD (must be calendar-valid)","name":"classificationDay","in":"query"}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AbcSummaryResponse"}}}},"400":{"description":"Bad Request - Invalid input parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Missing or invalid authentication","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/business-hours/settings":{"get":{"tags":["Analytics","Business Hours"],"summary":"Get business hours settings","description":"\nFetches business hours configuration for the authenticated merchant.\n\n## Response\n\nReturns business hours settings for each day of the week, or null if not configured.\n  ","security":[{"BearerAuth":[]}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"allOf":[{"$ref":"#/components/schemas/BusinessHoursSettings"},{"nullable":true}]}},"required":["success","data"]}}}},"401":{"description":"Unauthorized - Missing or invalid authentication","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/products/skus":{"get":{"tags":["Products","SKUs"],"summary":"List SKUs with inventory data","description":"\nFetches SKUs for the authenticated merchant with optional filtering and pagination.\n\n## Query Parameters\n\n- **search**: Search by SKU code, product name, or variant title\n- **category**: Filter by product category\n- **abcCategory**: Filter by ABC category (A, B, C, Unclassified)\n- **lowStock**: Filter to low stock items only\n- **outOfStock**: Filter to out of stock items only\n- **page**: Page number (default: 1)\n- **limit**: Items per page (default: 50, max: 100)\n\n## Response\n\nReturns SKUs with associated inventory positions and Shopify mappings.\n\n## ABC Filter Limitation (MVP)\n\nCombining `abcCategory` with `lowStock` or `outOfStock` returns a validation error (400).\n  ","security":[{"BearerAuth":[]}],"parameters":[{"schema":{"type":"string"},"required":false,"name":"search","in":"query"},{"schema":{"type":"string"},"required":false,"name":"category","in":"query"},{"schema":{"type":"string","enum":["A","B","C","Unclassified"],"description":"Filter by ABC category from the latest completed run"},"required":false,"description":"Filter by ABC category from the latest completed run","name":"abcCategory","in":"query"},{"schema":{"type":"boolean","nullable":true},"required":false,"name":"lowStock","in":"query"},{"schema":{"type":"boolean","nullable":true},"required":false,"name":"outOfStock","in":"query"},{"schema":{"type":"integer","minimum":1},"required":false,"name":"page","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":100},"required":false,"name":"limit","in":"query"}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SKUListResponse"}}}},"400":{"description":"Bad Request - Invalid input parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Missing or invalid authentication","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/products/skus/{id}":{"get":{"tags":["Products","SKUs"],"summary":"Get SKU details","description":"Fetches a single SKU with full details including inventory transactions.","security":[{"BearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/SKU"}},"required":["success","data"]}}}},"400":{"description":"Bad Request - Invalid input parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Missing or invalid authentication","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource does not exist","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"patch":{"tags":["Products","SKUs"],"summary":"Update SKU","description":"Updates a SKU with the provided fields.","security":[{"BearerAuth":[],"CSRFToken":[]}],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SKUUpdateRequest"}}}},"responses":{"200":{"description":"SKU updated successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/SKU"}},"required":["success","data"]}}}},"400":{"description":"Bad Request - Invalid input parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Missing or invalid authentication","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource does not exist","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/products/categories":{"get":{"tags":["Products"],"summary":"Get product categories","description":"Fetches unique product categories for the authenticated merchant.","security":[{"BearerAuth":[]}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"type":"string"}}},"required":["success","data"]}}}},"401":{"description":"Unauthorized - Missing or invalid authentication","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/products/stats":{"get":{"tags":["Products","Analytics"],"summary":"Get product statistics","description":"Fetches aggregated product and inventory statistics for the authenticated merchant. `totalValue` is returned in cents and is derived from the canonical supplier-cost precedence: primary active supplier cost, then any active supplier cost, otherwise 0.","security":[{"BearerAuth":[]}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProductStatsResponse"}}}},"401":{"description":"Unauthorized - Missing or invalid authentication","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/suppliers":{"get":{"tags":["Suppliers"],"summary":"List suppliers with filters","description":"\nFetches suppliers for the authenticated merchant with optional filtering and pagination.\n\n## Query Parameters\n\n- **status**: Filter by status: active (default), inactive, or all\n- **search**: Search by supplier name (case-insensitive, tenant-scoped)\n- **page**: Page number (default: 1)\n- **per_page**: Items per page (default: 20, max: 100)\n\nSupplier names are unique per merchant regardless of active state.\n","security":[{"BearerAuth":[]}],"parameters":[{"schema":{"type":"string","enum":["active","inactive","all"]},"required":false,"name":"status","in":"query"},{"schema":{"type":"string","maxLength":200},"required":false,"name":"search","in":"query"},{"schema":{"type":"integer","minimum":1},"required":false,"name":"page","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":100},"required":false,"name":"per_page","in":"query"}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SupplierListResponse"}}}},"400":{"description":"Bad Request - Invalid input parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Missing or invalid authentication","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden - CSRF violation or insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"post":{"tags":["Suppliers"],"summary":"Create a new supplier","description":"\nCreates a new supplier for the authenticated merchant. Requires merchant_admin role.\n\n- Supplier names are unique per merchant (active or inactive).\n- `merchant_id` is derived from auth context; sending it is an error.\n- Email must match the DB CHECK constraint format.\n","security":[{"BearerAuth":[],"CSRFToken":[]}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSupplierRequest"}}}},"responses":{"200":{"description":"Supplier created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SupplierDetailResponse"}}}},"400":{"description":"Bad Request - Invalid input parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Missing or invalid authentication","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden - CSRF violation or insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Supplier name conflict (duplicate)","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string","enum":["BIZ_RESOURCE_CONFLICT"]},"message":{"type":"string"}},"required":["code","message"]}},"required":["success","error"]}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/suppliers/{id}":{"get":{"tags":["Suppliers"],"summary":"Get supplier details","description":"Fetches a single supplier by ID. Returns not-found without existence leakage for cross-tenant access.","security":[{"BearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SupplierDetailResponse"}}}},"400":{"description":"Bad Request - Invalid input parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Missing or invalid authentication","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden - CSRF violation or insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource does not exist","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"patch":{"tags":["Suppliers"],"summary":"Update a supplier","description":"\nUpdates supplier fields. Requires merchant_admin role.\n\n- Supports reactivation via `is_active: true` on inactive suppliers.\n- Supports deactivation via `is_active: false`.\n- Name changes are checked against all existing suppliers (active or inactive) for the merchant.\n- `merchant_id` is derived from auth context; sending it is an error.\n","security":[{"BearerAuth":[],"CSRFToken":[]}],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateSupplierRequest"}}}},"responses":{"200":{"description":"Supplier updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SupplierDetailResponse"}}}},"400":{"description":"Bad Request - Invalid input parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Missing or invalid authentication","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden - CSRF violation or insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource does not exist","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Supplier name conflict (duplicate)","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string","enum":["BIZ_RESOURCE_CONFLICT"]},"message":{"type":"string"}},"required":["code","message"]}},"required":["success","error"]}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"delete":{"tags":["Suppliers"],"summary":"Deactivate a supplier","description":"\nSoft-deactivates a supplier by setting `is_active` to `false`. Requires merchant_admin role.\n\n- Hard delete is not supported. POs reference suppliers with ON DELETE RESTRICT.\n- Idempotent: returns the current supplier if already inactive.\n- Does not cascade to existing purchase orders or SKU-supplier mappings.\n","security":[{"BearerAuth":[],"CSRFToken":[]}],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Supplier deactivated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SupplierDetailResponse"}}}},"400":{"description":"Bad Request - Invalid input parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Missing or invalid authentication","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden - CSRF violation or insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource does not exist","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/sku-suppliers":{"get":{"tags":["SKU-Suppliers"],"summary":"List SKU-supplier mappings","description":"Fetches SKU-supplier mappings for the authenticated merchant with optional filtering and pagination.","security":[{"BearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":false,"name":"supplier_id","in":"query"},{"schema":{"type":"string","format":"uuid"},"required":false,"name":"sku_id","in":"query"},{"schema":{"type":"integer","minimum":1},"required":false,"name":"page","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":100},"required":false,"name":"per_page","in":"query"}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SkuSupplierListResponse"}}}},"400":{"description":"Bad Request - Invalid input parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Missing or invalid authentication","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden - CSRF violation or insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"post":{"tags":["SKU-Suppliers"],"summary":"Create a SKU-supplier mapping","description":"Creates a new SKU-supplier mapping. Requires merchant_admin role. Supplier must be active.","security":[{"BearerAuth":[],"CSRFToken":[]}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSkuSupplierRequest"}}}},"responses":{"200":{"description":"Mapping created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SkuSupplierDetailResponse"}}}},"400":{"description":"Bad Request - Invalid input parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Missing or invalid authentication","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden - CSRF violation or insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource does not exist","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Duplicate mapping","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string","enum":["BIZ_RESOURCE_CONFLICT"]},"message":{"type":"string"}},"required":["code","message"]}},"required":["success","error"]}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/sku-suppliers/{id}":{"get":{"tags":["SKU-Suppliers"],"summary":"Get SKU-supplier mapping detail","security":[{"BearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SkuSupplierDetailResponse"}}}},"400":{"description":"Bad Request - Invalid input parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Missing or invalid authentication","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden - CSRF violation or insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource does not exist","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"patch":{"tags":["SKU-Suppliers"],"summary":"Update a SKU-supplier mapping","description":"Updates mapping fields. Rejects updates if supplier is inactive. Requires merchant_admin role.","security":[{"BearerAuth":[],"CSRFToken":[]}],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateSkuSupplierRequest"}}}},"responses":{"200":{"description":"Mapping updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SkuSupplierDetailResponse"}}}},"400":{"description":"Bad Request - Invalid input parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Missing or invalid authentication","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden - CSRF violation or insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource does not exist","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"delete":{"tags":["SKU-Suppliers"],"summary":"Delete a SKU-supplier mapping","security":[{"BearerAuth":[],"CSRFToken":[]}],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Mapping deleted","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"deleted":{"type":"boolean","enum":[true]}},"required":["id","deleted"]}},"required":["success","data"]}}}},"400":{"description":"Bad Request - Invalid input parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Missing or invalid authentication","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden - CSRF violation or insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource does not exist","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/sku-suppliers/{id}/set-primary":{"post":{"tags":["SKU-Suppliers"],"summary":"Set a mapping as primary","description":"Uses the set_primary_sku_supplier SECURITY DEFINER RPC to atomically swap primary status.","security":[{"BearerAuth":[],"CSRFToken":[]}],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Primary status updated","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"mapping_id":{"type":"string","format":"uuid"},"sku_id":{"type":"string","format":"uuid"},"previous_primary_id":{"type":"string","nullable":true,"format":"uuid"}},"required":["mapping_id","sku_id","previous_primary_id"]}},"required":["success","data"]}}}},"400":{"description":"Bad Request - Invalid input parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Missing or invalid authentication","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden - CSRF violation or insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource does not exist","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/suppliers/import":{"post":{"tags":["Suppliers"],"summary":"Preview or commit supplier import","description":"Handles both preview and commit via the `action` query parameter. Preview parses a CSV and returns validation results; commit applies validated rows.","security":[{"BearerAuth":[],"CSRFToken":[]}],"parameters":[{"schema":{"type":"string","enum":["preview","commit"]},"required":true,"name":"action","in":"query"}],"requestBody":{"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"file":{"type":"string","format":"binary","description":"CSV file containing supplier import rows."}},"required":["file"]}},"application/json":{"schema":{"type":"object","properties":{"rows":{"type":"array","items":{"nullable":true},"minItems":1}},"required":["rows"]}}}},"responses":{"200":{"description":"Preview or commit result","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"anyOf":[{"type":"object","properties":{"rows":{"type":"array","items":{"nullable":true}},"errors":{"type":"array","items":{"nullable":true}},"total_rows":{"type":"integer"},"valid_rows":{"type":"integer"},"error_rows":{"type":"integer"}},"required":["rows","errors","total_rows","valid_rows","error_rows"]},{"type":"object","properties":{"created_suppliers":{"type":"integer"},"created_mappings":{"type":"integer"}},"required":["created_suppliers","created_mappings"]}]}},"required":["success","data"]}}}},"400":{"description":"Bad Request - Invalid input parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Missing or invalid authentication","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden - CSRF violation or insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Commit failed because a referenced SKU or supplier was not found","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string","enum":["BIZ_RESOURCE_NOT_FOUND"]},"message":{"type":"string"},"details":{"type":"object","properties":{"errors":{"type":"array","items":{"nullable":true}}}}},"required":["code","message"]}},"required":["success","error"]}}}},"409":{"description":"Commit failed because of a duplicate supplier/mapping conflict or invalid supplier state","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string","enum":["BIZ_RESOURCE_CONFLICT","BIZ_INVALID_STATE"]},"message":{"type":"string"},"details":{"type":"object","properties":{"errors":{"type":"array","items":{"nullable":true}}}}},"required":["code","message"]}},"required":["success","error"]}}}},"422":{"description":"Validation errors","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"]}},"required":["success","error"]}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/stocky-import/runs":{"get":{"tags":["Stocky Import"],"summary":"List Stocky import runs","description":"Authenticated Stocky migration assistant route. Merchant scope is derived server-side from the session/JWT. All routes are feature-gated by server env `STOCKY_IMPORT_ASSISTANT_ENABLED` (env key `env.rollout.stockyImportAssistantEnabled`, feature slug `stocky-import-assistant`) and return `403 BIZ_OPERATION_NOT_ALLOWED` with details `{ kind: \"feature_disabled\", feature: \"stocky-import-assistant\" }` when disabled. Merchant admins and fulfillment staff can list safe run summaries directly. Support reps must provide `reason` and may provide `source`; the route writes a support audit entry before returning sanitized summary metadata and fails closed if audit write fails. Missing support reason returns `400 VALID_MISSING_REQUIRED_FIELD` with `details.kind='support_access_reason_required'`.","security":[{"BearerAuth":[]},{"SessionCookieAuth":[]}],"parameters":[{"schema":{"type":"string","minLength":1,"maxLength":500},"required":false,"name":"reason","in":"query"},{"schema":{"type":"string","maxLength":100},"required":false,"name":"source","in":"query"}],"responses":{"200":{"description":"Stocky import runs","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StockyImportRunsResponse"}}}},"400":{"description":"Bad Request - Invalid input parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Missing or invalid authentication","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden. Includes the uniform feature-disabled envelope when `STOCKY_IMPORT_ASSISTANT_ENABLED` is off, or permission failures for unsupported roles.","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/StockyImportFeatureDisabledError"},{"$ref":"#/components/schemas/ErrorResponse"}]}}}},"404":{"description":"Not Found - Resource does not exist","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Stocky import lifecycle, operation-key, or row-state conflict","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StockyImportConflictError"}}}},"422":{"description":"Stocky import commit validation failed with row-level review outcomes","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StockyImportConflictError"}}}},"429":{"description":"Too Many Requests - Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"503":{"description":"Service Unavailable - Rate limiting service is temporarily unavailable","headers":{"Retry-After":{"schema":{"type":"string"},"description":"Seconds until the client should retry the request."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"post":{"tags":["Stocky Import"],"summary":"Create a Stocky import run","description":"Authenticated Stocky migration assistant route. Merchant scope is derived server-side from the session/JWT. All routes are feature-gated by server env `STOCKY_IMPORT_ASSISTANT_ENABLED` (env key `env.rollout.stockyImportAssistantEnabled`, feature slug `stocky-import-assistant`) and return `403 BIZ_OPERATION_NOT_ALLOWED` with details `{ kind: \"feature_disabled\", feature: \"stocky-import-assistant\" }` when disabled. Creates a draft run with server-derived merchant and actor context.","security":[{"BearerAuth":[]},{"SessionCookieAuth":[]}],"responses":{"200":{"description":"Created draft run","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StockyImportRunResponse"}}}},"400":{"description":"Bad Request - Invalid input parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Missing or invalid authentication","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden. Includes the uniform feature-disabled envelope when `STOCKY_IMPORT_ASSISTANT_ENABLED` is off, or permission failures for unsupported roles.","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/StockyImportFeatureDisabledError"},{"$ref":"#/components/schemas/ErrorResponse"}]}}}},"404":{"description":"Not Found - Resource does not exist","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Stocky import lifecycle, operation-key, or row-state conflict","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StockyImportConflictError"}}}},"422":{"description":"Stocky import commit validation failed with row-level review outcomes","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StockyImportConflictError"}}}},"429":{"description":"Too Many Requests - Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"503":{"description":"Service Unavailable - Rate limiting service is temporarily unavailable","headers":{"Retry-After":{"schema":{"type":"string"},"description":"Seconds until the client should retry the request."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/stocky-import/runs/{id}":{"get":{"tags":["Stocky Import"],"summary":"Get a Stocky import run","description":"Authenticated Stocky migration assistant route. Merchant scope is derived server-side from the session/JWT. All routes are feature-gated by server env `STOCKY_IMPORT_ASSISTANT_ENABLED` (env key `env.rollout.stockyImportAssistantEnabled`, feature slug `stocky-import-assistant`) and return `403 BIZ_OPERATION_NOT_ALLOWED` with details `{ kind: \"feature_disabled\", feature: \"stocky-import-assistant\" }` when disabled. Fulfillment staff can read safe run summaries directly. Support reps must provide `reason` and may provide `source`; the route writes a support audit entry before returning sanitized run metadata and fails closed if audit write fails. Raw storage data remains service-role-only. Missing support reason returns `400 VALID_MISSING_REQUIRED_FIELD` with `details.kind='support_access_reason_required'`.","security":[{"BearerAuth":[]},{"SessionCookieAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"id","in":"path"},{"schema":{"type":"string","minLength":1,"maxLength":500},"required":false,"name":"reason","in":"query"},{"schema":{"type":"string","maxLength":100},"required":false,"name":"source","in":"query"}],"responses":{"200":{"description":"Stocky import run","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StockyImportRunResponse"}}}},"400":{"description":"Bad Request - Invalid input parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Missing or invalid authentication","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden. Includes the uniform feature-disabled envelope when `STOCKY_IMPORT_ASSISTANT_ENABLED` is off, or permission failures for unsupported roles.","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/StockyImportFeatureDisabledError"},{"$ref":"#/components/schemas/ErrorResponse"}]}}}},"404":{"description":"Not Found - Resource does not exist","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Stocky import lifecycle, operation-key, or row-state conflict","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StockyImportConflictError"}}}},"422":{"description":"Stocky import commit validation failed with row-level review outcomes","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StockyImportConflictError"}}}},"429":{"description":"Too Many Requests - Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"503":{"description":"Service Unavailable - Rate limiting service is temporarily unavailable","headers":{"Retry-After":{"schema":{"type":"string"},"description":"Seconds until the client should retry the request."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"delete":{"tags":["Stocky Import"],"summary":"Request Stocky import run deletion and raw purge","description":"Authenticated Stocky migration assistant route. Merchant scope is derived server-side from the session/JWT. All routes are feature-gated by server env `STOCKY_IMPORT_ASSISTANT_ENABLED` (env key `env.rollout.stockyImportAssistantEnabled`, feature slug `stocky-import-assistant`) and return `403 BIZ_OPERATION_NOT_ALLOWED` with details `{ kind: \"feature_disabled\", feature: \"stocky-import-assistant\" }` when disabled. Merchant-admin-only deletion queues immediate raw purge for eligible draft, failed, or abandoned runs while preserving sanitized audit/report metadata.","security":[{"BearerAuth":[]},{"SessionCookieAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Updated run with deletion/purge metadata","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StockyImportRunResponse"}}}},"400":{"description":"Bad Request - Invalid input parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Missing or invalid authentication","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden. Includes the uniform feature-disabled envelope when `STOCKY_IMPORT_ASSISTANT_ENABLED` is off, or permission failures for unsupported roles.","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/StockyImportFeatureDisabledError"},{"$ref":"#/components/schemas/ErrorResponse"}]}}}},"404":{"description":"Not Found - Resource does not exist","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Stocky import lifecycle, operation-key, or row-state conflict","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StockyImportConflictError"}}}},"422":{"description":"Stocky import commit validation failed with row-level review outcomes","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StockyImportConflictError"}}}},"429":{"description":"Too Many Requests - Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"503":{"description":"Service Unavailable - Rate limiting service is temporarily unavailable","headers":{"Retry-After":{"schema":{"type":"string"},"description":"Seconds until the client should retry the request."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/stocky-import/runs/{id}/files":{"get":{"tags":["Stocky Import"],"summary":"List uploaded Stocky import files","description":"Authenticated Stocky migration assistant route. Merchant scope is derived server-side from the session/JWT. All routes are feature-gated by server env `STOCKY_IMPORT_ASSISTANT_ENABLED` (env key `env.rollout.stockyImportAssistantEnabled`, feature slug `stocky-import-assistant`) and return `403 BIZ_OPERATION_NOT_ALLOWED` with details `{ kind: \"feature_disabled\", feature: \"stocky-import-assistant\" }` when disabled. Returns authenticated file metadata and detection results; raw objects remain private.","security":[{"BearerAuth":[]},{"SessionCookieAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Stocky import files","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StockyImportFilesResponse"}}}},"400":{"description":"Bad Request - Invalid input parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Missing or invalid authentication","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden. Includes the uniform feature-disabled envelope when `STOCKY_IMPORT_ASSISTANT_ENABLED` is off, or permission failures for unsupported roles.","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/StockyImportFeatureDisabledError"},{"$ref":"#/components/schemas/ErrorResponse"}]}}}},"404":{"description":"Not Found - Resource does not exist","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Stocky import lifecycle, operation-key, or row-state conflict","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StockyImportConflictError"}}}},"422":{"description":"Stocky import commit validation failed with row-level review outcomes","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StockyImportConflictError"}}}},"429":{"description":"Too Many Requests - Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"503":{"description":"Service Unavailable - Rate limiting service is temporarily unavailable","headers":{"Retry-After":{"schema":{"type":"string"},"description":"Seconds until the client should retry the request."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"post":{"tags":["Stocky Import"],"summary":"Upload CSV or ZIP files and persist no-write preview rows","description":"Authenticated Stocky migration assistant route. Merchant scope is derived server-side from the session/JWT. All routes are feature-gated by server env `STOCKY_IMPORT_ASSISTANT_ENABLED` (env key `env.rollout.stockyImportAssistantEnabled`, feature slug `stocky-import-assistant`) and return `403 BIZ_OPERATION_NOT_ALLOWED` with details `{ kind: \"feature_disabled\", feature: \"stocky-import-assistant\" }` when disabled. Accepts multipart `file` or `files` entries. Limits: 50 MiB multipart, 20 multipart parts (individual CSV or ZIP files), up to 50 CSV files after ZIP extraction, 10 MiB per standalone CSV or per ZIP entry, 25 MiB per ZIP, 100 MiB total decompressed, no nested archives, no path traversal, and row caps per detected file role. Upload/preview never mutates suppliers, count sessions, inventory, POs, or Shopify.","security":[{"BearerAuth":[]},{"SessionCookieAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"file":{"type":"string","format":"binary"},"files":{"type":"array","items":{"type":"string","format":"binary"}}}}}}},"responses":{"200":{"description":"Persisted no-write preview result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StockyImportUploadResponse"}}}},"400":{"description":"Missing file or invalid multipart payload","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StockyImportCsvValidationError"}}}},"401":{"description":"Unauthorized - Missing or invalid authentication","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden. Includes the uniform feature-disabled envelope when `STOCKY_IMPORT_ASSISTANT_ENABLED` is off, or permission failures for unsupported roles.","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/StockyImportFeatureDisabledError"},{"$ref":"#/components/schemas/ErrorResponse"}]}}}},"404":{"description":"Not Found - Resource does not exist","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Stocky import lifecycle, operation-key, or row-state conflict","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StockyImportConflictError"}}}},"413":{"description":"Multipart or file size limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StockyImportCsvValidationError"}}}},"422":{"description":"CSV/ZIP safety or parser validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StockyImportCsvValidationError"}}}},"429":{"description":"Too Many Requests - Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"503":{"description":"Service Unavailable - Rate limiting service is temporarily unavailable","headers":{"Retry-After":{"schema":{"type":"string"},"description":"Seconds until the client should retry the request."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/stocky-import/runs/{id}/preview":{"get":{"tags":["Stocky Import"],"summary":"Fetch persisted Stocky import preview","description":"Authenticated Stocky migration assistant route. Merchant scope is derived server-side from the session/JWT. All routes are feature-gated by server env `STOCKY_IMPORT_ASSISTANT_ENABLED` (env key `env.rollout.stockyImportAssistantEnabled`, feature slug `stocky-import-assistant`) and return `403 BIZ_OPERATION_NOT_ALLOWED` with details `{ kind: \"feature_disabled\", feature: \"stocky-import-assistant\" }` when disabled. Read-only preview of persisted files and normalized rows. The `limit` query parameter is clamped to 50,000 internally; values above 50,000 are accepted without error. No inventory or live-data side effects. POST is an alias for clients that need body-less form submission compatibility.","security":[{"BearerAuth":[]},{"SessionCookieAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"id","in":"path"},{"schema":{"type":"integer","minimum":1,"description":"Maximum rows to return. Values above 50,000 are accepted and clamped to 50,000 internally."},"required":false,"description":"Maximum rows to return. Values above 50,000 are accepted and clamped to 50,000 internally.","name":"limit","in":"query"},{"schema":{"type":"integer","nullable":true,"minimum":0},"required":false,"name":"offset","in":"query"}],"responses":{"200":{"description":"Persisted no-write preview","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StockyImportPreviewResponse"}}}},"400":{"description":"Bad Request - Invalid input parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Missing or invalid authentication","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden. Includes the uniform feature-disabled envelope when `STOCKY_IMPORT_ASSISTANT_ENABLED` is off, or permission failures for unsupported roles.","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/StockyImportFeatureDisabledError"},{"$ref":"#/components/schemas/ErrorResponse"}]}}}},"404":{"description":"Not Found - Resource does not exist","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Stocky import lifecycle, operation-key, or row-state conflict","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StockyImportConflictError"}}}},"422":{"description":"Stocky import commit validation failed with row-level review outcomes","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StockyImportConflictError"}}}},"429":{"description":"Too Many Requests - Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"503":{"description":"Service Unavailable - Rate limiting service is temporarily unavailable","headers":{"Retry-After":{"schema":{"type":"string"},"description":"Seconds until the client should retry the request."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"post":{"tags":["Stocky Import"],"summary":"Fetch persisted Stocky import preview (POST alias)","description":"Authenticated Stocky migration assistant route. Merchant scope is derived server-side from the session/JWT. All routes are feature-gated by server env `STOCKY_IMPORT_ASSISTANT_ENABLED` (env key `env.rollout.stockyImportAssistantEnabled`, feature slug `stocky-import-assistant`) and return `403 BIZ_OPERATION_NOT_ALLOWED` with details `{ kind: \"feature_disabled\", feature: \"stocky-import-assistant\" }` when disabled. POST alias of the preview read. The `limit` query parameter is clamped to 50,000 internally; values above 50,000 are accepted without error. No inventory or live-data side effects.","security":[{"BearerAuth":[]},{"SessionCookieAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"id","in":"path"},{"schema":{"type":"integer","minimum":1,"description":"Maximum rows to return. Values above 50,000 are accepted and clamped to 50,000 internally."},"required":false,"description":"Maximum rows to return. Values above 50,000 are accepted and clamped to 50,000 internally.","name":"limit","in":"query"},{"schema":{"type":"integer","nullable":true,"minimum":0},"required":false,"name":"offset","in":"query"}],"responses":{"200":{"description":"Persisted no-write preview","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StockyImportPreviewResponse"}}}},"400":{"description":"Bad Request - Invalid input parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Missing or invalid authentication","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden. Includes the uniform feature-disabled envelope when `STOCKY_IMPORT_ASSISTANT_ENABLED` is off, or permission failures for unsupported roles.","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/StockyImportFeatureDisabledError"},{"$ref":"#/components/schemas/ErrorResponse"}]}}}},"404":{"description":"Not Found - Resource does not exist","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Stocky import lifecycle, operation-key, or row-state conflict","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StockyImportConflictError"}}}},"422":{"description":"Stocky import commit validation failed with row-level review outcomes","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StockyImportConflictError"}}}},"429":{"description":"Too Many Requests - Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"503":{"description":"Service Unavailable - Rate limiting service is temporarily unavailable","headers":{"Retry-After":{"schema":{"type":"string"},"description":"Seconds until the client should retry the request."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/stocky-import/runs/{id}/mappings/suppliers":{"get":{"tags":["Stocky Import"],"summary":"Get supplier mapping decisions for a Stocky import run","description":"Authenticated Stocky migration assistant route. Merchant scope is derived server-side from the session/JWT. All routes are feature-gated by server env `STOCKY_IMPORT_ASSISTANT_ENABLED` (env key `env.rollout.stockyImportAssistantEnabled`, feature slug `stocky-import-assistant`) and return `403 BIZ_OPERATION_NOT_ALLOWED` with details `{ kind: \"feature_disabled\", feature: \"stocky-import-assistant\" }` when disabled. Merchant-admin-only supplier reconstruction mapping surface. Supplier import is create-only in this MVP and does not claim native Stocky supplier export support.","security":[{"BearerAuth":[]},{"SessionCookieAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Supplier rows and decisions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StockySupplierMappingsResponse"}}}},"400":{"description":"Bad Request - Invalid input parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Missing or invalid authentication","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden. Includes the uniform feature-disabled envelope when `STOCKY_IMPORT_ASSISTANT_ENABLED` is off, or permission failures for unsupported roles.","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/StockyImportFeatureDisabledError"},{"$ref":"#/components/schemas/ErrorResponse"}]}}}},"404":{"description":"Not Found - Resource does not exist","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Stocky import lifecycle, operation-key, or row-state conflict","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StockyImportConflictError"}}}},"422":{"description":"Stocky import commit validation failed with row-level review outcomes","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StockyImportConflictError"}}}},"429":{"description":"Too Many Requests - Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"503":{"description":"Service Unavailable - Rate limiting service is temporarily unavailable","headers":{"Retry-After":{"schema":{"type":"string"},"description":"Seconds until the client should retry the request."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"post":{"tags":["Stocky Import"],"summary":"Save supplier mapping decisions","description":"Authenticated Stocky migration assistant route. Merchant scope is derived server-side from the session/JWT. All routes are feature-gated by server env `STOCKY_IMPORT_ASSISTANT_ENABLED` (env key `env.rollout.stockyImportAssistantEnabled`, feature slug `stocky-import-assistant`) and return `403 BIZ_OPERATION_NOT_ALLOWED` with details `{ kind: \"feature_disabled\", feature: \"stocky-import-assistant\" }` when disabled. Saves bounded accepted/rejected supplier mapping decisions for later supplier commit.","security":[{"BearerAuth":[]},{"SessionCookieAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StockySupplierMappingRequest"}}}},"responses":{"200":{"description":"Saved supplier mapping decisions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StockySupplierMappingsResponse"}}}},"400":{"description":"Bad Request - Invalid input parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Missing or invalid authentication","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden. Includes the uniform feature-disabled envelope when `STOCKY_IMPORT_ASSISTANT_ENABLED` is off, or permission failures for unsupported roles.","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/StockyImportFeatureDisabledError"},{"$ref":"#/components/schemas/ErrorResponse"}]}}}},"404":{"description":"Not Found - Resource does not exist","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Stocky import lifecycle, operation-key, or row-state conflict","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StockyImportConflictError"}}}},"422":{"description":"Stocky import commit validation failed with row-level review outcomes","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StockyImportConflictError"}}}},"429":{"description":"Too Many Requests - Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"503":{"description":"Service Unavailable - Rate limiting service is temporarily unavailable","headers":{"Retry-After":{"schema":{"type":"string"},"description":"Seconds until the client should retry the request."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/stocky-import/runs/{id}/commit/suppliers":{"post":{"tags":["Stocky Import"],"summary":"Commit supplier reconstruction rows","description":"Authenticated Stocky migration assistant route. Merchant scope is derived server-side from the session/JWT. All routes are feature-gated by server env `STOCKY_IMPORT_ASSISTANT_ENABLED` (env key `env.rollout.stockyImportAssistantEnabled`, feature slug `stocky-import-assistant`) and return `403 BIZ_OPERATION_NOT_ALLOWED` with details `{ kind: \"feature_disabled\", feature: \"stocky-import-assistant\" }` when disabled. Merchant-admin-only, create-only supplier reconstruction commit. Uses operation-key idempotency scoped by merchant/run/segment/request hash. Replay returns the prior 200 body with `replayed: true`; different request hash, in-progress, and previously failed keys return 409 conflict details.","security":[{"BearerAuth":[]},{"SessionCookieAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StockySupplierCommitRequest"}}}},"responses":{"200":{"description":"Supplier commit result or replayed prior body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StockySupplierCommitResponse"}}}},"400":{"description":"Bad Request - Invalid input parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Missing or invalid authentication","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden. Includes the uniform feature-disabled envelope when `STOCKY_IMPORT_ASSISTANT_ENABLED` is off, or permission failures for unsupported roles.","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/StockyImportFeatureDisabledError"},{"$ref":"#/components/schemas/ErrorResponse"}]}}}},"404":{"description":"Not Found - Resource does not exist","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Stocky import lifecycle, operation-key, or row-state conflict","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StockyImportConflictError"}}}},"422":{"description":"Stocky import commit validation failed with row-level review outcomes","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StockyImportConflictError"}}}},"429":{"description":"Too Many Requests - Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"503":{"description":"Service Unavailable - Rate limiting service is temporarily unavailable","headers":{"Retry-After":{"schema":{"type":"string"},"description":"Seconds until the client should retry the request."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/stocky-import/runs/{id}/mappings/stocktake":{"get":{"tags":["Stocky Import"],"summary":"Preview Stocky stocktake row matching","description":"Authenticated Stocky migration assistant route. Merchant scope is derived server-side from the session/JWT. All routes are feature-gated by server env `STOCKY_IMPORT_ASSISTANT_ENABLED` (env key `env.rollout.stockyImportAssistantEnabled`, feature slug `stocky-import-assistant`) and return `403 BIZ_OPERATION_NOT_ALLOWED` with details `{ kind: \"feature_disabled\", feature: \"stocky-import-assistant\" }` when disabled. Stocktake mapping preview with no inventory or live-data side effects. May refresh run-level review state and row outcome counters so the returned run metadata reflects the latest preview. Merchant admins can see full matching details; fulfillment staff receive redacted sensitive fields. POST is an alias for clients that model preview as an action.","security":[{"BearerAuth":[]},{"SessionCookieAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"No-side-effect stocktake mapping preview","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StockyStocktakeMappingResponse"}}}},"400":{"description":"Bad Request - Invalid input parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Missing or invalid authentication","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden. Includes the uniform feature-disabled envelope when `STOCKY_IMPORT_ASSISTANT_ENABLED` is off, or permission failures for unsupported roles.","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/StockyImportFeatureDisabledError"},{"$ref":"#/components/schemas/ErrorResponse"}]}}}},"404":{"description":"Not Found - Resource does not exist","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Stocky import lifecycle, operation-key, or row-state conflict","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StockyImportConflictError"}}}},"422":{"description":"Stocky import commit validation failed with row-level review outcomes","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StockyImportConflictError"}}}},"429":{"description":"Too Many Requests - Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"503":{"description":"Service Unavailable - Rate limiting service is temporarily unavailable","headers":{"Retry-After":{"schema":{"type":"string"},"description":"Seconds until the client should retry the request."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"post":{"tags":["Stocky Import"],"summary":"Preview Stocky stocktake row matching (POST alias)","description":"Authenticated Stocky migration assistant route. Merchant scope is derived server-side from the session/JWT. All routes are feature-gated by server env `STOCKY_IMPORT_ASSISTANT_ENABLED` (env key `env.rollout.stockyImportAssistantEnabled`, feature slug `stocky-import-assistant`) and return `403 BIZ_OPERATION_NOT_ALLOWED` with details `{ kind: \"feature_disabled\", feature: \"stocky-import-assistant\" }` when disabled. POST alias of the stocktake mapping preview; no inventory or live-data side effects. Does not persist decisions or mutate inventory.","security":[{"BearerAuth":[]},{"SessionCookieAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"No-side-effect stocktake mapping preview","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StockyStocktakeMappingResponse"}}}},"400":{"description":"Bad Request - Invalid input parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Missing or invalid authentication","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden. Includes the uniform feature-disabled envelope when `STOCKY_IMPORT_ASSISTANT_ENABLED` is off, or permission failures for unsupported roles.","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/StockyImportFeatureDisabledError"},{"$ref":"#/components/schemas/ErrorResponse"}]}}}},"404":{"description":"Not Found - Resource does not exist","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Stocky import lifecycle, operation-key, or row-state conflict","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StockyImportConflictError"}}}},"422":{"description":"Stocky import commit validation failed with row-level review outcomes","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StockyImportConflictError"}}}},"429":{"description":"Too Many Requests - Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"503":{"description":"Service Unavailable - Rate limiting service is temporarily unavailable","headers":{"Retry-After":{"schema":{"type":"string"},"description":"Seconds until the client should retry the request."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"patch":{"tags":["Stocky Import"],"summary":"Resolve ambiguous Stocky stocktake rows","description":"Authenticated Stocky migration assistant route. Merchant scope is derived server-side from the session/JWT. All routes are feature-gated by server env `STOCKY_IMPORT_ASSISTANT_ENABLED` (env key `env.rollout.stockyImportAssistantEnabled`, feature slug `stocky-import-assistant`) and return `403 BIZ_OPERATION_NOT_ALLOWED` with details `{ kind: \"feature_disabled\", feature: \"stocky-import-assistant\" }` when disabled. Merchant admins and fulfillment staff can resolve stocktake review rows by marking selected non-duplicate ambiguous rows as `skipped` or choosing one row from a duplicate SKU/location group with `decisionStatus: 'chosen_duplicate'`. This does not create inventory transactions, count sessions, or Shopify writes; it refreshes the mapping preview so draft-count creation can proceed with ready rows only.","security":[{"BearerAuth":[]},{"SessionCookieAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StockyStocktakeResolutionRequest"}}}},"responses":{"200":{"description":"Updated stocktake mapping preview after stocktake row-resolution decisions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StockyStocktakeMappingResponse"}}}},"400":{"description":"Bad Request - Invalid input parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Missing or invalid authentication","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden. Includes the uniform feature-disabled envelope when `STOCKY_IMPORT_ASSISTANT_ENABLED` is off, or permission failures for unsupported roles.","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/StockyImportFeatureDisabledError"},{"$ref":"#/components/schemas/ErrorResponse"}]}}}},"404":{"description":"Not Found - Resource does not exist","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Stocky import lifecycle, operation-key, or row-state conflict","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StockyImportConflictError"}}}},"422":{"description":"Stocky import commit validation failed with row-level review outcomes","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StockyImportConflictError"}}}},"429":{"description":"Too Many Requests - Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"503":{"description":"Service Unavailable - Rate limiting service is temporarily unavailable","headers":{"Retry-After":{"schema":{"type":"string"},"description":"Seconds until the client should retry the request."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/stocky-import/runs/{id}/commit/stocktake":{"post":{"tags":["Stocky Import"],"summary":"Create a draft count session from ready Stocky stocktake rows","description":"Authenticated Stocky migration assistant route. Merchant scope is derived server-side from the session/JWT. All routes are feature-gated by server env `STOCKY_IMPORT_ASSISTANT_ENABLED` (env key `env.rollout.stockyImportAssistantEnabled`, feature slug `stocky-import-assistant`) and return `403 BIZ_OPERATION_NOT_ALLOWED` with details `{ kind: \"feature_disabled\", feature: \"stocky-import-assistant\" }` when disabled. Requires an inventory writer role. Creates a draft stock_take count session only; inventory changes remain in the existing count review/commit workflow. Request body requires `operationKey` and may include `rowIds` and `name`. Invalid/stale rows return row-level outcomes and leave the run in `needs_review`; operation-key replay/conflict semantics match supplier commit.","security":[{"BearerAuth":[]},{"SessionCookieAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StockyStocktakeCommitRequest"}}}},"responses":{"200":{"description":"Draft count session creation result or replayed prior body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StockyStocktakeCommitResponse"}}}},"400":{"description":"Bad Request - Invalid input parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Missing or invalid authentication","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden. Includes the uniform feature-disabled envelope when `STOCKY_IMPORT_ASSISTANT_ENABLED` is off, or permission failures for unsupported roles.","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/StockyImportFeatureDisabledError"},{"$ref":"#/components/schemas/ErrorResponse"}]}}}},"404":{"description":"Not Found - Resource does not exist","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Stocky import lifecycle, operation-key, or row-state conflict","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StockyImportConflictError"}}}},"422":{"description":"Stocky import commit validation failed with row-level review outcomes","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StockyImportConflictError"}}}},"429":{"description":"Too Many Requests - Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"503":{"description":"Service Unavailable - Rate limiting service is temporarily unavailable","headers":{"Retry-After":{"schema":{"type":"string"},"description":"Seconds until the client should retry the request."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/stocky-import/runs/{id}/report.csv":{"get":{"tags":["Stocky Import"],"summary":"Download the secure Stocky import CSV report","description":"Authenticated Stocky migration assistant route. Merchant scope is derived server-side from the session/JWT. All routes are feature-gated by server env `STOCKY_IMPORT_ASSISTANT_ENABLED` (env key `env.rollout.stockyImportAssistantEnabled`, feature slug `stocky-import-assistant`) and return `403 BIZ_OPERATION_NOT_ALLOWED` with details `{ kind: \"feature_disabled\", feature: \"stocky-import-assistant\" }` when disabled. Returns a formula-escaped `text/csv` attachment with `Cache-Control: no-store` and `X-Content-Type-Options: nosniff`. Merchant admins can download directly. Support reps must provide `reason` and may provide `source`; the route writes a support audit entry before reading report rows. Missing support reason returns `400 VALID_MISSING_REQUIRED_FIELD` with `details.kind='support_access_reason_required'`; non-download roles return `403 PERM_INSUFFICIENT_PERMISSIONS`; pre-read support audit failure returns `500` with details kind `support_audit_write_failed`.","security":[{"BearerAuth":[]},{"SessionCookieAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"id","in":"path"},{"schema":{"type":"string","minLength":1,"maxLength":500,"description":"Required for support_rep downloads."},"required":false,"description":"Required for support_rep downloads.","name":"reason","in":"query"},{"schema":{"type":"string","minLength":1,"maxLength":100,"example":"support_ticket"},"required":false,"name":"source","in":"query"}],"responses":{"200":{"description":"CSV attachment containing the secure Stocky import report","headers":{"Content-Disposition":{"schema":{"type":"string"},"description":"attachment; filename=\"...csv\""},"Cache-Control":{"schema":{"type":"string"},"description":"no-store"},"X-Content-Type-Options":{"schema":{"type":"string"},"description":"nosniff"}},"content":{"text/csv":{"schema":{"type":"string"}}}},"400":{"description":"Bad Request - Invalid input parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Missing or invalid authentication","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden. Includes the uniform feature-disabled envelope when `STOCKY_IMPORT_ASSISTANT_ENABLED` is off, or permission failures for unsupported roles.","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/StockyImportFeatureDisabledError"},{"$ref":"#/components/schemas/ErrorResponse"}]}}}},"404":{"description":"Not Found - Resource does not exist","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Stocky import lifecycle, operation-key, or row-state conflict","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StockyImportConflictError"}}}},"422":{"description":"Stocky import commit validation failed with row-level review outcomes","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StockyImportConflictError"}}}},"429":{"description":"Too Many Requests - Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"503":{"description":"Service Unavailable - Rate limiting service is temporarily unavailable","headers":{"Retry-After":{"schema":{"type":"string"},"description":"Seconds until the client should retry the request."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}}}}