openapi: 3.2.0 info: title: makeup.land Proposals API version: 1.0.0 summary: REST API for makeup.land — Hebrew-RTL professional cosmetics storefront with bilingual product data, ILS + ℳ-credit dual-tender pricing, and agent-friendly endpoints. description: All endpoints live under `/api/v1/`. contact: name: makeup.land url: https://makeup.land license: name: Proprietary url: https://makeup.land/terms-of-service servers: - url: https://makeup.land description: Production tags: - name: Proposals description: Catalog enrichment proposal intake paths: /api/v1/proposals: post: operationId: submitProposals summary: Batch-submit catalog enrichment proposals description: Inserts new proposals after superseding any prior proposals for the same `(entity_id, field_name)` tuple. Snapshots the current ML value for the audit log. Batch is capped at 200 rows; larger payloads return 413. tags: - Proposals security: - bearerAuth: - full - proposals parameters: - name: Idempotency-Key in: header required: false description: 'Optional client-generated idempotency token (recommended: UUIDv4). Retries with the same key within 24h replay the original response.' schema: $schema: https://json-schema.org/draft/2020-12/schema description: 'Optional client-generated idempotency token (recommended: UUIDv4). Retries with the same key within 24h replay the original response.' type: string minLength: 1 maxLength: 255 requestBody: required: true content: application/json: schema: $schema: https://json-schema.org/draft/2020-12/schema anyOf: - type: array items: type: object properties: entity_type: type: string enum: - product description: Only `product` is accepted in Phase 3. entity_id: type: string minLength: 1 field_name: type: string description: Field key from the ENRICH_FIELD_CONTRACT — e.g. `title_he`, `description_he`, `tags`, etc. proposed_value: {} source: type: string description: Provenance label — must be in ENRICH_PROPOSAL_SOURCES (e.g. `manual`, `shopify-import`, `gemini-2.5-pro`, `vps-1.5`). source_detail: type: string confidence: type: number minimum: 0 maximum: 1 vector: description: Optional embedding vector identifier type: string proposed_by: type: string description: Actor that produced the proposal (admin username, agent id, ...) request_id: type: string source_urls: description: HTTP(S) only. Other schemes are rejected at validation. type: array items: type: string format: uri vps_confidence: type: number minimum: 0 maximum: 1 required: - entity_type - entity_id - field_name - proposed_value - source - proposed_by additionalProperties: false - type: object properties: proposals: type: array items: type: object properties: entity_type: type: string enum: - product description: Only `product` is accepted in Phase 3. entity_id: type: string minLength: 1 field_name: type: string description: Field key from the ENRICH_FIELD_CONTRACT — e.g. `title_he`, `description_he`, `tags`, etc. proposed_value: {} source: type: string description: Provenance label — must be in ENRICH_PROPOSAL_SOURCES (e.g. `manual`, `shopify-import`, `gemini-2.5-pro`, `vps-1.5`). source_detail: type: string confidence: type: number minimum: 0 maximum: 1 vector: description: Optional embedding vector identifier type: string proposed_by: type: string description: Actor that produced the proposal (admin username, agent id, ...) request_id: type: string source_urls: description: HTTP(S) only. Other schemes are rejected at validation. type: array items: type: string format: uri vps_confidence: type: number minimum: 0 maximum: 1 required: - entity_type - entity_id - field_name - proposed_value - source - proposed_by additionalProperties: false discovered_image_urls: type: array items: type: string format: uri required: - proposals additionalProperties: false description: Either a bare array of proposals or `{ proposals, discovered_image_urls }`. When the envelope form is used, `discovered_image_urls` is denormalised onto every proposal. responses: '200': description: Counts of inserted + superseded rows content: application/json: schema: $schema: https://json-schema.org/draft/2020-12/schema type: object properties: accepted: type: integer minimum: 0 maximum: 9007199254740991 superseded: type: integer minimum: 0 maximum: 9007199254740991 required: - accepted - superseded additionalProperties: false '400': description: Invalid JSON or envelope content: application/json: schema: $schema: https://json-schema.org/draft/2020-12/schema type: object properties: error: type: string description: Human-readable error message (en or he, copy may shift) error_code: description: Stable machine-readable code. Optional today (legacy callers depend on the `error` string field); will become required in the next API version. type: string enum: - invalid_json - invalid_quantity - invalid_phone - invalid_parameter - product_unavailable - variant_mismatch - tender_unavailable - customer_not_found - line_item_not_found - registration_not_found - insufficient_stock - insufficient_credits - line_collision - phone_conflict - validation_failed - scope_mismatch - read_only_token - rate_limited - unauthorized - internal_error - endpoint_not_found required: - error additionalProperties: {} description: Standard V1 error envelope. Additional fields may be present (e.g. `available_cents`, `requested_cents` on 409 insufficient_credits, `row_errors` on 422 validation failures). '401': description: Missing bearer token content: application/json: schema: $schema: https://json-schema.org/draft/2020-12/schema type: object properties: error: type: string description: Human-readable error message (en or he, copy may shift) error_code: description: Stable machine-readable code. Optional today (legacy callers depend on the `error` string field); will become required in the next API version. type: string enum: - invalid_json - invalid_quantity - invalid_phone - invalid_parameter - product_unavailable - variant_mismatch - tender_unavailable - customer_not_found - line_item_not_found - registration_not_found - insufficient_stock - insufficient_credits - line_collision - phone_conflict - validation_failed - scope_mismatch - read_only_token - rate_limited - unauthorized - internal_error - endpoint_not_found required: - error additionalProperties: {} description: Standard V1 error envelope. Additional fields may be present (e.g. `available_cents`, `requested_cents` on 409 insufficient_credits, `row_errors` on 422 validation failures). '403': description: Read-only token or scope mismatch content: application/json: schema: $schema: https://json-schema.org/draft/2020-12/schema type: object properties: error: type: string description: Human-readable error message (en or he, copy may shift) error_code: description: Stable machine-readable code. Optional today (legacy callers depend on the `error` string field); will become required in the next API version. type: string enum: - invalid_json - invalid_quantity - invalid_phone - invalid_parameter - product_unavailable - variant_mismatch - tender_unavailable - customer_not_found - line_item_not_found - registration_not_found - insufficient_stock - insufficient_credits - line_collision - phone_conflict - validation_failed - scope_mismatch - read_only_token - rate_limited - unauthorized - internal_error - endpoint_not_found required: - error additionalProperties: {} description: Standard V1 error envelope. Additional fields may be present (e.g. `available_cents`, `requested_cents` on 409 insufficient_credits, `row_errors` on 422 validation failures). '413': description: Batch exceeds 200 rows content: application/json: schema: $schema: https://json-schema.org/draft/2020-12/schema type: object properties: error: type: string description: Human-readable error message (en or he, copy may shift) error_code: description: Stable machine-readable code. Optional today (legacy callers depend on the `error` string field); will become required in the next API version. type: string enum: - invalid_json - invalid_quantity - invalid_phone - invalid_parameter - product_unavailable - variant_mismatch - tender_unavailable - customer_not_found - line_item_not_found - registration_not_found - insufficient_stock - insufficient_credits - line_collision - phone_conflict - validation_failed - scope_mismatch - read_only_token - rate_limited - unauthorized - internal_error - endpoint_not_found required: - error additionalProperties: {} description: Standard V1 error envelope. Additional fields may be present (e.g. `available_cents`, `requested_cents` on 409 insufficient_credits, `row_errors` on 422 validation failures). '422': description: Per-row validation errors content: application/json: schema: $schema: https://json-schema.org/draft/2020-12/schema type: object properties: error: type: string const: Validation failed row_errors: type: array items: type: object properties: index: type: integer minimum: 0 maximum: 9007199254740991 field_name: type: string reason: type: string required: - index - field_name - reason additionalProperties: false required: - error - row_errors additionalProperties: false '500': description: Server error content: application/json: schema: $schema: https://json-schema.org/draft/2020-12/schema type: object properties: error: type: string description: Human-readable error message (en or he, copy may shift) error_code: description: Stable machine-readable code. Optional today (legacy callers depend on the `error` string field); will become required in the next API version. type: string enum: - invalid_json - invalid_quantity - invalid_phone - invalid_parameter - product_unavailable - variant_mismatch - tender_unavailable - customer_not_found - line_item_not_found - registration_not_found - insufficient_stock - insufficient_credits - line_collision - phone_conflict - validation_failed - scope_mismatch - read_only_token - rate_limited - unauthorized - internal_error - endpoint_not_found required: - error additionalProperties: {} description: Standard V1 error envelope. Additional fields may be present (e.g. `available_cents`, `requested_cents` on 409 insufficient_credits, `row_errors` on 422 validation failures). components: securitySchemes: bearerAuth: type: http scheme: bearer bearerFormat: ml_ description: API bearer token issued under `api_tokens`. Prefix `ml_` is required. Per-token scope and `read_only` flag govern endpoint + write access. phoneIdentifier: type: apiKey in: query name: phone description: Phone number in E.164 format (e.g. `+972501234567`) that selects which customer's resources to return. **NOT a credential** — endpoints that accept this also REQUIRE `bearerAuth`. The bearer authenticates the calling partner; the phone selects the customer. For POST/PATCH cart-mutation endpoints, the phone goes in the JSON body instead of the query string. x-scopes: full: Full read + write access. Default scope for first-party tokens. register: Issue new customer registrations and read registrations belonging to the token's `registration_source`. Restricted to the `/register` and `/registrations` endpoints. giftcards: Redeem gift cards. Required only by `POST /gift-cards/redeem`. The public `/gift-cards/validate` endpoint requires no token. proposals: Submit catalog enrichment proposals to `/proposals`. Read-only against the rest of the catalog. read_only: Marker for tokens whose `read_only=true` flag rejects every write. Not negotiated at request time — set at token issuance.