Files
backend/docs/website-api/index.html
T
Alireza HassaniandCursor 6517877bed Use id+slug paths for user products and count their visits.
Align storefront/sitemap URLs with catalog products, add by-id public APIs, and include user-product detail views in the product visit chart.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 15:35:46 +03:30

199 lines
8.3 KiB
HTML
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.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Meshkee Website API</title>
<style>
:root {
--bg: #0f1419;
--panel: #1a222c;
--text: #e8eef4;
--muted: #9aa8b5;
--accent: #3d9cf0;
--line: #2a3542;
}
* { box-sizing: border-box; }
body {
margin: 0;
font-family: "IBM Plex Sans", "Segoe UI", sans-serif;
background: radial-gradient(1200px 600px at 10% -10%, #1b3a57 0%, var(--bg) 55%);
color: var(--text);
line-height: 1.55;
}
main {
max-width: 760px;
margin: 0 auto;
padding: 3rem 1.25rem 4rem;
}
h1 { font-size: 2rem; margin: 0 0 0.5rem; letter-spacing: -0.02em; }
h2 { font-size: 1.15rem; margin: 2rem 0 0.75rem; }
p, li { color: var(--muted); }
strong { color: var(--text); }
code {
font-family: "IBM Plex Mono", ui-monospace, monospace;
background: #0b1015;
padding: 0.1rem 0.35rem;
border-radius: 4px;
color: #cde3f7;
font-size: 0.92em;
}
.panel {
background: var(--panel);
border: 1px solid var(--line);
border-radius: 12px;
padding: 1rem 1.1rem;
margin: 1rem 0;
}
a.btn {
display: inline-block;
margin: 0.35rem 0.5rem 0.35rem 0;
padding: 0.65rem 1rem;
border-radius: 8px;
background: var(--accent);
color: #061018;
text-decoration: none;
font-weight: 600;
}
a.btn.secondary {
background: transparent;
color: var(--text);
border: 1px solid var(--line);
}
.eyebrow { color: var(--accent); font-size: 0.85rem; font-weight: 600; letter-spacing: 0.04em; text-transform: uppercase; }
</style>
</head>
<body>
<main>
<div class="eyebrow">Meshkee · Global storefront contract</div>
<h1>Website API</h1>
<p>
One API for <strong>every</strong> Meshkee business website. Not tied to a single domain.
Set your site’s apex host (e.g. <code>sanihome.ir</code>) and reuse the same endpoints.
</p>
<div class="panel">
<p style="margin:0 0 0.75rem"><strong>Global links</strong> (share these with designers &amp; AI tools):</p>
<a class="btn" href="/docs/website/openapi.json">OpenAPI JSON</a>
<a class="btn secondary" href="/docs/website/Meshkee-Website-API.postman_collection.json">Download Postman</a>
<a class="btn secondary" href="/docs/website/AI_PROMPT.md">AI prompt</a>
<a class="btn secondary" href="/docs/website/SMS.md">Partner SMS</a>
</div>
<h2>Base URL</h2>
<p><code>https://api.meshkee.com/api/v1</code></p>
<p>Optional per-site alias (same backend): <code>https://api.&lt;domain&gt;/api/v1</code></p>
<h2>How tenants work</h2>
<ol>
<li>Variable <code>domain</code> = website apex only (no <code>www</code>/<code>api</code>/<code>customer</code>/<code>business</code>).</li>
<li><code>GET /tenants/{domain}</code> → <code>businessId</code>.</li>
<li>Public pages: <code>/tenants/{domain}/...</code> (no auth) — products, <strong>user-products</strong>, blogs, portfolios, store-items, etc.</li>
<li>Favorites (optional, if cookies exist): <code>/businesses/{businessId}/...</code> + Bearer JWT.</li>
<li>Login, checkout, server cart, orders: <strong>customer dashboard</strong> at <code>https://customer.{domain}</code> — not pages on the shop.</li>
</ol>
<h2>Shared login with customer dashboard</h2>
<p>
Do <strong>not</strong> build a login / register / OTP page on the storefront.
Send shoppers to <code>https://customer.{domain}/login</code>.
The customer dashboard writes parent-domain cookies; the shop only
<strong>reads</strong> them to detect an existing session:
</p>
<ul>
<li><code>meshkee_customer_access_token</code></li>
<li><code>meshkee_customer_refresh_token</code></li>
</ul>
<p>
Set <code>Domain=.{domain}</code>, <code>Path=/</code>, <code>SameSite=Lax</code>.
API auth is still <code>Authorization: Bearer &lt;accessToken&gt;</code> (cookies are not sent to the API).
Do not use <code>/auth/handoff</code> for shoppers (staff-only into the business dashboard).
Full detail: <a href="/docs/website/AI_PROMPT.md">AI_PROMPT.md</a>.
</p>
<h2>Shopping cart on the storefront</h2>
<p>
The shop implements a <strong>mini-cart only</strong>: header icon, quantity badge,
popup, Continue. Persist a guest cart as <code>meshkee-guest-cart</code>
(localStorage + parent-domain cookie). Each line <code>id</code> is
<code>storeItemVariantId</code>.
Add-to-cart: <code>GET /tenants/{domain}/store-items/by-product/{productId}</code>,
list variants if there is more than one, then add the chosen variant
(same id already in cart → increment quantity). Continue goes to the customer dashboard:
</p>
<ul>
<li>Logged in → <code>https://customer.{domain}/checkout/cart?guestCart=…</code></li>
<li>Not logged in → <code>https://customer.{domain}/login?redirect=/checkout/cart?guestCart=…</code></li>
</ul>
<p>
Do not call <code>/cart</code> or <code>/cart/checkout</code> from the website,
and do not add shop <code>/login</code> or <code>/checkout</code> routes.
Encoding and payload: <a href="/docs/website/AI_PROMPT.md">AI_PROMPT.md</a> (Shopping cart).
</p>
<h2>Branding (favicon + logos)</h2>
<p>
<code>GET /tenants/{domain}/website/favicon</code> returns
<code>faviconUrl</code>, <code>logoUrl</code>, <code>logoDarkUrl</code>, and
<code>hasDedicatedFavicon</code>. Use <code>faviconUrl</code> for the browser tab icon
(Next.js <code>metadata.icons</code>). When no dedicated favicon is uploaded,
<code>faviconUrl</code> falls back to <code>logoUrl</code>.
</p>
<h2>User products (customer listings)</h2>
<p>
Marketplace-style stock listings created by customers. Public read-only under
<code>/tenants/{domain}/user-products</code> (list / by-id / details / technical-info).
Storefront URLs: <code>/user-products/{id}/{pathSlug}</code>.
See OpenAPI tag <strong>User Products</strong>.
</p>
<p>
<strong>Technical details:</strong> detail responses include
<code>technicalValues</code> with <em>values only</em> (no field labels).
For a label→value specs table, call
<code>GET /tenants/{domain}/user-products/by-id/{id}/technical-info</code>
(catalog products:
<code>.../products/by-id/{id}/technical-info</code>) and join
<code>form.fields[].id</code> ↔ <code>values[].fieldId</code>.
There is no public <code>product-category-variation-fields</code> route.
</p>
<h2>Torob (price comparison)</h2>
<p>
<code>POST /tenants/{domain}/torob_api/v3/products</code> is for
<strong>Torob</strong>, not storefront JavaScript. On the live shop,
nginx proxies <code>POST https://{domain}/torob_api/v3/products</code>
to that API. It only returns catalog store items when the business has
the <strong>store</strong> module enabled <em>and</em> Store settings →
Torob is on; otherwise 404.
Do not implement this path in Next.js.
</p>
<h2>For a new website AI / designer</h2>
<ol>
<li>Open <a href="/docs/website/AI_PROMPT.md">AI_PROMPT.md</a> and paste it into the AI chat.</li>
<li>Replace <code>&lt;WEBSITE_DOMAIN&gt;</code> with that site’s apex.</li>
<li>Import the Postman collection (set <code>domain</code>, run Resolve tenant).</li>
<li>Or feed <code>openapi.json</code> to the AI / codegen tool.</li>
</ol>
<h2>Import Postman</h2>
<p>
Postman → Import → Link → paste<br />
<code>https://api.meshkee.com/docs/website/Meshkee-Website-API.postman_collection.json</code>
</p>
<h2>Partner SMS gateway</h2>
<p>
External backends (e.g. Balout) can send transactional SMS through Meshkee → Gama.
Server-to-server only — API key per allowlisted domain. See
<a href="/docs/website/SMS.md">SMS.md</a>.
</p>
<div class="panel">
<p style="margin:0"><code>POST /api/v1/public/sms/send</code></p>
<p style="margin:0.5rem 0 0">Header <code>X-Api-Key</code> + body <code>{ domain, to, message }</code></p>
</div>
</main>
</body>
</html>