API v1
საიტის დაკავშირება API-ით
თქვენს საიტზე გაფორმებული შეკვეთა ერთი მოთხოვნით ჩნდება Gayidvebi.ge-ს დაფაზე, სვეტში „საიტიდან“. როცა გამყიდველი შეკვეთას გადაიტანს, თქვენი საიტი webhook-ით გაიგებს ახალ სტატუსს. ასევე შეგიძლიათ წაიკითხოთ პროდუქტები და მარაგი.
- Base URL
https://www.gayidvebi.ge/api/v1- ფორმატი
- JSON, UTF-8
- OpenAPI
- /api/v1/openapi.json
სწრაფი დაწყება
- გამყიდველი ქმნის გასაღებს: პარამეტრები → ინტეგრაციები → საკუთარი საიტი (API).
- შეამოწმეთ გასაღები — პასუხი 200 ნიშნავს, რომ ყველაფერი რიგზეა და პარამეტრებში გამოჩნდება „დაკავშირებულია“:
curl https://www.gayidvebi.ge/api/v1/ping \
-H "Authorization: Bearer gyd_live_xxxxxxxxxxxx_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"- checkout-ის შემდეგ გამოგზავნეთ შეკვეთა:
<?php
// $orderId, $customer, $cart come from your checkout
$order = [
'id' => (string) $orderId,
'customer' => ['name' => $customer['name'], 'phone' => $customer['phone']],
'shipping' => ['city' => $customer['city'], 'address' => $customer['address'], 'fee' => 6],
'payment' => ['method' => 'cod', 'paid' => false],
'items' => array_map(fn ($line) => [
'product_id' => (string) $line['product_id'],
'name' => $line['name'],
'options' => $line['options'] ?? [], // ['ზომა' => 'L']
'quantity' => (int) $line['qty'],
'price' => (float) $line['unit_price'],
], $cart),
];
$ch = curl_init('https://www.gayidvebi.ge/api/v1/orders');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 15,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('GAYIDVEBI_API_KEY'),
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode($order, JSON_UNESCAPED_UNICODE),
]);
$response = json_decode((string) curl_exec($ch), true);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($status === 201 || $status === 200) {
// Saved (or it was already saved). $response['order']['crm_id']
} elseif ($status === 0 || !empty($response['retry'])) {
// No answer, 429 or 5xx: try again later with the same id — never saved twice
} else {
error_log('Gayidvebi refused the order: ' . json_encode($response));
}ავტორიზაცია
ყველა მოთხოვნას დაურთეთ ჰედერი Authorization: Bearer gyd_live_…. გასაღები ერთ საიტზეა მიბმული.
- ბრაუზერიდან (Origin ჰედერით) მოსული მოთხოვნა უარყოფილია — 403.
- გასაღები URL-ში (?key=…) — 400.
- ლიმიტი: წუთში 120 მოთხოვნა გასაღებზე. გადაჭარბებისას — 429 და Retry-After.
- ახალი გასაღების შექმნისას ძველი მაშინვე წყვეტს მუშაობას (401 key_revoked).
- გამოიყენეთ www: gayidvebi.ge (www-ის გარეშე) გადამისამართებს, და ზოგი HTTP კლიენტი POST-ს გადამისამართებისას არ აგზავნის.
შეკვეთის გამოგზავნა
POST/api/v1/orders
შეკვეთა ჩნდება სვეტში „საიტიდან“ — გამყიდველი ხმოვან შეტყობინებას იღებს და ადასტურებს. მარაგი ავტომატურად აკლდება.
| ველი | ტიპი | აღწერა |
|---|---|---|
| id* | string | თქვენი შეკვეთის ID (1–64 სიმბოლო: ასოები, ციფრები, . _ : -). ერთი და იგივე id ორჯერ არასდროს შეინახება. |
| number | string | შეკვეთის ნომერი, რომელსაც მყიდველი ხედავს (ნაგულისხმევად = id). |
| created_at | ISO 8601 | როდის გაფორმდა (ნაგულისხმევად — ახლა). |
| customer.name | string | სახელი და გვარი (ან customer.first_name + customer.last_name). |
| customer.phone* | string | ტელეფონი ნებისმიერ ფორმატში: +995 555 12 34 56, 555123456… |
| customer.email | string | კომენტარში ჩაიწერება, თუ გამყიდველმა ჩართო. |
| customer.personal_id | string | პირადი ნომერი (ზედნადებისთვის). |
| shipping.city / shipping.address | string | მიწოდების ქალაქი და მისამართი. |
| shipping.fee | number | მიტანის საფასური ლარში. |
| shipping.paid_by | "customer" | "shop" | ვინ უხდის კურიერს. თუ არ მიუთითებთ: ონლაინ გადახდისას — მაღაზია, ადგილზე — მყიდველი. |
| payment.method | string | გადახდის კოდი: cod / cash (ადგილზე), bank_transfer ან თქვენი ნებისმიერი კოდი — გამყიდველი პარამეტრებში მიაბამს მეთოდს. |
| payment.title / payment.paid | string / boolean | მეთოდის სახელი და გადახდილია თუ არა. |
| items[]* | array | 1–200 პროდუქტი. |
| items[].name* | string | პროდუქტის სახელი ვარიაციის გარეშე („მაისური“ და არა „მაისური - L“). ასე ემთხვევა CRM-ის პროდუქტს; თუ არ არსებობს, შეიქმნება. |
| items[].quantity* | integer | რაოდენობა (1-დან). |
| items[].price* | number | ერთეულის ფასი, რომელსაც მყიდველი იხდის. |
| items[].product_id / variant_id / sku | string | თქვენი ID-ები. პირველი შეკვეთის შემდეგ ვიმახსოვრებთ, რომელ CRM პროდუქტს შეესაბამება — სახელის შეცვლის შემდეგაც. |
| items[].options | object | ვარიაცია: {"ზომა": "L"}. ემთხვევა CRM-ის ვარიაციებს (დიდ/პატარა ასოებს არ აქვს მნიშვნელობა). |
| discount | number | შეკვეთის ფასდაკლება ლარში — პროპორციულად ნაწილდება პროდუქტებზე. |
| total | number | სულ თანხა. თუ არ ემთხვევა, გამყიდველი გაფრთხილებას ნახავს. |
| currency / note / admin_url | string | ვალუტა (GEL), მყიდველის კომენტარი, შეკვეთის ბმული თქვენს ადმინში. |
{
"id": "1001",
"number": "A-1001",
"created_at": "2026-10-15T13:30:00+04:00",
"customer": {
"name": "ნინო ბერიძე",
"phone": "+995 555 12 34 56",
"email": "nino@example.ge",
"personal_id": "01001012345"
},
"shipping": {
"city": "თბილისი",
"address": "ჭავჭავაძის გამზ. 12, ბინა 4",
"fee": 6,
"paid_by": "customer"
},
"payment": { "method": "cod", "title": "ადგილზე გადახდა", "paid": false },
"items": [
{
"product_id": "202",
"variant_id": "203",
"sku": "TS-L",
"name": "მაისური",
"options": { "ზომა": "L", "ფერი": "შავი" },
"quantity": 2,
"price": 35
}
],
"discount": 0,
"total": 76,
"currency": "GEL",
"note": "დარეკეთ მისვლამდე",
"admin_url": "https://shop.ge/admin/orders/1001"
}განმეორება უსაფრთხოა
თუ პასუხი არ მოვიდა, ან მოვიდა 429/5xx (retry: true), გაგზავნეთ იგივე შეკვეთა ხელახლა. ერთი და იგივე id მეორედ არ შეინახება — მიიღებთ 200-ს და result: "duplicate". სურვილისამებრ დაურთეთ Idempotency-Key ჰედერი (8–100 სიმბოლო).
შემოწმება შენახვის გარეშე
POST /api/v1/orders?dry_run=1 — ამოწმებს ყველა ველს და გიჩვენებთ, როგორ შეივსება შეკვეთა CRM-ში, მაგრამ არაფერს ინახავს. არასწორი ველები ბრუნდება ასე:
HTTP/1.1 422 Unprocessable Entity
{
"ok": false,
"error": "validation_failed",
"message": "Some fields are invalid. See `errors`.",
"field": "customer.phone",
"errors": [
{ "field": "customer.phone", "code": "required", "message": "customer.phone is required" },
{ "field": "items[0].quantity", "code": "invalid_value", "message": "items[0].quantity must be a whole number from 1 to 100000" }
],
"retry": false,
"server_time": 1760520601
}შეკვეთის სტატუსი
GET/api/v1/orders/{id}
{id} — თქვენი შეკვეთის id. აბრუნებს იმავე order ობიექტს, რაც შექმნისას. სტატუსის ცვლილებების მისაღებად უმჯობესია webhook-ები.
curl https://www.gayidvebi.ge/api/v1/orders/1001 \
-H "Authorization: Bearer gyd_live_xxxxxxxxxxxx_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"გაუქმება
POST/api/v1/orders/{id}/cancel
თუ შეკვეთა ჯერ კიდევ „საიტიდან“ სვეტშია — უქმდება და მარაგი ბრუნდება. თუ გამყიდველმა უკვე დაადასტურა — შეკვეთას ემატება შენიშვნა „⚠ საიტზე გაუქმდა“ და გადაწყვეტილებას გამყიდველი იღებს. პასუხში მიმდინარე სტატუსია.
curl -X POST https://www.gayidvebi.ge/api/v1/orders/1001/cancel \
-H "Authorization: Bearer gyd_live_xxxxxxxxxxxx_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{ "reason": "customer" }'პროდუქტები და მარაგი
GET/api/v1/products
გამყიდველის პროდუქტები: ფასი, ვარიაციები და ხელმისაწვდომი მარაგი (თვითღირებულება არასდროს). პარამეტრები: limit (1–200, ნაგულისხმევად 100), cursor (წინა პასუხის next_cursor), updated_since (ISO თარიღი — მხოლოდ შეცვლილები). პასუხი 60 წამით შეგიძლიათ დაიმახსოვროთ.
curl "https://www.gayidvebi.ge/api/v1/products?limit=100" \
-H "Authorization: Bearer gyd_live_xxxxxxxxxxxx_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"Webhook-ები
გამყიდველი პარამეტრებში უთითებს თქვენს https მისამართს და იღებს ხელმოწერის გასაღებს (whsec_…). ყოველ ჯერზე, როცა API-ით მიღებული შეკვეთის სტატუსი იცვლება, ამ მისამართზე მოდის POST მოთხოვნა. ფორმატი — Standard Webhooks (standardwebhooks.com): შეგიძლიათ გამოიყენოთ მათი ბიბლიოთეკები ან ქვემოთ მოცემული კოდი.
order.status_changed— სტატუსი შეიცვალა (დადასტურებაც).order.deleted— გამყიდველმა შეკვეთა წაშალა.test— ღილაკი „სატესტო შეტყობინება“ პარამეტრებში.
POST /your/webhook/url HTTP/1.1
Content-Type: application/json
webhook-id: msg_5b0c3a1e9d2f4c7b8a6e1d0c9b8a7f6e
webhook-timestamp: 1760520601
webhook-signature: v1,K5oZfzN95Z9UVu1EsfQmfVNQhnkZ2pj9o9NDN/H/pI4=
{
"type": "order.status_changed",
"timestamp": "2026-10-15T09:30:01.123Z",
"data": {
"id": "1001",
"number": "A-1001",
"crm_id": "5b0c…-…",
"status": { "id": "shipped", "label": "გაგზავნილი", "stage": "in_progress" },
"previous_status": { "id": "pending", "label": "ახალი", "stage": "new" },
"changed_at": "2026-10-15T09:30:01.123Z"
}
}| stage | მნიშვნელობა |
|---|---|
| received | მიღებულია, ელოდება გამყიდველის დადასტურებას („საიტიდან“). |
| new | დადასტურებულია, მუშავდება. |
| in_progress | გამყიდველის ნებისმიერი სხვა სვეტი (მაგ. „გაგზავნილი“). label-ში მისი სახელია. |
| completed | მიწოდებულია / დასრულებულია. |
| cancelled | გაუქმებულია (ან დაბრუნებულია). |
status.id და label გამყიდველის სვეტებია და შეიძლება შეიცვალოს — კოდში stage გამოიყენეთ.
ხელმოწერის შემოწმება
<?php
$secret = getenv('GAYIDVEBI_WEBHOOK_SECRET'); // whsec_...
$id = $_SERVER['HTTP_WEBHOOK_ID'] ?? '';
$ts = $_SERVER['HTTP_WEBHOOK_TIMESTAMP'] ?? '';
$header = $_SERVER['HTTP_WEBHOOK_SIGNATURE'] ?? '';
$body = file_get_contents('php://input'); // the raw body, not re-encoded
$key = base64_decode(substr($secret, strlen('whsec_')));
$expected = base64_encode(hash_hmac('sha256', "$id.$ts.$body", $key, true));
$valid = false;
foreach (explode(' ', $header) as $part) {
[$version, $signature] = array_pad(explode(',', $part, 2), 2, '');
if ($version === 'v1' && hash_equals($expected, $signature)) $valid = true;
}
if (!$valid || abs(time() - (int) $ts) > 300) {
http_response_code(401);
exit;
}
$event = json_decode($body, true);
// Retries reuse the same webhook-id: skip an id you already handled
if ($event['type'] === 'order.status_changed') {
$orderId = $event['data']['id']; // your order id
$stage = $event['data']['status']['stage']; // received|new|in_progress|completed|cancelled
// … update the order on your site
}
http_response_code(200);- უპასუხეთ 2xx-ით 10 წამში. სხვა პასუხზე ან დროის ამოწურვაზე ვცდით ხელახლა: 1 წთ, 5 წთ, 30 წთ, 2 სთ, 6 სთ, 12 სთ, 24 სთ.
- განმეორებისას webhook-id იგივეა — უკვე დამუშავებული id გამოტოვეთ.
- თანმიმდევრობა გარანტირებული არ არის: შეადარეთ data.changed_at და ძველი გამოტოვეთ, ან წაიკითხეთ GET /orders/{id}.
- გადამისამართებას (3xx) არ მივყვებით; მისამართი უნდა იყოს საჯარო https.
შეცდომები
შეცდომისას პასუხია {"ok": false, "error": "<code>", "message": "…", "retry": false}. retry: true ნიშნავს, რომ მოგვიანებით განმეორება დაგეხმარებათ.
| error | HTTP | retry | მნიშვნელობა |
|---|---|---|---|
| missing_api_key / invalid_api_key / unknown_key | 401 | false | გასაღები არ არის, არასწორია ან უცნობია. |
| key_revoked | 401 | false | გასაღები გაუქმდა ან შეიცვალა — ახალი შექმენით პარამეტრებში. |
| browser_requests_not_allowed | 403 | false | მოთხოვნა ბრაუზერიდან მოვიდა. გამოიძახეთ სერვერიდან. |
| plan_not_allowed | 403 | false | API ხელმისაწვდომია Pro პაკეტიდან. |
| key_in_url | 400 | false | გასაღები URL-შია. გადაიტანეთ Authorization ჰედერში. |
| invalid_json / invalid_idempotency_key / invalid_query / invalid_id | 400 | false | მოთხოვნა არასწორადაა აწყობილი. |
| validation_failed / invalid_phone | 422 | false | ველები არასწორია — იხ. field და errors. |
| order_not_found | 404 | false | ამ id-ით შეკვეთა თქვენი საიტიდან არ მიგვიღია. |
| payload_too_large | 413 | false | სხეული 256 KB-ზე დიდია. |
| rate_limited | 429 | true | წუთში 120-ზე მეტი მოთხოვნა. დაელოდეთ Retry-After წამს. |
| server_error / not_configured | 500 / 503 | true | ჩვენი მხრის შეცდომა — სცადეთ მოგვიანებით (იგივე id უსაფრთხოა). |
კითხვები? მოგვწერეთ