Files
backend/docs/website-api/openapi.json
T
Alireza HassaniandCursor 7cef24336a Use /{id}/{fa-slug} detail URLs in sitemaps and add public by-id lookups.
Default sitemap templates now emit SEO-friendly Farsi path segments with stable CMS ids; storefronts resolve content via new by-id public endpoints.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-22 23:43:25 +03:30

3152 lines
77 KiB
JSON
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{
"openapi": "3.0.3",
"info": {
"title": "Meshkee Website API",
"version": "1.0.0",
"description": "Global storefront API for every Meshkee business website.\n\n**Not domain-specific.** Replace `{domain}` with the website apex (e.g. `sanihome.ir`).\n\n**Base URL:** `https://api.meshkee.com/api/v1` (or `https://api.{domain}/api/v1` if that alias is configured).\n\n**Tenant rule:** public content uses `/tenants/{domain}/...`. After login, cart/orders/favorites use `/businesses/{businessId}/...` with Bearer JWT.\n\n**Docs:** https://api.meshkee.com/docs/website"
},
"servers": [
{
"url": "https://api.meshkee.com/api/v1",
"description": "Production (central) — use this for all websites"
},
{
"url": "https://api.{domain}/api/v1",
"description": "Optional per-site alias (same backend). {domain} = website apex",
"variables": {
"domain": {
"default": "example.com"
}
}
}
],
"tags": [
{
"name": "Tenant"
},
{
"name": "SEO"
},
{
"name": "Homepage"
},
{
"name": "Categories"
},
{
"name": "Products"
},
{
"name": "User Products"
},
{
"name": "Store"
},
{
"name": "Blogs"
},
{
"name": "Portfolios"
},
{
"name": "Comments"
},
{
"name": "Expert Reviews"
},
{
"name": "Contact"
},
{
"name": "Auth"
},
{
"name": "Addresses"
},
{
"name": "Cities"
},
{
"name": "Cart"
},
{
"name": "Orders"
},
{
"name": "Favorites"
},
{
"name": "Partner SMS"
},
{
"name": "Payments",
"description": "Online e-payment gateways (website checkout)"
}
],
"components": {
"securitySchemes": {
"bearerAuth": {
"type": "http",
"scheme": "bearer",
"bearerFormat": "JWT"
},
"apiKeyAuth": {
"type": "apiKey",
"in": "header",
"name": "X-Api-Key",
"description": "Partner SMS API key (server-to-server only). Issued per allowlisted domain."
}
},
"parameters": {
"domain": {
"name": "domain",
"in": "path",
"required": true,
"description": "Website apex host only (e.g. sanihome.ir). No www/api/customer/business prefix.",
"schema": {
"type": "string",
"example": "example.com"
}
},
"businessId": {
"name": "businessId",
"in": "path",
"required": true,
"description": "From GET /tenants/{domain} → id",
"schema": {
"type": "string"
}
}
}
},
"paths": {
"/tenants/{domain}": {
"get": {
"tags": [
"Tenant"
],
"summary": "Resolve website domain → business",
"parameters": [
{
"$ref": "#/components/parameters/domain"
}
],
"responses": {
"200": {
"description": "Business branding",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"name": {
"type": "string"
},
"nameFa": {
"type": "string"
},
"slug": {
"type": "string"
},
"domain": {
"type": "string"
},
"primaryColor": {
"type": "string",
"nullable": true
},
"defaultLocale": {
"type": "string",
"enum": [
"en",
"fa"
]
},
"logoUrl": {
"type": "string",
"nullable": true
},
"faviconUrl": {
"type": "string",
"nullable": true
},
"specialProductsSource": {
"type": "string",
"enum": [
"product",
"store_item"
],
"description": "Where homepage special-product carousels read from. Defaults to store_item when the store module is enabled, otherwise product."
}
}
}
}
}
}
}
}
},
"/tenants/{domain}/sitemap.xml": {
"get": {
"tags": [
"SEO"
],
"summary": "XML sitemap for search engines",
"description": "Published products, blogs, and portfolios for this tenant (respects enabled modules), plus static pages and URL templates from the synced website manifest (`GET https://{domain}/meshkee/sitemap-config.json`). Default detail paths: `/products/{id}/{nameFaSlug}`, `/blog/{id}/{titleSlug}`, `/portfolios/{id}/{titleFaSlug}`. Proxied from `https://{domain}/sitemap.xml` on the storefront. Cached in Redis; refreshed after CMS writes and manifest sync.",
"parameters": [
{
"$ref": "#/components/parameters/domain"
}
],
"responses": {
"200": {
"description": "Sitemap XML (urlset)",
"content": {
"application/xml": {
"schema": {
"type": "string"
}
}
},
"headers": {
"Cache-Control": {
"schema": {
"type": "string",
"example": "public, max-age=900"
}
}
}
},
"404": {
"description": "Unknown domain"
}
}
}
},
"/tenants/{domain}/robots.txt": {
"get": {
"tags": [
"SEO"
],
"summary": "robots.txt with sitemap reference",
"description": "Plain-text robots file pointing crawlers to `https://{domain}/sitemap.xml`. Proxied from `https://{domain}/robots.txt` on the storefront.",
"parameters": [
{
"$ref": "#/components/parameters/domain"
}
],
"responses": {
"200": {
"description": "robots.txt",
"content": {
"text/plain": {
"schema": {
"type": "string",
"example": "User-agent: *\\nAllow: /\\n\\nSitemap: https://example.com/sitemap.xml\\n"
}
}
},
"headers": {
"Cache-Control": {
"schema": {
"type": "string",
"example": "public, max-age=900"
}
}
}
},
"404": {
"description": "Unknown domain"
}
}
}
},
"/tenants/{domain}/website/business-info": {
"get": {
"tags": [
"Homepage"
],
"summary": "About, contacts, addresses, social",
"parameters": [
{
"$ref": "#/components/parameters/domain"
}
],
"responses": {
"200": {
"description": "Business public profile"
}
}
}
},
"/tenants/{domain}/website/sliders": {
"get": {
"tags": [
"Homepage"
],
"summary": "Homepage sliders + slides",
"parameters": [
{
"$ref": "#/components/parameters/domain"
}
],
"responses": {
"200": {
"description": "{ items: Slider[] }"
}
}
}
},
"/tenants/{domain}/website/static-images": {
"get": {
"tags": [
"Homepage"
],
"summary": "Named static image slots (single or list)",
"description": "Each slot has a stable `key` used in website placeholders and a `pageKey` (`home`, `products`, `about`, …). Filter with `?pageKey=home`. `kind` is `single` (one image) or `list` (ordered images). `itemCount` is the expected number of images when fixed (e.g. 2 for a two-banner row); omit/null means an unbounded list. Every image may include optional `titleFa`, `titleEn`, `subtext`, and `linkUrl`. Empty `images` means show the site fallback.",
"parameters": [
{
"$ref": "#/components/parameters/domain"
},
{
"name": "pageKey",
"in": "query",
"required": false,
"schema": {
"type": "string",
"example": "home"
},
"description": "If set, only slots for that website page are returned."
}
],
"responses": {
"200": {
"description": "{ items: StaticImageSlot[] } — key, pageKey, kind, label, aspectRatio, recommendedWidth, itemCount, images[{ id, url, titleFa, titleEn, subtext, linkUrl, width, height, sortOrder }]"
}
}
}
},
"/tenants/{domain}/website/static-images/{key}": {
"get": {
"tags": [
"Homepage"
],
"summary": "One static image slot by key",
"parameters": [
{
"$ref": "#/components/parameters/domain"
},
{
"name": "key",
"in": "path",
"required": true,
"schema": {
"type": "string",
"example": "home-hero"
}
}
],
"responses": {
"200": {
"description": "StaticImageSlot"
},
"404": {
"description": "Unknown slot key for this domain"
}
}
}
},
"/tenants/{domain}/website/category-groups": {
"get": {
"tags": [
"Homepage"
],
"summary": "Homepage category groups",
"parameters": [
{
"$ref": "#/components/parameters/domain"
}
],
"responses": {
"200": {
"description": "{ items: CategoryGroup[] } — each group has id, key, title, items[]"
}
}
}
},
"/tenants/{domain}/website/brand-groups": {
"get": {
"tags": [
"Homepage"
],
"summary": "Homepage brand groups",
"parameters": [
{
"$ref": "#/components/parameters/domain"
}
],
"responses": {
"200": {
"description": "{ items: BrandGroup[] } — each group has id, key, title, items[]"
}
}
}
},
"/tenants/{domain}/store-specials": {
"get": {
"tags": [
"Homepage",
"Store"
],
"summary": "Active store specials",
"parameters": [
{
"$ref": "#/components/parameters/domain"
}
],
"responses": {
"200": {
"description": "{ source: product|store_item, items: StoreSpecial[] } — source is the business special-products setting; each special has id, key, title, items[]"
}
}
}
},
"/tenants/{domain}/categories": {
"get": {
"tags": [
"Categories"
],
"summary": "Public categories",
"parameters": [
{
"$ref": "#/components/parameters/domain"
},
{
"name": "entityType",
"in": "query",
"schema": {
"type": "string",
"enum": [
"product",
"blog",
"portfolio",
"video"
],
"default": "product"
}
}
],
"responses": {
"200": {
"description": "{ items: Category[] }"
}
}
}
},
"/tenants/{domain}/products": {
"get": {
"tags": [
"Products"
],
"summary": "List published products",
"parameters": [
{
"$ref": "#/components/parameters/domain"
},
{
"name": "page",
"in": "query",
"schema": {
"type": "integer"
}
},
{
"name": "pageSize",
"in": "query",
"schema": {
"type": "integer",
"default": 12
}
},
{
"name": "name",
"in": "query",
"schema": {
"type": "string"
}
},
{
"name": "categoryId",
"in": "query",
"schema": {
"type": "string"
}
},
{
"name": "brandId",
"in": "query",
"schema": {
"type": "string"
}
},
{
"name": "tag",
"in": "query",
"schema": {
"type": "string"
}
},
{
"name": "inStore",
"in": "query",
"schema": {
"type": "boolean"
}
}
],
"responses": {
"200": {
"description": "{ items, total, page, pageSize }"
}
}
}
},
"/tenants/{domain}/products/by-id/{productId}": {
"get": {
"tags": [
"Products"
],
"summary": "Product by id (preferred for /products/{id}/{nameFaSlug} pages)",
"parameters": [
{
"$ref": "#/components/parameters/domain"
},
{
"name": "productId",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "{ product, relatedProducts } — same shape as product-by-slug"
}
}
}
},
"/tenants/{domain}/products/by-id/{productId}/variations": {
"get": {
"tags": [
"Products"
],
"summary": "Product variations by id",
"parameters": [
{
"$ref": "#/components/parameters/domain"
},
{
"name": "productId",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "Variation tree for the product"
}
}
}
},
"/tenants/{domain}/products/by-id/{productId}/technical-info": {
"get": {
"tags": [
"Products"
],
"summary": "Product technical info by id",
"parameters": [
{
"$ref": "#/components/parameters/domain"
},
{
"name": "productId",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "Technical form + values"
}
}
}
},
"/tenants/{domain}/products/{slug}": {
"get": {
"tags": [
"Products"
],
"summary": "Product by slug",
"parameters": [
{
"$ref": "#/components/parameters/domain"
},
{
"name": "slug",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "{ product, relatedProducts } — relatedProducts uses the product list-card shape (incl. store). Ranked by relativity (same category, then same brand) with availability beside it (in-stock first within each group). Up to 8 items; excludes the current product."
}
}
}
},
"/tenants/{domain}/products/{slug}/variations": {
"get": {
"tags": [
"Products"
],
"summary": "Product variation options",
"parameters": [
{
"$ref": "#/components/parameters/domain"
},
{
"name": "slug",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "{ variations }"
}
}
}
},
"/tenants/{domain}/products/{slug}/technical-info": {
"get": {
"tags": [
"Products"
],
"summary": "Product technical specs",
"parameters": [
{
"$ref": "#/components/parameters/domain"
},
{
"name": "slug",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "{ form, values }"
}
}
}
},
"/tenants/{domain}/user-products": {
"get": {
"tags": [
"User Products"
],
"summary": "List published customer / stock listings",
"description": "Public marketplace-style listings created by customers (user products). Only `status=published`. Search with `name` or `q` (title/description). Filter by category, city, country, condition, or promoted.",
"parameters": [
{
"$ref": "#/components/parameters/domain"
},
{
"name": "page",
"in": "query",
"schema": {
"type": "integer",
"default": 1
}
},
{
"name": "pageSize",
"in": "query",
"schema": {
"type": "integer",
"default": 12
}
},
{
"name": "name",
"in": "query",
"description": "Search title/description (alias of q)",
"schema": {
"type": "string"
}
},
{
"name": "q",
"in": "query",
"description": "Search title/description (alias of name)",
"schema": {
"type": "string"
}
},
{
"name": "categoryId",
"in": "query",
"schema": {
"type": "string"
}
},
{
"name": "cityId",
"in": "query",
"schema": {
"type": "string"
}
},
{
"name": "countryId",
"in": "query",
"schema": {
"type": "string"
}
},
{
"name": "condition",
"in": "query",
"schema": {
"type": "string",
"enum": [
"new",
"stock",
"needs_repair",
"scrap"
]
}
},
{
"name": "promoted",
"in": "query",
"schema": {
"type": "boolean"
}
}
],
"responses": {
"200": {
"description": "{ items: UserProductListItem[], total, page, pageSize }. Each item includes id, slug, titleFa/titleEn, price, priceCurrency, condition, city/country names, imageUrl, category*, promoted, publishedAt."
}
}
}
},
"/tenants/{domain}/user-products/{slug}": {
"get": {
"tags": [
"User Products"
],
"summary": "User product details by slug",
"description": "Full published listing: location IDs, gallery images (`images`, `galleryMediaIds`), technical field values, delivery/technical notes.",
"parameters": [
{
"$ref": "#/components/parameters/domain"
},
{
"name": "slug",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "{ product } with gallery (`images`: [{ mediaId, url }]), featuredMediaId, technicalValues, countryId, cityId, countrySlug"
},
"404": {
"description": "Not found or not published"
}
}
}
},
"/tenants/{domain}/user-products/{slug}/technical-info": {
"get": {
"tags": [
"User Products"
],
"summary": "User product technical form + values",
"description": "Category technical form schema plus the listing’s submitted values (same shape as dashboard technical values).",
"parameters": [
{
"$ref": "#/components/parameters/domain"
},
{
"name": "slug",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "{ form, values }"
}
}
}
},
"/tenants/{domain}/store-items": {
"get": {
"tags": [
"Store"
],
"summary": "List sellable variants",
"parameters": [
{
"$ref": "#/components/parameters/domain"
},
{
"name": "page",
"in": "query",
"schema": {
"type": "integer"
}
},
{
"name": "pageSize",
"in": "query",
"schema": {
"type": "integer",
"default": 20
}
},
{
"name": "categoryId",
"in": "query",
"schema": {
"type": "string"
}
},
{
"name": "brandId",
"in": "query",
"schema": {
"type": "string"
}
},
{
"name": "productId",
"in": "query",
"schema": {
"type": "string"
}
},
{
"name": "name",
"in": "query",
"description": "Instant search on product title / nameFa. Results are ordered in-stock first (unlimited or qty > 0), then by updatedAt desc.",
"schema": {
"type": "string"
}
},
{
"name": "inStock",
"in": "query",
"schema": {
"type": "boolean"
}
},
{
"name": "isFestival",
"in": "query",
"schema": {
"type": "boolean"
}
},
{
"name": "minPrice",
"in": "query",
"schema": {
"type": "number"
}
},
{
"name": "maxPrice",
"in": "query",
"schema": {
"type": "number"
}
}
],
"responses": {
"200": {
"description": "{ items, total, page, pageSize }"
}
}
}
},
"/tenants/{domain}/store-items/by-product/{productId}": {
"get": {
"tags": [
"Store"
],
"summary": "Variants for one product",
"parameters": [
{
"$ref": "#/components/parameters/domain"
},
{
"name": "productId",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "{ storeItem }"
}
}
}
},
"/tenants/{domain}/store-items/{variantId}": {
"get": {
"tags": [
"Store"
],
"summary": "One variant",
"parameters": [
{
"$ref": "#/components/parameters/domain"
},
{
"name": "variantId",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "{ variant }"
}
}
}
},
"/tenants/{domain}/blogs": {
"get": {
"tags": [
"Blogs"
],
"summary": "List published blogs",
"parameters": [
{
"$ref": "#/components/parameters/domain"
},
{
"name": "page",
"in": "query",
"schema": {
"type": "integer"
}
},
{
"name": "pageSize",
"in": "query",
"schema": {
"type": "integer",
"default": 12
}
},
{
"name": "type",
"in": "query",
"schema": {
"type": "string",
"enum": [
"news",
"article",
"blog"
]
}
},
{
"name": "categoryId",
"in": "query",
"schema": {
"type": "string"
}
},
{
"name": "title",
"in": "query",
"schema": {
"type": "string"
}
},
{
"name": "tag",
"in": "query",
"description": "Filter by exact tag in metadata.tags",
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "{ items, total, page, pageSize }"
}
}
}
},
"/tenants/{domain}/blogs/by-id/{blogId}": {
"get": {
"tags": [
"Blogs"
],
"summary": "Blog by id (preferred for /blog/{id}/{titleSlug} pages)",
"parameters": [
{
"$ref": "#/components/parameters/domain"
},
{
"name": "blogId",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "{ blog }"
}
}
}
},
"/tenants/{domain}/blogs/{slug}": {
"get": {
"tags": [
"Blogs"
],
"summary": "Blog by slug",
"parameters": [
{
"$ref": "#/components/parameters/domain"
},
{
"name": "slug",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "{ blog }"
}
}
}
},
"/tenants/{domain}/blogs/{blogId}/comments": {
"get": {
"tags": [
"Blogs",
"Comments"
],
"summary": "Approved blog comments",
"parameters": [
{
"$ref": "#/components/parameters/domain"
},
{
"name": "blogId",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "{ items }"
}
}
},
"post": {
"tags": [
"Blogs",
"Comments"
],
"summary": "Submit blog comment",
"parameters": [
{
"$ref": "#/components/parameters/domain"
},
{
"name": "blogId",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"authorName",
"text"
],
"properties": {
"authorName": {
"type": "string"
},
"authorEmail": {
"type": "string"
},
"text": {
"type": "string"
}
}
}
}
}
},
"responses": {
"201": {
"description": "{ comment, message }"
}
}
}
},
"/tenants/{domain}/videos": {
"get": {
"tags": [
"Videos"
],
"summary": "List published videos",
"parameters": [
{
"$ref": "#/components/parameters/domain"
},
{
"name": "page",
"in": "query",
"schema": {
"type": "integer"
}
},
{
"name": "pageSize",
"in": "query",
"schema": {
"type": "integer",
"default": 12
}
},
{
"name": "provider",
"in": "query",
"schema": {
"type": "string",
"enum": [
"youtube",
"aparat"
]
}
},
{
"name": "categoryId",
"in": "query",
"schema": {
"type": "string"
}
},
{
"name": "title",
"in": "query",
"schema": {
"type": "string"
}
},
{
"name": "tag",
"in": "query",
"description": "Filter by exact tag in metadata.tags",
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "{ items, total, page, pageSize }"
}
}
}
},
"/tenants/{domain}/videos/{slug}": {
"get": {
"tags": [
"Videos"
],
"summary": "Video by slug",
"parameters": [
{
"$ref": "#/components/parameters/domain"
},
{
"name": "slug",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "{ video }"
}
}
}
},
"/tenants/{domain}/videos/{videoId}/comments": {
"get": {
"tags": [
"Videos",
"Comments"
],
"summary": "Approved video comments",
"parameters": [
{
"$ref": "#/components/parameters/domain"
},
{
"name": "videoId",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "{ items }"
}
}
},
"post": {
"tags": [
"Videos",
"Comments"
],
"summary": "Submit video comment",
"parameters": [
{
"$ref": "#/components/parameters/domain"
},
{
"name": "videoId",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"authorName",
"text"
],
"properties": {
"authorName": {
"type": "string"
},
"authorEmail": {
"type": "string"
},
"text": {
"type": "string"
}
}
}
}
}
},
"responses": {
"201": {
"description": "{ comment, message }"
}
}
}
},
"/tenants/{domain}/portfolios": {
"get": {
"tags": [
"Portfolios"
],
"summary": "List published portfolios",
"parameters": [
{
"$ref": "#/components/parameters/domain"
},
{
"name": "page",
"in": "query",
"schema": {
"type": "integer"
}
},
{
"name": "pageSize",
"in": "query",
"schema": {
"type": "integer",
"default": 12
}
},
{
"name": "categoryId",
"in": "query",
"schema": {
"type": "string"
}
},
{
"name": "title",
"in": "query",
"schema": {
"type": "string"
}
},
{
"name": "tag",
"in": "query",
"description": "Filter by exact tag in metadata.tags",
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "{ items, total, page, pageSize }"
}
}
}
},
"/tenants/{domain}/portfolios/by-id/{portfolioId}": {
"get": {
"tags": [
"Portfolios"
],
"summary": "Portfolio by id (preferred for /portfolios/{id}/{titleFaSlug} pages)",
"parameters": [
{
"$ref": "#/components/parameters/domain"
},
{
"name": "portfolioId",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "{ portfolio }"
}
}
}
},
"/tenants/{domain}/portfolios/{slug}": {
"get": {
"tags": [
"Portfolios"
],
"summary": "Portfolio by slug",
"parameters": [
{
"$ref": "#/components/parameters/domain"
},
{
"name": "slug",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "{ portfolio }"
}
}
}
},
"/tenants/{domain}/portfolios/{portfolioId}/comments": {
"get": {
"tags": [
"Portfolios",
"Comments"
],
"summary": "Approved portfolio comments",
"parameters": [
{
"$ref": "#/components/parameters/domain"
},
{
"name": "portfolioId",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "{ items }"
}
}
},
"post": {
"tags": [
"Portfolios",
"Comments"
],
"summary": "Submit portfolio comment",
"parameters": [
{
"$ref": "#/components/parameters/domain"
},
{
"name": "portfolioId",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"authorName",
"text"
],
"properties": {
"authorName": {
"type": "string"
},
"authorEmail": {
"type": "string"
},
"text": {
"type": "string"
}
}
}
}
}
},
"responses": {
"201": {
"description": "{ comment, message }"
}
}
}
},
"/tenants/{domain}/comments": {
"get": {
"tags": [
"Comments"
],
"summary": "List approved comments for any entity",
"parameters": [
{
"$ref": "#/components/parameters/domain"
},
{
"name": "entityType",
"in": "query",
"required": true,
"schema": {
"type": "string",
"enum": [
"product",
"blog",
"portfolio",
"video"
]
}
},
{
"name": "entityId",
"in": "query",
"required": true,
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "{ items }"
}
}
},
"post": {
"tags": [
"Comments"
],
"summary": "Submit comment (product/blog/portfolio)",
"parameters": [
{
"$ref": "#/components/parameters/domain"
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"entityType",
"entityId",
"authorName",
"text"
],
"properties": {
"entityType": {
"type": "string",
"enum": [
"product",
"blog",
"portfolio",
"video"
]
},
"entityId": {
"type": "string"
},
"authorName": {
"type": "string"
},
"authorEmail": {
"type": "string"
},
"text": {
"type": "string"
}
}
}
}
}
},
"responses": {
"201": {
"description": "{ comment, message }"
}
}
}
},
"/tenants/{domain}/expert-reviews": {
"get": {
"tags": [
"Expert Reviews"
],
"summary": "Approved expert reviews for a product",
"parameters": [
{
"$ref": "#/components/parameters/domain"
},
{
"name": "productId",
"in": "query",
"required": true,
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "{ items }"
}
}
},
"post": {
"tags": [
"Expert Reviews"
],
"summary": "Submit expert review",
"parameters": [
{
"$ref": "#/components/parameters/domain"
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"productId",
"authorName",
"rate",
"positivePoints",
"negativePoints",
"text"
],
"properties": {
"productId": {
"type": "string"
},
"authorName": {
"type": "string"
},
"authorEmail": {
"type": "string"
},
"rate": {
"type": "integer",
"minimum": 1,
"maximum": 10
},
"positivePoints": {
"type": "array",
"items": {
"type": "string"
}
},
"negativePoints": {
"type": "array",
"items": {
"type": "string"
}
},
"text": {
"type": "string"
}
}
}
}
}
},
"responses": {
"201": {
"description": "{ review, message }"
}
}
}
},
"/tenants/{domain}/contact-submissions": {
"post": {
"tags": [
"Contact"
],
"summary": "Contact form",
"parameters": [
{
"$ref": "#/components/parameters/domain"
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"title",
"name",
"text"
],
"properties": {
"title": {
"type": "string"
},
"name": {
"type": "string"
},
"email": {
"type": "string"
},
"cellNumber": {
"type": "string"
},
"text": {
"type": "string"
}
}
}
}
}
},
"responses": {
"201": {
"description": "{ submission, message }"
}
}
}
},
"/auth/register": {
"post": {
"tags": [
"Auth"
],
"summary": "Register customer on a website",
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"cellNumber",
"password",
"firstName",
"lastName",
"domain"
],
"properties": {
"cellNumber": {
"type": "string",
"description": "E.164 e.g. +98912..."
},
"password": {
"type": "string",
"minLength": 8
},
"firstName": {
"type": "string"
},
"lastName": {
"type": "string"
},
"email": {
"type": "string"
},
"domain": {
"type": "string",
"description": "Same website apex as {domain}"
},
"acknowledgeExistingAccount": {
"type": "boolean",
"description": "If true, link an existing Meshkee account from another website without matching its password. Profile stays unchanged; password is replaced with the new signup password. Response may include passwordUpdated: true."
}
}
}
}
}
},
"responses": {
"201": {
"description": "{ user, accessToken, refreshToken, registeredBusiness }"
}
}
}
},
"/auth/login": {
"post": {
"tags": [
"Auth"
],
"summary": "Login",
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"cellNumber",
"password"
],
"properties": {
"cellNumber": {
"type": "string"
},
"password": {
"type": "string"
}
}
}
}
}
},
"responses": {
"200": {
"description": "{ user, accessToken, refreshToken }"
}
}
}
},
"/auth/login-otp": {
"post": {
"tags": [
"Auth"
],
"summary": "Passwordless login with SMS OTP",
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"cellNumber",
"code"
],
"properties": {
"cellNumber": {
"type": "string"
},
"code": {
"type": "string",
"minLength": 6,
"maxLength": 6
}
}
}
}
}
},
"responses": {
"200": {
"description": "{ user, accessToken, refreshToken }"
}
}
}
},
"/auth/reset-password": {
"post": {
"tags": [
"Auth"
],
"summary": "Reset password with SMS OTP",
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"cellNumber",
"code",
"newPassword"
],
"properties": {
"cellNumber": {
"type": "string"
},
"code": {
"type": "string",
"minLength": 6,
"maxLength": 6
},
"newPassword": {
"type": "string",
"minLength": 8
}
}
}
}
}
},
"responses": {
"200": {
"description": "{ message }"
}
}
}
},
"/auth/refresh": {
"post": {
"tags": [
"Auth"
],
"summary": "Refresh tokens",
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"refreshToken"
],
"properties": {
"refreshToken": {
"type": "string"
}
}
}
}
}
},
"responses": {
"200": {
"description": "{ user, accessToken, refreshToken }"
}
}
}
},
"/auth/me": {
"get": {
"tags": [
"Auth"
],
"summary": "Current user",
"security": [
{
"bearerAuth": []
}
],
"responses": {
"200": {
"description": "{ user }"
}
}
}
},
"/auth/profile": {
"patch": {
"tags": [
"Auth"
],
"summary": "Update profile",
"security": [
{
"bearerAuth": []
}
],
"responses": {
"200": {
"description": "{ message, user }"
}
}
}
},
"/auth/change-password": {
"post": {
"tags": [
"Auth"
],
"summary": "Change password",
"security": [
{
"bearerAuth": []
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"currentPassword",
"newPassword"
],
"properties": {
"currentPassword": {
"type": "string"
},
"newPassword": {
"type": "string",
"minLength": 8
}
}
}
}
}
},
"responses": {
"200": {
"description": "{ message }"
}
}
}
},
"/auth/send-otp": {
"post": {
"tags": [
"Auth"
],
"summary": "Send OTP SMS",
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"cellNumber"
],
"properties": {
"cellNumber": {
"type": "string"
},
"domain": {
"type": "string",
"description": "Tenant host/apex used to brand the OTP SMS with the business Farsi name"
}
}
}
}
}
},
"responses": {
"200": {
"description": "{ enabled, message, expiresInSeconds? }"
}
}
}
},
"/auth/verify-otp": {
"post": {
"tags": [
"Auth"
],
"summary": "Verify OTP",
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"cellNumber",
"code"
],
"properties": {
"cellNumber": {
"type": "string"
},
"code": {
"type": "string",
"minLength": 6,
"maxLength": 6
}
}
}
}
}
},
"responses": {
"200": {
"description": "{ enabled, verified, message }"
}
}
}
},
"/auth/addresses": {
"get": {
"tags": [
"Addresses"
],
"summary": "List my shipping addresses",
"security": [
{
"bearerAuth": []
}
],
"responses": {
"200": {
"description": "{ items }"
}
}
},
"post": {
"tags": [
"Addresses"
],
"summary": "Create address",
"security": [
{
"bearerAuth": []
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"province",
"city",
"address"
],
"properties": {
"label": {
"type": "string"
},
"province": {
"type": "string"
},
"city": {
"type": "string"
},
"address": {
"type": "string"
},
"postalCode": {
"type": "string"
},
"landline": {
"type": "string"
}
}
}
}
}
},
"responses": {
"201": {
"description": "{ address }"
}
}
}
},
"/auth/addresses/{addressId}": {
"patch": {
"tags": [
"Addresses"
],
"summary": "Update address",
"security": [
{
"bearerAuth": []
}
],
"parameters": [
{
"name": "addressId",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "{ address }"
}
}
},
"delete": {
"tags": [
"Addresses"
],
"summary": "Delete address",
"security": [
{
"bearerAuth": []
}
],
"parameters": [
{
"name": "addressId",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "{ message }"
}
}
}
},
"/cities": {
"get": {
"tags": [
"Cities"
],
"summary": "Location tree (countries / provinces / cities)",
"parameters": [
{
"name": "level",
"in": "query",
"schema": {
"type": "string",
"enum": [
"country",
"province",
"city"
]
}
},
{
"name": "parentId",
"in": "query",
"schema": {
"type": "string"
}
},
{
"name": "parentSlug",
"in": "query",
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "{ items }"
}
}
}
},
"/cities/{cityId}": {
"get": {
"tags": [
"Cities"
],
"summary": "Get one location node",
"parameters": [
{
"name": "cityId",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "{ city }"
}
}
}
},
"/businesses/{businessId}/cart": {
"get": {
"tags": [
"Cart"
],
"summary": "Get cart",
"security": [
{
"bearerAuth": []
}
],
"parameters": [
{
"$ref": "#/components/parameters/businessId"
}
],
"responses": {
"200": {
"description": "{ cart }"
}
}
},
"delete": {
"tags": [
"Cart"
],
"summary": "Clear cart",
"security": [
{
"bearerAuth": []
}
],
"parameters": [
{
"$ref": "#/components/parameters/businessId"
}
],
"responses": {
"200": {
"description": "{ message, cart }"
}
}
}
},
"/businesses/{businessId}/cart/items": {
"post": {
"tags": [
"Cart"
],
"summary": "Add variant to cart",
"security": [
{
"bearerAuth": []
}
],
"parameters": [
{
"$ref": "#/components/parameters/businessId"
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"storeItemVariantId"
],
"properties": {
"storeItemVariantId": {
"type": "string"
},
"quantity": {
"type": "integer",
"minimum": 1,
"default": 1
}
}
}
}
}
},
"responses": {
"201": {
"description": "{ message, cart }"
}
}
}
},
"/businesses/{businessId}/cart/items/{itemId}": {
"patch": {
"tags": [
"Cart"
],
"summary": "Update cart line quantity",
"security": [
{
"bearerAuth": []
}
],
"parameters": [
{
"$ref": "#/components/parameters/businessId"
},
{
"name": "itemId",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"quantity"
],
"properties": {
"quantity": {
"type": "integer",
"minimum": 1
}
}
}
}
}
},
"responses": {
"200": {
"description": "{ message, cart }"
}
}
},
"delete": {
"tags": [
"Cart"
],
"summary": "Remove cart line",
"security": [
{
"bearerAuth": []
}
],
"parameters": [
{
"$ref": "#/components/parameters/businessId"
},
{
"name": "itemId",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "{ message, cart }"
}
}
}
},
"/businesses/{businessId}/cart/checkout": {
"post": {
"tags": [
"Cart"
],
"summary": "Checkout → create order",
"security": [
{
"bearerAuth": []
}
],
"parameters": [
{
"$ref": "#/components/parameters/businessId"
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"payment"
],
"properties": {
"addressId": {
"type": "string"
},
"shippingAddress": {
"type": "object",
"properties": {
"province": {
"type": "string"
},
"city": {
"type": "string"
},
"address": {
"type": "string"
},
"postalCode": {
"type": "string"
},
"landline": {
"type": "string"
}
}
},
"customerNotes": {
"type": "string"
},
"payment": {
"type": "object",
"required": [
"type"
],
"properties": {
"type": {
"type": "string",
"enum": [
"pos",
"cash",
"transfer",
"e_payment_gate"
]
},
"posType": {
"type": "string"
},
"transferAccount": {
"type": "string"
},
"transferRefNumber": {
"type": "string"
},
"gatewayType": {
"type": "string",
"enum": [
"mellat",
"sep",
"snappay",
"digipay",
"zarinpal"
],
"description": "Required when type is e_payment_gate (defaults to store defaultGateway if omitted)."
},
"notes": {
"type": "string"
}
}
},
"returnUrl": {
"type": "string",
"format": "uri",
"description": "Required for e_payment_gate. Absolute URL the bank callback redirects the shopper to (status, orderId, transactionId query params appended)."
}
}
}
}
}
},
"responses": {
"201": {
"description": "Cash/transfer/pos: { message, order }. E-payment: { message, order, payment: { gatewayType, transactionId, redirect: { method, url, fields } } }"
}
}
}
},
"/businesses/{businessId}/orders": {
"get": {
"tags": [
"Orders"
],
"summary": "My orders",
"security": [
{
"bearerAuth": []
}
],
"parameters": [
{
"$ref": "#/components/parameters/businessId"
},
{
"name": "page",
"in": "query",
"schema": {
"type": "integer"
}
},
{
"name": "pageSize",
"in": "query",
"schema": {
"type": "integer",
"default": 20
}
},
{
"name": "status",
"in": "query",
"schema": {
"type": "string",
"enum": [
"pending",
"confirmed",
"processing",
"shipped",
"delivered",
"cancelled"
]
}
}
],
"responses": {
"200": {
"description": "{ items, total, page, pageSize }"
}
}
}
},
"/businesses/{businessId}/orders/{orderId}": {
"get": {
"tags": [
"Orders"
],
"summary": "My order detail",
"security": [
{
"bearerAuth": []
}
],
"parameters": [
{
"$ref": "#/components/parameters/businessId"
},
{
"name": "orderId",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "{ order }"
}
}
}
},
"/businesses/{businessId}/favorites": {
"get": {
"tags": [
"Favorites"
],
"summary": "List favorites",
"security": [
{
"bearerAuth": []
}
],
"parameters": [
{
"$ref": "#/components/parameters/businessId"
},
{
"name": "page",
"in": "query",
"schema": {
"type": "integer"
}
},
{
"name": "pageSize",
"in": "query",
"schema": {
"type": "integer",
"default": 20
}
}
],
"responses": {
"200": {
"description": "{ items, total, page, pageSize }"
}
}
},
"post": {
"tags": [
"Favorites"
],
"summary": "Add favorite",
"security": [
{
"bearerAuth": []
}
],
"parameters": [
{
"$ref": "#/components/parameters/businessId"
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"productId"
],
"properties": {
"productId": {
"type": "string"
}
}
}
}
}
},
"responses": {
"201": {
"description": "{ favorite, message }"
}
}
}
},
"/businesses/{businessId}/favorites/{productId}": {
"delete": {
"tags": [
"Favorites"
],
"summary": "Remove favorite",
"security": [
{
"bearerAuth": []
}
],
"parameters": [
{
"$ref": "#/components/parameters/businessId"
},
{
"name": "productId",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "{ message }"
}
}
}
},
"/public/sms/send": {
"post": {
"tags": [
"Partner SMS"
],
"summary": "Send SMS via Meshkee (partner gateway)",
"description": "Server-to-server only. For external/partner backends (e.g. Balout) that need to send SMS through Meshkee → Gama. Not for browser/storefront JS. Requires an allowlisted `domain` + matching `X-Api-Key`. See /docs/website/SMS.md.",
"security": [
{
"apiKeyAuth": []
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"domain",
"to",
"message"
],
"properties": {
"domain": {
"type": "string",
"example": "baloutpastry.com",
"description": "Allowlisted partner apex (www. is stripped)"
},
"to": {
"type": "string",
"example": "09127004945",
"description": "Iranian mobile: 09…, 9…, +989…, or 989…"
},
"message": {
"type": "string",
"maxLength": 700,
"example": "سفارش شما به شماره ی ۱۲۱۱۳۲۲ اماده می باشد."
}
}
}
}
}
},
"responses": {
"200": {
"description": "Accepted by Gama",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"success": {
"type": "boolean",
"example": true
},
"serverId": {
"type": "string",
"example": "1136923081051406337"
}
}
}
}
}
},
"400": {
"description": "Invalid phone or message"
},
"401": {
"description": "Missing/invalid X-Api-Key or domain"
},
"429": {
"description": "Rate limited (30/partner/min or 5/destination/min)"
},
"503": {
"description": "SMS disabled or provider unreachable"
}
}
}
},
"/tenants/{domain}/instructions": {
"get": {
"tags": [
"Instructions"
],
"summary": "List published instructions",
"parameters": [
{
"$ref": "#/components/parameters/domain"
},
{
"name": "page",
"in": "query",
"schema": {
"type": "integer"
}
},
{
"name": "pageSize",
"in": "query",
"schema": {
"type": "integer",
"default": 12
}
},
{
"name": "provider",
"in": "query",
"schema": {
"type": "string",
"enum": [
"youtube",
"aparat"
]
}
},
{
"name": "categoryId",
"in": "query",
"schema": {
"type": "string"
}
},
{
"name": "title",
"in": "query",
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "{ items, total, page, pageSize }"
}
}
}
},
"/tenants/{domain}/instructions/{slug}": {
"get": {
"tags": [
"Instructions"
],
"summary": "Instruction by slug",
"parameters": [
{
"$ref": "#/components/parameters/domain"
},
{
"name": "slug",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "{ instruction }"
}
}
}
},
"/tenants/{domain}/instructions/{instructionId}/comments": {
"get": {
"tags": [
"Instructions",
"Comments"
],
"summary": "Approved instruction comments",
"parameters": [
{
"$ref": "#/components/parameters/domain"
},
{
"name": "instructionId",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "{ items }"
}
}
},
"post": {
"tags": [
"Instructions",
"Comments"
],
"summary": "Submit instruction comment",
"parameters": [
{
"$ref": "#/components/parameters/domain"
},
{
"name": "instructionId",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"authorName",
"text"
],
"properties": {
"authorName": {
"type": "string"
},
"authorEmail": {
"type": "string"
},
"text": {
"type": "string"
}
}
}
}
}
},
"responses": {
"201": {
"description": "{ comment, message }"
}
}
}
},
"/tenants/{domain}/workshops": {
"get": {
"tags": ["Workshops"],
"summary": "List published workshops",
"parameters": [
{ "$ref": "#/components/parameters/domain" },
{ "name": "page", "in": "query", "schema": { "type": "integer" } },
{ "name": "pageSize", "in": "query", "schema": { "type": "integer", "default": 12 } },
{ "name": "categoryId", "in": "query", "schema": { "type": "string" } },
{ "name": "title", "in": "query", "schema": { "type": "string" } }
],
"responses": {
"200": { "description": "{ items, total, page, pageSize }" }
}
}
},
"/tenants/{domain}/workshops/{slug}": {
"get": {
"tags": ["Workshops"],
"summary": "Workshop by slug",
"parameters": [
{ "$ref": "#/components/parameters/domain" },
{ "name": "slug", "in": "path", "required": true, "schema": { "type": "string" } }
],
"responses": {
"200": { "description": "{ workshop } — includes eventDate, eventTime, duration" }
}
}
},
"/tenants/{domain}/workshops/{workshopId}/register": {
"post": {
"tags": ["Workshops"],
"summary": "Register logged-in website customer for a workshop",
"security": [{ "bearerAuth": [] }],
"parameters": [
{ "$ref": "#/components/parameters/domain" },
{ "name": "workshopId", "in": "path", "required": true, "schema": { "type": "string" } }
],
"responses": {
"201": { "description": "{ registration: { id, status: pending|approved|rejected, ... }, message }" },
"409": { "description": "Already registered" }
}
},
"delete": {
"tags": ["Workshops"],
"summary": "Cancel workshop registration",
"security": [{ "bearerAuth": [] }],
"parameters": [
{ "$ref": "#/components/parameters/domain" },
{ "name": "workshopId", "in": "path", "required": true, "schema": { "type": "string" } }
],
"responses": {
"200": { "description": "{ message }" }
}
}
},
"/businesses/{businessId}/payments/methods": {
"get": {
"tags": [
"Payments"
],
"summary": "List enabled online payment gateways (public)",
"parameters": [
{
"$ref": "#/components/parameters/businessId"
}
],
"responses": {
"200": {
"description": "{ enabled, defaultGateway, gateways: [{ id, label, labelFa }] } — no secrets"
}
}
}
},
"/businesses/{businessId}/payments/{gateway}/callback": {
"post": {
"tags": [
"Payments"
],
"summary": "Bank payment callback (public; redirects browser to returnUrl)",
"parameters": [
{
"$ref": "#/components/parameters/businessId"
},
{
"name": "gateway",
"in": "path",
"required": true,
"schema": {
"type": "string",
"enum": [
"mellat",
"sep",
"snappay",
"digipay",
"zarinpal"
]
}
}
],
"requestBody": {
"required": true,
"content": {
"application/x-www-form-urlencoded": {
"schema": {
"type": "object",
"additionalProperties": {
"type": "string"
},
"description": "Gateway-specific fields (Mellat: ResCode, SaleOrderId, SaleReferenceId, RefId, …)"
}
}
}
},
"responses": {
"303": {
"description": "Redirect to checkout returnUrl with status=success|failed"
}
}
},
"get": {
"tags": [
"Payments"
],
"summary": "Bank payment callback (GET variant)",
"parameters": [
{
"$ref": "#/components/parameters/businessId"
},
{
"name": "gateway",
"in": "path",
"required": true,
"schema": {
"type": "string",
"enum": [
"mellat",
"sep",
"snappay",
"digipay",
"zarinpal"
]
}
}
],
"responses": {
"303": {
"description": "Redirect to checkout returnUrl with status=success|failed"
}
}
}
}
}
}