P Perkly SaaS API Документация

Спецификация на Perkly API

Тази документация описва криптографския протокол и наличните адреси (API endpoints) за интеграция с мултитенантната SaaS система Perkly. Всички заявки към API сървъра се насочват към базов адрес: `http://localhost:3000/api/v1` (или вашия домейн) и изискват валиден криптографски подпис в хедърите.

📖 Ръководство за употреба на платформата

Как да стартирате и управлявате програмата за лоялност Perkly стъпка по стъпка.

1 Създаване на Група и Магазин (Tenant)

Влезте в административния панел на адрес /admin с вашите данни. Първо създайте Група (ако имате партньорски сайтове, които ще споделят точки), и след това добавете Магазин (Tenant) вътре в нея. Платформата автоматично ще ви генерира публичен API Key и таен API Secret Key.

2 Инсталиране на плъгина в WooCommerce

Качете архива на плъгина perkly.zip във вашия WordPress сайт през меню Разширения (Plugins) и го активирайте. Отидете в главното меню на WordPress -> Perkly SaaS Settings и въведете адреса на вашия API сървър и двата ключа. Задайте курс на печелене (Earn Rate) и курс на харчене (Spend Rate).

3 Настройка на продукти

При редактиране на продукт в WooCommerce ще видите новия панел Perkly SaaS Options. Оттук можете:

  • Да направите продукта "Само с точки" (Points Only) и да зададете неговата цена в точки.
  • Да го маркирате като VIP Абонамент (Subscription) и да зададете брой дни (например 30 дни). При покупка клиентът автоматично получава ролята Club Member.

4 Управление на транзакции и Ledger

Когато клиентите правят поръчки, Perkly автоматично резервира точки от техния акаунт в реално време. При завършване (или плащане) на поръчката, транзакцията се маркира като потвърдена (Confirmed) и се записва постоянно в Ledger-а. Всичко става автоматично и без риск от дублиране на баланси.

5 Одобряване на фактури (Invoice Claims)

Клиентите могат да качват фактури за покупки, извършени извън сайта, през своя WordPress профил ("Лоялна програма"). Вие ще виждате тези заявки директно в менюто WooCommerce -> Invoice Claims. Имате опция да ги прегледате, одобрите (при което точките се начисляват автоматично) или отхвърлите с посочване на причина.

6 Периодична ротация на тайни (Rotate Secret)

За максимална сигурност, можете периодично да натискате бутона Rotate Secret в SaaS контролния панел. Това генерира нов секретен ключ, но позволява на стария да работи в рамките на 24 часа. Това дава време да обновите настройките в WooCommerce сайтовете си без прекъсване на покупките.

🔐 Криптографска защита (HMAC-SHA256)

Всички заявки към API-то се подписват на базата на таен споделен ключ (`API Secret`).

Всяка заявка задължително изисква изпращането на следните HTTP хедъри:

  • `x-api-key`: Вашият публичен API ключ, издаден от SaaS портала.
  • `x-timestamp`: Текущото UNIX време в секунди (за предпазване от Replay атаки – заявки с разлика над 5 минути се отхвърлят).
  • `x-signature`: HMAC-SHA256 подписът, генериран по формулата по-долу.

Формула за генериране на подпис:

Signature = HMAC_SHA256( API_Secret, Method + Path + Timestamp + JSON_Body )

Забележка: При заявки без тяло (напр. GET заявки), `JSON_Body` е празен низ `""`.

Кодови примери за подписване:

PHP (WooCommerce)
$timestamp = time();
$body = json_encode($data, JSON_UNESCAPED_SLASHES);
$string_to_sign = "POST" . "/api/v1/transactions/reserve" . $timestamp . $body;
$signature = hash_hmac('sha256', $string_to_sign, $api_secret);
Node.js
const timestamp = Math.floor(Date.now() / 1000).toString();
const stringToSign = 'POST' + '/api/v1/transactions/reserve' + timestamp + JSON.stringify(body);
const signature = crypto.createHmac('sha256', apiSecret).update(stringToSign).digest('hex');

🔌 Верификация на връзката

Проверка на комуникацията на магазина с API сървъра и получаване на GitHub токен.

GET /verify Проверка на връзката

Използва се от WooCommerce клиента за проверка на валидността на `API Key` и `API Secret`. Връща данни за тенанта и частния GitHub токен за автоматични обновления на плъгина.

Успешен отговор (200 OK):
{
  "success": true,
  "tenant": {
    "id": "e30c4e12-32a8-444a-9b1c-99d88a77b66c",
    "name": "Моят WooCommerce Магазин",
    "group_id": "b10b4f8c-23a9-450f-90e9-aa88bb77cc66",
    "site_url": "https://website.com"
  },
  "update_token": "ghp_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
}

👥 Клиенти и Баланси

GET /customers/:email/balance Баланс и VIP статус

Връща наличния баланс на клиента в групата на магазина, както и информация за текущия му VIP абонамент. Ако имейлът не съществува в системата, връща баланс 0 и статус `inactive` без грешка.

