| Key | Type | Value | Description |
|---|---|---|---|
type | text | simple | Filter type as documented by the endpoint. Required. Type: string. Allowed values: simple, variant. Example: simple |
departmentId | text | 6a65c62109d85c1dbe0e86e2 | Must identify an active, non-deleted department. Required. Type: string. Example: 6a65c62109d85c1dbe0e86e2 |
subdepartmentId | text | 6a65c81b09d85c1dbe0e8732 | Must identify an active, non-deleted subdepartment that belongs to departmentId. Required. Type: string. Example: 6a65c81b09d85c1dbe0e8732 |
name | text | {"ar":"سماعات سوني","en":"Sony headphones"} | JSON-encoded form-data text field with exactly ar and en (2–200 characters each).
Required.
Type: string.
Example: {"ar":"سماعات سوني","en":"Sony headphones"} |
description | text | {"ar":"سماعات بحالة ممتازة","en":"Headphones in excellent condition"} | JSON-encoded form-data text field with exactly ar and en (1–500 characters each).
Required.
Type: string.
Example: {"ar":"سماعات بحالة ممتازة","en":"Headphones in excellent condition"} |
condition | text | used | Condition field. Required. Type: string. Allowed values: new, used. Example: used |
pricingMethod | text | manual | Source of the selling price the client sends. Always required. - `manual`: client-chosen price; `aiPricingRequestId` is optional. - `ai`: price sourced from AI; `aiPricingRequestId` is required and must be a completed provider-owned PricingRequest (`POST /pricing-request` → `data.id`). Required. Type: string. Allowed values: manual, ai. Example: manual |
aiPricingRequestId | text | Required when `pricingMethod=ai`. First call [`POST /pricing-request`](#/AI%20Pricing/createPricingRequest), then pass the returned `data.id` here. Optional when `pricingMethod=manual` (may still be sent to store the AI suggestion for display). Suggested price is loaded server-side; client-submitted AI prices are rejected. PricingRequest currently has no expiry or product-fingerprint fields. Optional. Type: string. | |
quantity | text | 4 | Simple only. Required for `type=simple`. Omit for `type=variant` (variant stock lives in `variants[].quantity`). Optional. Type: integer. Example: 4 |
price | text | 1400 | Simple only. Required selling price for `type=simple`. Omit for `type=variant` — use `variants[].price` instead. Optional. Type: number. Example: 1400 |
discountType | text | percentage | Simple only. Enum: `none` | `percentage` | `fixed`. When `none`, send `discountValue` as `0`. Omit for `type=variant` (use each variant's discount fields). Optional. Type: string. Allowed values: none, percentage, fixed. Example: percentage |
discountValue | text | 10 | Simple only. Percentage or fixed amount depending on `discountType`. Use `0` with `discountType=none`. Omit for `type=variant`. Optional. Type: number. Example: 10 |
attributes disabled | text | ["6a64b113dc6f51f903524f5a","6a64b113dc6f51f903524f5b"] | JSON-encoded array of MongoId strings submitted as a multipart/form-data text field. Required when `type=variant`. Forbidden when `type=simple`. Do not send this field for simple products. Do not send an empty value. Do not use “Send empty value” in Swagger or Postman. These IDs are the selected Product Attributes for the variant product (for example الحجم and اللون). Every variant row must use only `attributeId` values included in this array. Example: ```json [ "6a64b113dc6f51f903524f5a", |
variants disabled | text | [{"attributes":[{"attributeId":"6a64b113dc6f51f903524f5a","valueId":"6a64b145dc6f51f903524f73"},{"attributeId":"6a64b113dc6f51f903524f5b","valueId":"6a64b15fdc6f51f903524f8d"}],"quantity":5,"price":120,"discountType":"none","discountValue":0}] | JSON-encoded array of variant objects submitted as a multipart/form-data text field. Required when `type=variant`. Forbidden when `type=simple`. Do not send this field for simple products. Do not send an empty value. Do not send nested multipart keys such as `variants[0][attributes][0][attributeId]`. Send the full JSON array as the value of this single text field. Each variant is one purchasable combination of selected attribute values (example: الحجم = XL, اللون = أحمر, quantity = 5, price = |
images | file | JPEG/PNG/WEBP, maximum 5MB each. Direct upload; no media registry. Required. Type: file[]. Repeat this multipart file field for each upload supported by the endpoint. Example: <binary image> | |
video | file | Optional MP4/MOV, maximum 50MB. Optional. Type: file. Send as a file field. Prefer PNG / JPG / JPEG / WEBP when image validation applies. |
## Purpose
Create a provider product
## Purpose
Creates a simple or variant product owned by the authenticated provider.
Used by Mobile and Web product-builder screens after taxonomy, pricing,
attributes (variant), and media are collected.
## Actor
Provider (store owner).
## Auth
SecretKeyAuth + ProviderBearerAuth.
Ownership is taken from the JWT. Client-supplied `provider` / `providerId`
and other workflow fields are rejected.
## Headers
- `secretkey` — required application secret (not `x-secret-key`)
- `Authorization: Bearer `
- `lang` — `ar` (default) or `en`
## Transport
`multipart/form-data` only. Every non-file part is a form-data **text** field.
Structured fields (`name`, `description`, `attributes`, `variants`) must
contain JSON-encoded strings; they are parsed and validated server-side.
Required: `type`, `departmentId`, `subdepartmentId`, `name`, `description`,
`condition`, `pricingMethod`, `images` (1–10).
Both taxonomy records must be active and non-deleted, and the selected
subdepartment must belong to the selected department.
When `pricingMethod=ai`, `aiPricingRequestId` is required.
## Product type rules
`type` enum: `simple` | `variant`.
| Field | `type=simple` | `type=variant` |
|-------|---------------|----------------|
| `price` / `quantity` | required | **omit** |
| `discountType` / `discountValue` | optional (`none`/`percentage`/`fixed`) | **omit** |
| `attributes` | **omit** — do not send | required JSON string (MongoId array) |
| `variants` | **omit** — do not send | required JSON string (variant object array) |
Mixing columns returns `products.invalidProductPayload`.
### Mobile / frontend flow (`type=variant`)
1. User selects product type: `variant`.
2. User selects attributes (e.g. الحجم and اللون).
3. App sends selected attribute MongoIds in `attributes` (JSON string).
4. User builds purchasable combinations (e.g. XL + Red, XXL + Black).
5. App sends those combinations in `variants` (JSON string).
6. Each variant includes selected values, `quantity`, `price`, `discountType`, `discountValue`.
### Simple product example
Send product-level `price` / `quantity` / optional discount.
**Omit `attributes` and `variants` entirely** (do not send empty values).
| Part | Value |
|------|-------|
| `type` | `simple` |
| `departmentId` | `6a65c62109d85c1dbe0e86e2` |
| `subdepartmentId` | `6a65c81b09d85c1dbe0e8732` |
| `name` | `{"ar":"سماعات سوني","en":"Sony headphones"}` |
| `description` | `{"ar":"سماعات بحالة ممتازة","en":"Headphones in excellent condition"}` |
| `condition` | `new` |
| `pricingMethod` | `manual` |
| `quantity` | `4` |
| `price` | `1400` |
| `discountType` | `percentage` |
| `discountValue` | `10` |
| `images` | 1–10 image files |
### Variant product example (size + color)
Omit top-level `price` / `quantity` / `discountType` / `discountValue`.
| Part | Value |
|------|-------|
| `type` | `variant` |
| taxonomy / name / description / condition / pricingMethod | same pattern as simple |
| `attributes` | `["6a64b113dc6f51f903524f5a","6a64b113dc6f51f903524f5b"]` |
| `variants` | JSON string — see field schema example |
| `images` | 1–10 image files |
Sample IDs:
- size `attributeId`: `6a64b113dc6f51f903524f5a` · XL `valueId`: `6a64b145dc6f51f903524f73`
- color `attributeId`: `6a64b113dc6f51f903524f5b` · red `valueId`: `6a64b15fdc6f51f903524f8d`
### Common mistakes
- Do not send `attributes` or `variants` for simple products.
- Do not send empty values / enable “Send empty value” for forbidden fields.
- Do not send nested multipart keys for variants.
- Do not send invalid JSON.
- Do not send `valueId` without its matching `attributeId`.
- Do not mix simple pricing fields with variant payloads.
In Swagger Try it out: pick **one** example (`simpleWithPercentage` /
`simpleWithFixed` / `variantOneAttribute` / `variantSizeColor`), attach
`images`, then Execute. Simple examples intentionally omit attributes/variants.
Newly created products return `moderationStatus: wait`, the API value for
pending administration review, and emit the
`product_submitted_for_review` administration-review event. The
administration review notification is created only after Product
persistence succeeds. There is no transaction/outbox for that side-effect:
a request that fails validation, media/taxonomy/AI checks, or Product
persistence never creates a Product-review notification.
The Notification record and administration counter are persisted before
success. External push delivery is deferred and is no