დიზაინერებისა და მათი დეველოპერებისთვის
3Moss-ის API
3Moss-ზე ყველა დიზაინერს საკუთარი API აქვს. გამოიყენე ის, რომ შენი პროდუქტები საკუთარ ვებსაიტზე გაყიდო, ან მიეცი გასაღები სხვა ვებსაიტს, რომელსაც მათი გაყიდვა სურს, და შეკვეთები 3Moss-ს დაუბრუნე: 3Moss თითოეულს დაბეჭდავს და გააგზავნის. გასაღებები შენს ანგარიშში შექმენი, API-ის გვერდზე.
ავთენტიფიკაცია
გასაღები Authorization ჰედერში გაგზავნე, შენი სერვერიდან. ვისაც შენი გასაღები აქვს, შენს პროდუქტებს წაიკითხავს, ამიტომ არასოდეს ჩასვა ის გვერდის JavaScript-ში ან საჯარო რეპოზიტორიაში. თითო ვებსაიტს ცალკე გასაღები შეუქმენი, რომ ერთის გაუქმებამ დანარჩენები არ გააფუჭოს; შეიძლება გქონდეს 10-მდე.
Authorization: Bearer 3m_live_…შენი პროდუქტების სია
GET http://localhost:3000/api/v1/productslimit- 1–100, ნაგულისხმევად 50.
store- მხოლოდ ერთი მაღაზიის პროდუქტები — id
/api/v1/stores-დან. tag- მხოლოდ ამ თეგის მქონე პროდუქტები. გაიმეორე ან მძიმით გამოყავი, თუ გინდა პროდუქტები, რომლებსაც ყველა ეს თეგი აქვს — თეგების გვერდებისთვის.
q- ძიება: ემთხვევა სათაურს, აღწერას, SEO სათაურს და თეგებს, ქართულად ან ინგლისურად. 100 სიმბოლომდე.
updated_since- დრო ISO 8601 ფორმატში, სინქრონიზაციისთვის.
cursornext_cursorწინა გვერდიდან.
updated_since-ის გარეშე მიიღებ იმას, რაც ახლა იყიდება. მასთან ერთად — ყველა პროდუქტს, რომელიც მას შემდეგ შეიცვალა, იყიდება თუ არა; დამალე ისინი, რომლებსაც აქვთ "available": false. გვერდზე შეიძლება limit-ზე ნაკლები პროდუქტი იყოს; მიჰყევი next_cursor-ს, სანამ ის null არ გახდება. წაშლილი პროდუქტები ამ სიაში არ არის — ისინი /products/deleted-ს ჰკითხე. პროდუქტი შეცვლილად ითვლება, როცა იცვლება ნებისმიერი რამ, რაც მასზე ჩანს — მომწოდებლის მარაგის, ფასების, მიწოდებისა და მისი მაღაზიის სახელის ჩათვლით — და როდის, ამას მისი updated_at გეტყვის.
curl "http://localhost:3000/api/v1/products?limit=20" \
-H "Authorization: Bearer $THREEMOSS_KEY"ერთი პროდუქტი
GET http://localhost:3000/api/v1/products/{id}
GET http://localhost:3000/api/v1/products/{handle}პროდუქტს აბრუნებს მაშინაც, როცა ის არ იყიდება, რომ მარაგში არარსებულად აჩვენო. გამოიყენე id ან handle — ასე /products/owl-moon გვერდს შეუძლია პირდაპირ owl-moon მოითხოვოს. თუ ერთი სტრიქონი ერთდროულად id-იც არის და handle-იც, id-ს აქვს უპირატესობა.
წაშლილი პროდუქტები
GET http://localhost:3000/api/v1/products/deleted?since=2026-10-09T21:14:03Zყველა პროდუქტი, რომელიც since-ის შემდეგ წაშალე, ჯერ უახლესი, იგივე store, limit და cursor პარამეტრებით, რაც პროდუქტების სიას აქვს. თითოეული შენი საიტიდან მოხსენი. since-ად ბოლო სინქრონიზაციის დრო გამოიყენე — იგივე, რასაც updated_since-ად აგზავნი. წაშლები 90 დღე ინახება; თუ შენი საიტი ამაზე დიდხანს არ სინქრონიზებულა, სრული სინქრონიზაცია გაუშვი.
{
"deleted": [
{
"id": "p_7Hk2…",
"store_id": "ecc0…",
"handle": "owl-moon",
"deleted_at": "2026-10-10T08:02:51.000Z"
}
],
"next_cursor": null
}/products/{id}-ზე ამ 90 დღეში წაშლილი პროდუქტის მოთხოვნა 404-ის ნაცვლად 410-ს აბრუნებს, მისი deleted_at-ით.
შენი მაღაზიები
GET http://localhost:3000/api/v1/storesროგორ გამოიყურება პროდუქტი
{
"id": "p_7Hk2…",
"store": {
"id": "ecc0…",
"name": "Night Owl Co."
},
"title": "Owl moon",
"description": "…",
"available": true,
"garment": {
"name": "Unisex Heavy Cotton Tee",
"brand": "Gildan 5000",
"category": "T-shirts"
},
"price": {
"amount": "59.94",
"currency": "GEL"
},
"shipping": {
"first": "12.34",
"additional": "6.24",
"currency": "GEL"
},
"variants": [
{
"color": {
"id": "white",
"name": "White",
"hex": "#f7f7f5"
},
"size": "M",
"available": true
}
],
"handle": "owl-moon",
"images": [
{
"url": "http://localhost:3000/api/images/…?t=…",
"view": "front",
"alt": "Owl moon — front"
}
],
"tags": [
"owl",
"night sky"
],
"seo": {
"title": "Owl moon tee, hand-drawn night sky",
"description": "…",
"image": "http://localhost:3000/api/images/…?t=…",
"json_ld": {
"@context": "https://schema.org",
"@type": "Product",
"name": "Owl moon",
"offers": {
"…": "…"
}
}
},
"attributes": {
"style": "vintage"
},
"updated_at": "2026-10-09T21:14:03.000Z"
}- ფასები სტრიქონებია
currency-სთან ერთად, რომ მცურავი წერტილის გამო არაფერი დაიკარგოს. ყველა ფასი ქართულ ლარშია (GEL). priceშენი ფასია. საკუთარ ვებსაიტზე შეგიძლია მეტი მოითხოვო.- სურათების ბმულები ოცდაათ დღეს მოქმედებს და ყოველ მოთხოვნაზე თავიდან ხელმოიწერება. სურათები ჩამოტვირთე და ბმულით ნუ მიუთითებ.
საძიებო სისტემები
ყველა პროდუქტი პროდუქტის გვერდის <head>-ისთვის მზადაა. handle ბმულის წასაკითხი სახელია, ქართული სათაურებით ლათინურ ასოებში (ღამის ბუ → ghamis-bu), უნიკალური შენს პროდუქტებს შორის. ის სათაურს მიჰყვება, სანამ დიზაინერი თავად არ დააყენებს, ამიტომ შეინახე id და handle მისამართად ჩათვალე: როცა შეიცვლება, ძველი ახალზე გადაამისამართე. seo.title და seo.description არასოდეს არის ცარიელი და უკვე ეტევა იმაში, რასაც ძიების შედეგი აჩვენებს. seo.json_ld არის schema.org-ის Product ფასითა და ხელმისაწვდომობით, გაფართოებული შედეგებისთვის; მის offers-ში შენი გვერდის url დაამატე. ყველა სურათს აქვს alt ტექსტი.
<title>{product.seo.title}</title>
<meta name="description" content="{product.seo.description}">
<meta property="og:title" content="{product.seo.title}">
<meta property="og:image" content="{your copy of product.seo.image}">
<link rel="canonical" href="https://your-site.ge/products/{product.handle}">
<script type="application/ld+json">{JSON.stringify(product.seo.json_ld)}</script>სურათების ბმულებს ვადა გასდის, ამიტომ საკუთარი ასლები გამოიყენე — og:image-შიც და JSON-LD-ის image-შიც.
შეკვეთის გაგზავნა
POST http://localhost:3000/api/v1/ordersროცა შენი ვებსაიტი შენს რომელიმე პროდუქტს გაყიდის, შეკვეთა აქ გამოგზავნე და 3Moss მას დაბეჭდავს და შენს მყიდველს მიაწვდის. მყიდველი შენ გიხდის; 3Moss შენგან ბეჭდვისა და მიწოდების საფასურს იღებს. თუ იმ მაღაზიის ბალანსი, რომელშიც პროდუქტებია, ამას ფარავს, შეკვეთა მაშინვე მისით გადაიხდება და ბეჭდვაზე მიდის (status received). თუ არა, ის awaiting_payment სტატუსით ელოდება, სანამ შენს ანგარიშში არ გადაიხდი, და უქმდება, თუ 7 დღის შემდეგაც გადაუხდელია. ორივე შემთხვევაში შეტყობინებას მიიღებ.
{
"external_id": "my-site-1042",
"customer": {
"name": "ნინო ბერიძე",
"phone": "+995 555 12 34 56",
"email": "nino@example.com"
},
"address": {
"line1": "რუსთაველის გამზ. 34, ბ. 5",
"city": "თბილისი"
},
"items": [
{
"product_id": "p_7Hk2…",
"color": "white",
"size": "M",
"quantity": 2
}
],
"paid": {
"amount": "139.88",
"currency": "GEL"
}
}external_idშენივე შეკვეთის id-ია. იმავეს ხელახლა გაგზავნა უსაფრთხოა: იმავე შეკვეთას დაგიბრუნებსcreated: false-ით და201-ის ნაცვლად200სტატუსით — ასე რომ, ტაიმაუტის შემდეგ თამამად სცადე ხელახლა.- გამოიყენე პროდუქტის
id,variants[].color.idდაsizeპროდუქტების API-დან. ერთ შეკვეთაში ყველაფერი შენი ერთი მაღაზიიდან უნდა იყოს; თითო მაღაზიაზე ცალკე შეკვეთა გაგზავნე. - მთელი შეკვეთა
422-ით უარყოფილია, თუ მასში რამე ახლა ვერ იყიდება — პროდუქტი შეჩერებულია, ფერი ან ზომა ამოიწურა — ამიტომ ჯერ ხელმისაწვდომობა შეამოწმე და, თუ ასე მოხდა, შეტყობინება აჩვენე. - 3Moss საქართველოში აწვდის: ტელეფონი და ქალაქი სავალდებულოა, ხოლო
address.country, თუ გაგზავნი,GEუნდა იყოს.customer.emailდაpaidარასავალდებულოა;paidარის ის, რაც მყიდველმა შენ გადაგიხადა, შენივე ჩანაწერებისთვის.
{
"order": {
"id": "QWPEZW9V",
"external_id": "my-site-1042",
"status": "received",
"tracking": null,
"items": [
{
"product_id": "p_7Hk2…",
"title": "Owl moon",
"color": "white",
"size": "M",
"quantity": 2
}
],
"paid": {
"amount": "139.88",
"currency": "GEL"
},
"timeline": [
{
"status": "awaiting_payment",
"at": "2026-10-19T09:12:40.000Z"
},
{
"status": "received",
"at": "2026-10-19T09:12:40.000Z"
}
],
"created_at": "2026-10-19T09:12:40.000Z",
"updated_at": "2026-10-19T09:12:40.000Z"
},
"created": true
}შენი შეკვეთები
GET http://localhost:3000/api/v1/orders/{id}
GET http://localhost:3000/api/v1/orders/{external_id}
GET http://localhost:3000/api/v1/orders?updated_since=2026-10-19T09:00:00Zერთი შეკვეთა, 3Moss-ის id-ით ან შენი external_id-ით; ან ყველა შეკვეთა, რომელიც შენმა ვებსაიტებმა გამოგზავნეს, ჯერ ყველაზე ძველი ცვლილება, იგივე limit-ითა და cursor-ით, რაც პროდუქტების სიას აქვს. updated_since-ით პერიოდულად ჰკითხე, რომ მყიდველებს უთხრა, როდის გაიგზავნა მათი შეკვეთა: მაშინ tracking შეივსება. სტატუსებია awaiting_payment, received, in_production, shipped, delivered და cancelled. სიაში მხოლოდ API-ით გამოგზავნილი შეკვეთებია, შენი ნებისმიერი გასაღებიდან.
ვებჰუკები
პერიოდული კითხვის ნაცვლად, API-ის გვერდზე გასაღებს ვებჰუკის მისამართი მიეცი (https:// URL შენს სერვერზე). ცვლილებიდან დაახლოებით ერთ წუთში 3Moss მას POST-ს გაუგზავნის:
order.updated— შეკვეთამ, რომელიც ამ გასაღებმა გამოგზავნა, სტატუსი შეიცვალა ან თრექინგის ნომერი მიიღო.product.updated— შეიცვალა რამე, რასაც პროდუქტის გვერდი აჩვენებს: სათაური, ფასი, ფოტოები, ფერები, ზომები.product.unavailable— მისი ყიდვა აღარ შეიძლება: შეჩერებულია, ყველა ფერსა და ზომაში ამოიწურა, მოხსნილია ან წაშლილია.
შეკვეთები მხოლოდ იმ გასაღებს მიდის, რომელმაც ისინი გამოგზავნა; პროდუქტები — შენს ყველა გასაღებს. სხეული მთელ ობიექტს შეიცავს, ზუსტად ისე, როგორც მას GET /orders/{id} ან GET /products/{id} აბრუნებს, ამიტომ მეორე მოთხოვნა არ გჭირდება:
{
"id": "evt_8fK2mQ…",
"type": "order.updated",
"created_at": "2026-10-20T09:14:03.000Z",
"data": {
"order": { "id": "QWPEZW9V", "external_id": "1042", "status": "shipped", "tracking": "GE123…", … }
}
}წაშლილ პროდუქტს საჩვენებელი აღარაფერი აქვს, ამიტომ მხოლოდ ამას შეიცავს:
{
"type": "product.unavailable",
"data": { "product": { "id": "p_7Hk2…", "store_id": "ecc0…", "handle": "owl-moon", "deleted": true } }
}ყველა მოთხოვნას აქვს X-3Moss-Event (ტიპი), X-3Moss-Delivery (მოვლენის id, ყოველ ხელახალ ცდაზე ერთი და იგივე, რომ გამეორება უგულებელყო) და X-3Moss-Signature. სანამ სხეულს ენდობი, ხელმოწერა შეამოწმე: ეს არის HMAC-SHA256, შექმნილი გასაღების ხელმოწერის საიდუმლოთი (whsec_…, ჩანს ერთხელ, როცა მისამართს შეინახავ), დროისა და დაუმუშავებელი სხეულისგან. უარყავი ყველაფერი, რაც ხუთ წუთზე ძველია, რომ მოგვიანებით გამეორებულმა ძველმა მოთხოვნამ ვერაფერი გააკეთოს:
import { createHmac, timingSafeEqual } from "node:crypto";
// rawBody: the request body exactly as received, before JSON.parse.
function from3Moss(rawBody, header, secret) {
const parts = Object.fromEntries(header.split(",").map((part) => part.split("=")));
const t = Number(parts.t);
if (!t || Math.abs(Date.now() / 1000 - t) > 300) return false;
const expected = createHmac("sha256", secret).update(`${t}.${rawBody}`).digest("hex");
const given = Buffer.from(parts.v1 ?? "", "hex");
return given.length === 32 && timingSafeEqual(given, Buffer.from(expected, "hex"));
}სწრაფად უპასუხე ნებისმიერი 2xx-ით, საქმე კი მერე გააკეთე; 3Moss ათ წამს ელოდება. გადამისამართებას არ მიჰყვება. ნებისმიერ სხვა პასუხზე ხელახლა ცდის 1, 5 და 30 წუთის შემდეგ, მერე ყოველ საათში. იგზავნება მხოლოდ ობიექტის ბოლო მდგომარეობა: თუ შეკვეთა ორჯერ შეიცვლება, სანამ პირველს მიიღებ, მეორეს მიიღებ. ერთი დღის წარუმატებელი ცდების შემდეგ მისამართი ითიშება და შეგატყობინებთ; ჩართე ის API-ის გვერდიდან და updated_since-ით დაეწიე გამოტოვებულს. იქვე „Send a test“ აგზავნის ping მოვლენას ცარიელი data-ით, ხელმოწერილს ისევე, როგორც დანარჩენები.
შენი სერვერიდან
Node 22 ან უფრო ახალი:
const res = await fetch("http://localhost:3000/api/v1/products", {
headers: { Authorization: `Bearer ${process.env.THREEMOSS_KEY}` },
});
if (!res.ok) throw new Error((await res.json()).error.message);
const { products, next_cursor } = await res.json();ლიმიტები და შეცდომები
60 მოთხოვნა წუთში და 1000 საათში, თითო გასაღებზე. ამის მერე მიიღებ 429-ს Retry-After ჰედერით, წამებში. ყველა შეცდომა ერთნაირად გამოიყურება:
{ "error": { "code": "not_found", "message": "No such product." } }| 400 | bad_request | query პარამეტრი ისეთი არ არის, რომელსაც API იღებს. შეტყობინება მას ასახელებს. |
| 401 | unauthorized | გასაღები არ არის, არასწორია ან გაუქმებულია. |
| 404 | not_found | ასეთი პროდუქტი ან შეკვეთა შენსას შორის არ არის. |
| 410 | gone | შენი ეს პროდუქტი წაიშალა. სხეულში deleted_at-იც არის. |
| 422 | invalid_order | შეკვეთის მიღება ასე გაგზავნილი სახით შეუძლებელია: შეტყობინება გეტყვის, რომელი ნივთი ან ველი და რატომ. არაფერი შექმნილა. |
| 429 | rate_limited | ზედმეტად ბევრი მოთხოვნა. დაელოდე Retry-After-ში მითითებულ წამებს. |
| 500 | internal | ჩვენს მხარეს რაღაც შეცდომა მოხდა. სცადე ხელახლა. |