Параметри на пътя (Path Params):
  • `email`: Имейл адрес на клиента (напр. `customer@email.com`).
Успешен отговор (200 OK):
{
  "balance": 850,
  "subscription_status": "active",
  "subscription_expires_at": "2026-07-12",
  "subscription_created_at": "2026-06-12"
}
GET /customers/:email/transactions История на транзакциите

Връща хронологичен списък с транзакциите с точки на даден клиент. Поддържа странициране чрез query параметри.

Параметри на пътя (Path Params):
  • `email`: Имейл адрес на клиента.
Параметри на заявката (Query Params):
  • `page` (опционален): Номер на страницата (напр. `1`).
  • `limit` (опционален): Максимален брой резултати на страница (напр. `10`).
Успешен отговор (200 OK):
{
  "transactions": [
    {
      "id": "7a8b9c10-d1e2-3f4a-5b6c-7d8e9f0a1b2c",
      "amount": 120,
      "type": "Earn",
      "status": "Completed",
      "idempotency_key": "order_10023",
      "created_at": "2026-06-12T15:30:00.000Z"
    },
    {
      "id": "8c3b7a5e-14ef-4b2a-89a1-7788aa99bbcc",
      "amount": -150,
      "type": "Redeem",
      "status": "Completed",
      "idempotency_key": "order_10022",
      "created_at": "2026-06-11T12:00:00.000Z"
    }
  ],
  "total": 2,
  "page": 1,
  "limit": 10,
  "pages": 1
}

💸 Сделки и Управление на Точки (Transactions)

POST /transactions/reserve Резервиране на точки

Резервира точки от баланса на клиента. Използва се при завършване на поръчка. `amount` е отрицателно число. Изисква активен абонамент.

Параметри на заявката (JSON):
{
  "email": "customer@email.com",
  "amount": -150,
  "idempotency_key": "order_12345"
}
Успешен отговор (200 OK):
{
  "transaction_id": "8c3b7a5e-14ef-4b2a-89a1-7788aa99bbcc",
  "status": "Pending"
}
POST /transactions/confirm Потвърждаване на точки

Потвърждава резервирана транзакция (точките се отнемат трайно от баланса).

Параметри на заявката (JSON):
{
  "transaction_id": "8c3b7a5e-14ef-4b2a-89a1-7788aa99bbcc"
}
Успешен отговор (200 OK):
{
  "transaction_id": "8c3b7a5e-14ef-4b2a-89a1-7788aa99bbcc",
  "status": "Completed"
}
POST /transactions/earn Начисляване на точки

Начислява точки на баланса на клиента за завършена покупка или действие. `amount` трябва да е положително число. Автоматично създава клиента, ако не съществува.

Параметри на заявката (JSON):
{
  "email": "customer@email.com",
  "amount": 250,
  "idempotency_key": "order_earn_12345"
}
Успешен отговор (200 OK):
{
  "transaction_id": "fc4b2a8c-14b5-4122-aa11-8899aabbcc77",
  "status": "Completed"
}
POST /transactions/cancel Отказване на точки

Освобождава резервираните точки обратно в баланса на клиента (например при отказ на поръчка преди изпращане).

Параметри на заявката (JSON):
{
  "transaction_id": "8c3b7a5e-14ef-4b2a-89a1-7788aa99bbcc"
}
Успешен отговор (200 OK):
{
  "transaction_id": "8c3b7a5e-14ef-4b2a-89a1-7788aa99bbcc",
  "status": "Cancelled"
}
POST /transactions/refund Възстановяване на точки (Refund)

Възстановява изразходвани точки от приключила Redeem транзакция обратно на клиента (напр. при връщане на продукт). Сумата за възстановяване е положително число и не може да надвишава оригиналната сума на плащането.

Параметри на заявката (JSON):
{
  "reference_transaction_id": "8c3b7a5e-14ef-4b2a-89a1-7788aa99bbcc",
  "amount": 150,
  "idempotency_key": "refund_order_12345"
}
Успешен отговор (200 OK):
{
  "transaction_id": "9d8e7f6a-5b4c-3d2e-1f0a-a1b2c3d4e5f6",
  "status": "Completed"
}
POST /transactions/manual Ръчна корекция на точки

Ръчно добавяне или отнемане на точки от баланса на клиента. Положително число добавя точки, а отрицателно число ги отнема.

Параметри на заявката (JSON):
{
  "email": "customer@email.com",
  "amount": -50,
  "idempotency_key": "manual_adj_67890"
}
Успешен отговор (200 OK):
{
  "transaction_id": "1a2b3c4d-5e6f-7a8b-9c0d-1e2f3a4b5c6d",
  "status": "Completed"
}

👑 Управление на Абонаменти (Subscriptions)

POST /subscriptions/update Създаване/Удължаване на абонамент

Активира или удължава VIP статуса на клиента след покупка на VIP продукт в WooCommerce. Ако клиентът вече има активен абонамент, дните се прибавят адитивно към оставащото време.

