{"openapi":"3.1.0","info":{"title":"Curated for You API","description":"\n# API Usage Guide\n\n## Overview\n\nThe Curated for You API provides endpoints to manage and retrieve\ninformation authentication, curations, companies, and attributes. This\nguide will help you understand how to authenticate and interact with\nthe API effectively. Your permissions are setup beforehand when you\njoin the organization, for additional permissions please contact your\ncustomer care representative.\n\n## Authentication\n\nThe Curated for You API uses OAuth 2.0 Bearer token\nauthentication. Follow these steps to authenticate your requests:\n\n```bash\ncurl -X POST 'https://api.curatedforyou.io/api/v1/user/login' \\\n  -H 'Content-Type: application/x-www-form-urlencoded' \\\n  --data-urlencode 'username=your_email@example.com' \\\n  --data-urlencode 'password=your_password'\n```\n\n### Use the Token\n\nAfter a successful login, you will receive a token. This token lasts\nfor 30 minutes(?). Include the received token in the Authorization header\nfor all subsequent requests\n\n```bash\ncurl -G 'https://api.curatedforyou.io/api/v2/endpoint' \\\n  -H 'Authorization: Bearer ENTER_AUTH_TOKEN_HERE' \\\n  -H 'accept: application/json'\n```\n\n## Get Curation Products Guide\n\n### 1. Get Company Information\n\nRetrieve the companies you have access to:\n\n```bash\ncurl -G 'https://api.curatedforyou.io/api/v2/companies' \\\n  -H 'Authorization: Bearer ENTER_AUTH_TOKEN_HERE' \\\n  -H 'accept: application/json' \\\n  -d 'projection=code_name' \\\n  -d 'projection=display_name'\n```\n\nIn this example, we use projection limit our response to only\n`display_name` and the `code_name`.\n\n### 2. Get Curations\n\n\nUse the found `company_id` to get the curations within that company:\n\n```bash\ncurl -G 'https://api.curatedforyou.io/api/v2/curations' \\\n  -H 'Authorization: Bearer ENTER_AUTH_TOKEN_HERE' \\\n  -H 'accept: application/json' \\\n  -d 'company_id=ENTER_COMPANY_ID_HERE' \\\n  -d 'sort_by=created_at:desc' \\\n  -d 'limit=50' \\\n  -d 'offset=0' \\\n  -d 'projection=curation_display_name' \\\n  -d 'projection=curation_group_number' \\\n  -d 'projection=curation_description' \\\n  -d 'projection=export_page_url_handle' \\\n  -d 'projection=company_product_ids'\n```\n\nThis example shows the different ways we can return information by\nspecifying different projections.\n\n### 3. Get Most Recent Snapshot\n\nAfter finding your specific curation we can query the snapshot that\nwas exported to determine what information we should be displaying.\n\nThe curation_group_number is the important id to use and the\ninformation on how and what was exported can be found in the\n`meta_data` field.\n\n```bash\ncurl -G 'https://api.curatedforyou.io/api/v2/curation_snapshots' \\\n  -H 'Authorization: Bearer ENTER_AUTH_TOKEN_HERE' \\\n  -H 'accept: application/json' \\\n  -d 'company_id=ENTER_COMPANY_ID_HERE' \\\n  -d 'curation_group_number=CURATION_GROUP_NUMBER_HERE' \\\n  -d 'sort_by=created_at:desc' \\\n  -d 'limit=50' \\\n  -d 'offset=0' \\\n  -d 'projection=products' \\\n  -d 'projection=meta_data' \\ # <<< where the last export time is found\n  -d 'projection=display_name' \\\n  -d 'projection=created_at'\n```\n","version":"2.0.1","x-logo":{"url":"https://app.curatedforyou.io/cfy_logo.png"}},"paths":{"/api/v2/curations/":{"get":{"tags":["Curations"],"summary":"Fetch Curations","description":"This endpoint returns filtered and sorted curations based on specified query parameters. The response includes\npagination information and supports projection to customize the fields returned.\n\n### Terminology\n- Curation Group Number: A permanent unique identifier assigned to each curation that remains constant even if the curation is renamed or modified\n\n- Company Product ID: An external product identifier provided by the customer for integration purposes\n\n### Brief fields (projection only)\n- page_type and parent_curation_cgn are returned only when requested in projection.\n  Values are taken from curation_briefs.attributes for this company and CGN with scope \"curation\".","operationId":"fetch_curations_api_v2_curations__get","parameters":[{"name":"company_id","in":"query","required":true,"schema":{"type":"integer","description":"Company ID that owns the curations.\nRequired for filtering curations and permission checks.","title":"Company Id"},"description":"Company ID that owns the curations.\nRequired for filtering curations and permission checks.","example":1},{"name":"curation_group_number","in":"query","required":false,"schema":{"anyOf":[{"type":"array","items":{"type":"integer"}},{"type":"null"}],"description":"Filter by Curation Group Numbers (CGNs).\nMultiple CGNs can be provided to filter for multiple groups.","title":"Curation Group Number"},"description":"Filter by Curation Group Numbers (CGNs).\nMultiple CGNs can be provided to filter for multiple groups."},{"name":"search","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Search keyword to filter curations by display name.\nUses case-insensitive partial matching.","title":"Search"},"description":"Search keyword to filter curations by display name.\nUses case-insensitive partial matching."},{"name":"sort_by","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Sort parameter in format 'field:direction:is_nulls_last'.\nDefaults to 'curation_display_name:asc:true' if not specified.\n\n**Available sort fields:**\n- curation_display_name: Sort by display name\n- product_count: Sort by number of products\n- last_export_date: Sort by last export date\n- has_brief: Sort by whether curation brief exists\n- freeze_body.frozen_at: Sort by when the curation was frozen\n**Direction values:**\n- asc: Ascending order\n- desc: Descending order**is_nulls_last values:**\n- true: Null values appear last\n- false: Null values appear first\n\n","title":"Sort By"},"description":"Sort parameter in format 'field:direction:is_nulls_last'.\nDefaults to 'curation_display_name:asc:true' if not specified.\n\n**Available sort fields:**\n- curation_display_name: Sort by display name\n- product_count: Sort by number of products\n- last_export_date: Sort by last export date\n- has_brief: Sort by whether curation brief exists\n- freeze_body.frozen_at: Sort by when the curation was frozen\n**Direction values:**\n- asc: Ascending order\n- desc: Descending order**is_nulls_last values:**\n- true: Null values appear last\n- false: Null values appear first\n\n","example":"created_at:desc"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"description":"Maximum number of curations to return.\nUsed for pagination.","default":50,"title":"Limit"},"description":"Maximum number of curations to return.\nUsed for pagination.","example":50},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"Number of curations to skip.\nUsed for pagination.","default":0,"title":"Offset"},"description":"Number of curations to skip.\nUsed for pagination.","example":0},{"name":"projection","in":"query","required":false,"schema":{"anyOf":[{"type":"array","items":{"type":"string"}},{"type":"null"}],"description":"**Available Fields:**\nid, curation_display_name, curation_group_number, curation_description, export_page_url_handle, export_page_header, export_page_description, export_page_meta_title, export_page_meta_description, promoted_to_live_at, last_export_date, created_at, updated_at, geo, settings, product_count, company_product_ids\n\n**Additional optional fields (projection only):**\npage_type, parent_curation_cgn — from the curation brief (scope=curation) for this CGN; null when missing or invalid.","title":"Projection"},"description":"**Available Fields:**\nid, curation_display_name, curation_group_number, curation_description, export_page_url_handle, export_page_header, export_page_description, export_page_meta_title, export_page_meta_description, promoted_to_live_at, last_export_date, created_at, updated_at, geo, settings, product_count, company_product_ids\n\n**Additional optional fields (projection only):**\npage_type, parent_curation_cgn — from the curation brief (scope=curation) for this CGN; null when missing or invalid.","example":["id","curation_display_name","curation_group_number","curation_description","export_page_url_handle","company_product_ids"]},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"title":"Response Fetch Curations Api V2 Curations  Get"},"examples":{"default":{"summary":"Default Response","value":{"data":[{"id":123,"curation_display_name":"Summer Collection 2024","curation_group_number":456,"curation_group_name":"Summer Collections","version_status":"live","product_count":42,"first_product":{"product_id":789,"image_url":"https://example.com/image.jpg","product_name":"Summer Dress"}}],"total":100,"limit":50,"offset":0}}}}}},"400":{"description":"Bad Request","content":{"application/json":{"examples":{"invalid_status":{"summary":"Invalid Status","value":{"detail":"Invalid status fields: [invalid_status]"}}}}}},"403":{"description":"Forbidden","content":{"application/json":{"examples":{"no_permission":{"summary":"No Permission","value":{"detail":"You do not have permission to read curations."}},"restricted_status":{"summary":"Restricted Status","value":{"detail":"You do not have permission to read updating/inactive/archived curations."}}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"detail":"Company not found"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v2/companies/":{"get":{"tags":["Companies"],"summary":"Get Companies","description":"This endpoint returns filtered & sorted companies.\n\nAUTHENTICATION (dual-mode):\n- Global admin (Clerk or legacy) → all companies.\n- Clerk non-admin → companies whose Clerk org the user belongs to (Redis).\n- Legacy non-admin → companies from permission_id=3 entries in DB.","operationId":"get_companies_api_v2_companies__get","parameters":[{"name":"projection","in":"query","required":false,"schema":{"anyOf":[{"type":"array","items":{"type":"string"}},{"type":"null"}],"description":"Fields to return.","title":"Projection"},"description":"Fields to return.","example":["id","code_name","display_name"]},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"title":"Response Get Companies Api V2 Companies  Get"},"examples":{"default":{"summary":"Default Response","value":{"data":[{"code_name":"example_company","display_name":"Example Company","id":191}]}}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v2/users/login":{"post":{"summary":"Login","description":"Authenticate yourself using your <a href=\"https://app.curatedforyou.io\" target=\"_blank\">CFY App</a> credentials.\n\nThe response contains a bearer token, which you will need to provide to the **Authorization** header to make other requests in the Curation API.","operationId":"login_api_v2_users_login_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_login_api_v2_users_login_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Token"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v2/shopify/install":{"get":{"tags":["shopify"],"summary":"Install","description":"Shopify OAuth install handler.\n\nVerifies HMAC, stores nonce in Redis keyed by nonce value (not shop),\nthen redirects the merchant to Shopify's OAuth consent screen.","operationId":"install_api_v2_shopify_install_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/v2/shopify/callback":{"get":{"tags":["shopify"],"summary":"Callback","description":"Shopify OAuth callback.\n\nVerifies HMAC + nonce, exchanges code for access token, stores token in\nGCP Secret Manager, upserts ShopifyStore DB row, redirects into Admin iframe.","operationId":"callback_api_v2_shopify_callback_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/v2/shopify/app":{"get":{"tags":["shopify"],"summary":"App Status Page","description":"Serve the Account Status page (embedded app home).\n\nNo session token required for the page load — App Bridge v4 injects the token\ninto subsequent fetch() calls automatically.","operationId":"app_status_page_api_v2_shopify_app_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/api/v2/shopify/app/collections":{"get":{"tags":["shopify"],"summary":"App Collections Page","description":"Serve the Collections page of the embedded app.","operationId":"app_collections_page_api_v2_shopify_app_collections_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/api/v2/shopify/ensure-installed":{"post":{"tags":["shopify"],"summary":"Ensure Installed","description":"Exchange session token for offline access token on first load.\n\nManaged installation bypasses /install and /callback — Shopify handles\nconsent itself and loads application_url directly in the iframe. This\nendpoint detects the missing store record and exchanges the session token\n(JWT) for a non-expiring offline access token via Shopify's token exchange\nAPI.\n\nIdempotent: returns immediately if store record already exists.","operationId":"ensure_installed_api_v2_shopify_ensure_installed_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Ensure Installed Api V2 Shopify Ensure Installed Post"}}}}}}},"/api/v2/shopify/status":{"get":{"tags":["shopify"],"summary":"Get Store Status","description":"Return whether the store is linked to a CFY company account.\n\nReturns unlinked (not 404) when the store is brand-new — there is a brief window\nafter OAuth where the session token is valid but the DB upsert hasn't committed yet.","operationId":"get_store_status_api_v2_shopify_status_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StoreStatusResponse"}}}}}}},"/api/v2/shopify/all-collections":{"get":{"tags":["shopify"],"summary":"List All Collections","description":"Fetch all Shopify collections for this store via GraphQL.\n\nWorks for any installer regardless of company_id — reviewers see real data.\nPaginates up to MAX_PAGES (500 collections).","operationId":"list_all_collections_api_v2_shopify_all_collections_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/AllCollectionResponse"},"type":"array","title":"Response List All Collections Api V2 Shopify All Collections Get"}}}}}}},"/api/v2/shopify/collections":{"get":{"tags":["shopify"],"summary":"List Collections","description":"Return CFY-managed collections for this store.\n\nNote: this endpoint is for the export pipeline, not the embedded UI.\nThe embedded UI uses /all-collections (Tab 2) and /status (Tab 1).\nReturns empty list if the store is not yet linked to a CFY company.","operationId":"list_collections_api_v2_shopify_collections_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/CollectionResponse"},"type":"array","title":"Response List Collections Api V2 Shopify Collections Get"}}}}}}},"/api/v2/shopify/request-setup":{"post":{"tags":["shopify"],"summary":"Request Setup","description":"Log an account setup request and notify CFY staff via Slack.\n\nIdempotent per store per 24 hours — prevents flooding from repeated clicks.","operationId":"request_setup_api_v2_shopify_request_setup_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Request Setup Api V2 Shopify Request Setup Post"}}}}}}},"/api/v2/shopify/collections/{handle}/resync":{"post":{"tags":["shopify"],"summary":"Resync Collection","description":"Enqueue a CFY export for the given collection handle.\n\nTODO: integrate with the export Cloud Tasks queue once the export pipeline\nsupports public-app merchants. Currently returns 200 with status=queued.","operationId":"resync_collection_api_v2_shopify_collections__handle__resync_post","parameters":[{"name":"handle","in":"path","required":true,"schema":{"type":"string","title":"Handle"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Resync Collection Api V2 Shopify Collections  Handle  Resync Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v2/shopify/collections/{handle}/request-analysis":{"post":{"tags":["shopify"],"summary":"Request Collection Analysis","description":"Request CFY analysis for an unmanaged collection.\n\nCreates a ShopifyManagedCollection row with status='requested'.\nIdempotent — returns appropriate status on duplicate requests.\nWorks for unlinked stores (no company_id required).","operationId":"request_collection_analysis_api_v2_shopify_collections__handle__request_analysis_post","parameters":[{"name":"handle","in":"path","required":true,"schema":{"type":"string","title":"Handle"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AnalysisRequestBody"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Request Collection Analysis Api V2 Shopify Collections  Handle  Request Analysis Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v2/shopify/webhooks":{"post":{"tags":["shopify"],"summary":"Webhooks","description":"Handle all Shopify webhook topics at a single endpoint.\n\nAll four GDPR + app/uninstalled topics are routed here.\nHMAC is verified before any payload parsing.\nReturns 200 for all valid requests, 401 for HMAC failures.","operationId":"webhooks_api_v2_shopify_webhooks_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Webhooks Api V2 Shopify Webhooks Post"}}}}}}},"/api/v2/shopify/cd/{app_key}/install":{"get":{"tags":["shopify"],"summary":"Install","description":"CD OAuth install handler.\n\nMirrors the public-app `/install`: verifies HMAC against the CD app's\nclient_secret, stores a nonce keyed by value (not shop) to prevent\ntwo-tab races, and redirects the merchant to Shopify's consent screen.","operationId":"install_api_v2_shopify_cd__app_key__install_get","parameters":[{"name":"app_key","in":"path","required":true,"schema":{"type":"string","title":"App Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v2/shopify/cd/{app_key}/callback":{"get":{"tags":["shopify"],"summary":"Callback","description":"CD OAuth callback.\n\nVerifies HMAC + nonce, exchanges the auth code for a token, validates\ngranted scopes, stores the token in Secret Manager at\n`shopify_{app_key}__{slug}_key`, and upserts a ShopifyStore row with\n`shopify_app_key={app_key}`.","operationId":"callback_api_v2_shopify_cd__app_key__callback_get","parameters":[{"name":"app_key","in":"path","required":true,"schema":{"type":"string","title":"App Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v2/feedback/":{"post":{"tags":["Feedback"],"summary":"Ingest AI feedback card (M2M only)","description":"Ingest a new AI feedback card.\n\n**Auth:** Clerk M2M token only. Regular user JWTs receive 403.\n\nAuto-populates `curation_group_number`, `company_id`, and `product_ids`\nfrom the curation record and blocks payload.\n\n**Response 201:** `{id, curation_id, curation_group_number, created_at}`","operationId":"ingest_feedback_api_v2_feedback__post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FeedbackIngestRequest"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"title":"Response Ingest Feedback Api V2 Feedback  Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["Feedback"],"summary":"List pending AI feedback cards for a curation","description":"Return pending AI feedback cards for the given curation.\n\n**Auth:** Regular user JWT with `org:curations:read` permission.\n\n`action_context` is never included in the response.","operationId":"get_feedback_api_v2_feedback__get","parameters":[{"name":"curation_id","in":"query","required":true,"schema":{"type":"integer","description":"Curation ID to fetch feedback for","title":"Curation Id"},"description":"Curation ID to fetch feedback for"},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"description":"Page number","default":1,"title":"Page"},"description":"Page number"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"description":"Items per page (max 100)","default":20,"title":"Limit"},"description":"Items per page (max 100)"},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"title":"Response Get Feedback Api V2 Feedback  Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v2/feedback/{feedback_id}/execute-action":{"post":{"tags":["Feedback"],"summary":"Execute an action on an AI feedback card","description":"Execute an action on an AI feedback card.\n\n**Auth:** Regular user JWT with `org:curations:manage` permission.\n\n| `action_id`            | Behaviour                                          |\n|------------------------|----------------------------------------------------|\n| `dismiss`              | Sets `status=resolved` and `resolved_at`           |\n| `apply_rules`          | Patches linked `CurationBrief` and resolves card   |\n| `apply_product_swap`   | Swaps product at expected position and resolves    |","operationId":"execute_action_api_v2_feedback__feedback_id__execute_action_post","parameters":[{"name":"feedback_id","in":"path","required":true,"schema":{"type":"integer","title":"Feedback Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExecuteActionRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"title":"Response Execute Action Api V2 Feedback  Feedback Id  Execute Action Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/chronicle/log":{"post":{"summary":" Relay Log","operationId":"_relay_log_api_chronicle_log_post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}},"components":{"schemas":{"AllCollectionResponse":{"properties":{"handle":{"type":"string","title":"Handle"},"title":{"type":"string","title":"Title"},"type":{"type":"string","title":"Type"},"product_count":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Product Count"},"updated_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Updated At"},"managed_status":{"type":"string","title":"Managed Status"},"admin_url":{"type":"string","title":"Admin Url"}},"type":"object","required":["handle","title","type","product_count","updated_at","managed_status","admin_url"],"title":"AllCollectionResponse","description":"All Shopify collections — returned by GET /all-collections."},"AnalysisRequestBody":{"properties":{"title":{"type":"string","title":"Title"}},"type":"object","required":["title"],"title":"AnalysisRequestBody"},"Body_login_api_v2_users_login_post":{"properties":{"username":{"type":"string","title":"Username","default":"jeffe@example.com"},"password":{"type":"string","title":"Password","default":"secretpassword"}},"type":"object","title":"Body_login_api_v2_users_login_post"},"CollectionResponse":{"properties":{"handle":{"type":"string","title":"Handle"},"title":{"type":"string","title":"Title"},"type":{"type":"string","title":"Type"},"product_count":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Product Count"},"last_synced_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Last Synced At"},"status":{"type":"string","title":"Status"}},"type":"object","required":["handle","title","type","product_count","last_synced_at","status"],"title":"CollectionResponse","description":"CFY-managed collections — returned by GET /collections."},"ExecuteActionRequest":{"properties":{"action_id":{"type":"string","title":"Action Id"}},"type":"object","required":["action_id"],"title":"ExecuteActionRequest"},"FeedbackIngestRequest":{"properties":{"curation_id":{"type":"integer","title":"Curation Id"},"blocks":{"additionalProperties":true,"type":"object","title":"Blocks"},"action_context":{"additionalProperties":true,"type":"object","title":"Action Context"}},"type":"object","required":["curation_id","blocks","action_context"],"title":"FeedbackIngestRequest"},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"StoreStatusResponse":{"properties":{"linked":{"type":"boolean","title":"Linked"},"shop_domain":{"type":"string","title":"Shop Domain"}},"type":"object","required":["linked","shop_domain"],"title":"StoreStatusResponse","description":"Store link status — returned by GET /status."},"Token":{"properties":{"access_token":{"type":"string","title":"Access Token","description":"Token used to authenticate future API requests","example":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJPbmxpbmUgSldUIEJ1aWxkZXIiLCJpYXQiOjE2NzMwNDkxNzgsImV4cCI6MTcwNDU4NTE3OCwiYXVkIjoid3d3LmV4YW1wbGUuY29tIiwic3ViIjoianJvY2tldEBleGFtcGxlLmNvbSIsIkdpdmVuTmFtZSI6IkpvaG5ueSIsIlN1cm5hbWUiOiJSb2NrZXQiLCJFbWFpbCI6Impyb2NrZXRAZXhhbXBsZS5jb20iLCJSb2xlIjpbIk1hbmFnZXIiLCJQcm9qZWN0IEFkbWluaXN0cmF0b3IiXX0.Y-KnsQHFu4MV67cBTzf92jbt65ex-gQIXPBSwWz5gBM"},"token_type":{"type":"string","title":"Token Type","description":"Token type. Currently we only support OAuth 2.0 Bearer tokens","default":"bearer"}},"type":"object","required":["access_token"],"title":"Token"},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"},"input":{"title":"Input"},"ctx":{"type":"object","title":"Context"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"}}},"tags":[{"name":"Users","x-displayName":"Users"},{"name":"Companies","x-displayName":"Companies"},{"name":"Curations","x-displayName":"Curations"}]}