Параметри на заявката (JSON):
{
  "email": "customer@email.com",
  "status": "active",
  "expires_in_days": 30,
  "source": "woocommerce_order_12345"
}
Успешен отговор (200 OK):
{
  "message": "Subscription updated successfully.",
  "event": "activated",
  "status": "active",
  "days_added": 30,
  "expires_at": "2026-07-12T15:00:00.000Z"
}
POST /customers/subscription/manual Ръчна промяна на VIP статус

Ръчно задаване на статус и крайна дата на изтичане на VIP абонамент през административната част на WooCommerce.

Параметри на заявката (JSON):
{
  "email": "customer@email.com",
  "status": "active",
  "start_date": "2026-06-12",
  "expires_at": "2026-07-12",
  "note": "Ръчно активиран статус"
}
Успешен отговор (200 OK):
{
  "message": "Subscription manually updated successfully.",
  "status": "active",
  "start_date": "2026-06-12",
  "expires_at": "2026-07-12"
}
POST /webhooks/subscription Webhook за изтичане на абонамент

Външен Webhook от WooCommerce при събития за промяна на абонамент (изтичане, спиране, подновяване).

Параметри на заявката (JSON):
{
  "email": "customer@email.com",
  "status": "expired",
  "source": "woocommerce_subscription_webhook"
}
Успешен отговор (200 OK):
{
  "success": true,
  "message": "Subscription webhook processed successfully.",
  "customer": "customer@email.com",
  "event": "cancelled",
  "status": "expired"
}

📝 Заявки за фактури (Invoice Claims)

POST /invoices/claim Изпращане на заявка за фактура

Използва се за качване на снимка или PDF на фактура за покупки, извършени извън сайта. Изисква `multipart/form-data` кодиране на заявката. Достъпно само за VIP клиенти с активен абонамент.

Параметри на формата (Form Fields - multipart/form-data):
  • `customer_email` (text): Имейл на VIP клиента.
  • `amount` (text/number): Обща сума на покупката от фактурата (напр. `250.50`).
  • `currency` (text, опционален): Валута на покупката (напр. `BGN`).
  • `description` (text, опционален): Описание на покупката.
  • `invoice` (file): Файлът на фактурата (JPEG, PNG или PDF до 5MB).
Успешен отговор (201 Created):
{
  "success": true,
  "message": "Invoice claim submitted successfully for review.",
  "claim_id": "fc4b2a8c-14b5-4122-aa11-8899aabbcc77"
}
GET /customers/:email/invoices Лични искове на клиент

Извлича история на подадените фактури от даден клиент към текущия магазин.

Параметри на пътя (Path Params):
  • `email`: Имейл адрес на клиента.
Успешен отговор (200 OK):
{
  "success": true,
  "invoices": [
    {
      "id": "claim-uuid",
      "amount": 250.50,
      "currency": "BGN",
      "points_awarded": 250,
      "description": "Покупка от физически магазин",
      "image_url": "/uploads/invoices/unique-filename.jpg",
      "status": "approved",
      "rejection_reason": null,
      "created_at": "2026-06-12T15:00:00.000Z"
    }
  ]
}
GET /invoices Списък на исковете за разглеждане

Извлича всички искове по фактури на текущата група магазини. Използва се в интеграцията на WordPress администратора за показване на чакащи за одобрение документи.

Параметри на заявката (Query Params):
  • `status` (опционален): Филтър по статус на иска (`pending`, `approved`, `rejected`).
Успешен отговор (200 OK):
{
  "success": true,
  "invoices": [
    {
      "id": "claim-uuid",
      "amount": 250.50,
      "currency": "BGN",
      "points_awarded": null,
      "description": "Покупка",
      "image_url": "/uploads/invoices/unique-filename.jpg",
      "status": "pending",
      "rejection_reason": null,
      "customer_email": "customer@email.com",
      "tenant_name": "Магазин Име",
      "site_url": "https://client-site.com",
      "created_at": "2026-06-12T15:00:00.000Z"
    }
  ]
}
POST /invoices/:id/approve Одобряване на фактура

Одобрява заявката за фактура и начислява посочените точки в баланса на клиента.

Параметри на пътя (Path Params):
  • `id`: UUID на иска по фактура.
Параметри на заявката (JSON):
{
  "points_awarded": 150,
  "reviewer_email": "admin@tenant.com"
}
Успешен отговор (200 OK):
{
  "success": true,
  "message": "Invoice claim approved and points awarded successfully."
}
POST /invoices/:id/reject Отхвърляне на фактура

Отхвърля иск по фактура. Ако искът е бил одобрен по-рано, системата се опитва да отнеме начислените точки, без да допуска отрицателен баланс.

Параметри на пътя (Path Params):
  • `id`: UUID на иска по фактура.
Параметри на заявката (JSON):
{
  "rejection_reason": "Документът е нечетлив.",
  "reviewer_email": "admin@tenant.com"
}
Успешен отговор (200 OK):
{
  "success": true,
  "message": "Invoice claim rejected successfully."
}