{
  "info": {
    "name": "ProtoPays Merchant API",
    "description": "Импортируйте файл в Postman. В переменных коллекции укажите baseUrl, keyId и secret из кабинета. Подпись HMAC подставится сама (кроме страницы оплаты).",
    "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
  },
  "variable": [
    {
      "key": "baseUrl",
      "value": "https://api.protopays.io"
    },
    {
      "key": "keyId",
      "value": ""
    },
    {
      "key": "secret",
      "value": ""
    }
  ],
  "event": [
    {
      "listen": "prerequest",
      "script": {
        "type": "text/javascript",
        "exec": [
          "const CryptoJS = require(\"crypto-js\");",
          "const path = pm.request.url.getPath();",
          "if (path.includes(\"/checkout/\")) {",
          "  return;",
          "}",
          "const secret = pm.collectionVariables.get(\"secret\") || \"\";",
          "const keyId = pm.collectionVariables.get(\"keyId\") || \"\";",
          "const raw =",
          "  pm.request.body && pm.request.body.mode === \"raw\" && pm.request.body.raw",
          "    ? pm.request.body.raw",
          "    : \"\";",
          "const signature = CryptoJS.HmacSHA256(raw, secret).toString();",
          "pm.request.headers.upsert({ key: \"X-Merchant-Key-Id\", value: keyId });",
          "pm.request.headers.upsert({ key: \"X-Merchant-Secret\", value: secret });",
          "pm.request.headers.upsert({ key: \"Signature\", value: signature });",
          "if (raw) {",
          "  pm.request.headers.upsert({",
          "    key: \"Content-Type\",",
          "    value: \"application/json\",",
          "  });",
          "}",
          ""
        ]
      }
    }
  ],
  "item": [
    {
      "name": "Платежи",
      "item": [
        {
          "name": "Создать платёж",
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/payments",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "payments"
              ],
              "variable": []
            },
            "description": "В ответе — `requisite` (СБП, карта и др.) или `checkoutUrl` для quasi_ecom и mtstpay.\n\nМерчант берётся из заголовков, не из тела.\n\nЕсли реквизит подобрать нельзя — **200**, `status: requisite_unavailable`, `code: collect_requisites_not_available`. Запись создана, webhook не уходит.\n\nСтатус дальше — GET или webhook.",
            "body": {
              "mode": "raw",
              "raw": "{\n  \"orderId\": \"order-001\",\n  \"amount\": \"1000\",\n  \"currency\": \"RUB\",\n  \"callbackUri\": \"https://example.com/hooks/protopays\",\n  \"method\": \"sbp\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          }
        },
        {
          "name": "Статус платежа",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/payments/:payment",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "payments",
                ":payment"
              ],
              "variable": [
                {
                  "key": "payment",
                  "value": ""
                }
              ]
            },
            "description": "Опрос по UUID из create (`data.id`). Для финала лучше webhook. Статусы строчными буквами. Чужой платёж — 404 `payment_not_found`."
          }
        },
        {
          "name": "Апелляция по платежу",
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/payments/:payment/appeal",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "payments",
                ":payment",
                "appeal"
              ],
              "variable": [
                {
                  "key": "payment",
                  "value": ""
                }
              ]
            },
            "description": "Если платёж в `failed` (или `cancelled`), можно открыть спор: текст и файл (чек). Окно около 24 часов.\n\n`payment` в URL — числовой id или UUID.\n\nПодпись **не** от сырого multipart. HMAC-SHA256 от строк (UTF-8, LF):\n\n```\nappeal-v1\n{reason}\n{originalFileName}\n{sizeBytes}\n```\n\n`sizeBytes` — размер файла в байтах."
          }
        },
        {
          "name": "Повторный код (квази-еком)",
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/payments/:payment/quasi-ecom/resend-code",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "payments",
                ":payment",
                "quasi-ecom",
                "resend-code"
              ],
              "variable": [
                {
                  "key": "payment",
                  "value": ""
                }
              ]
            },
            "description": "Если SMS не пришла или код устарел. Не опрашивайте статус ради повторной отправки.\n\nТело `{}`. Пауза около 45 секунд, не больше трёх попыток на заявку.\n\nЕсли повтор запросил трейдер — на callbackUri придёт `payment.quasi_ecom.code_resend`.",
            "body": {
              "mode": "raw",
              "raw": "{}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          }
        }
      ]
    },
    {
      "name": "Страница оплаты",
      "item": [
        {
          "name": "Статус страницы оплаты",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/checkout/:token",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "checkout",
                ":token"
              ],
              "variable": [
                {
                  "key": "token",
                  "value": ""
                }
              ]
            },
            "description": "По желанию опрашивайте раз в 2–5 с. Финал — `isTerminal: true` или webhook."
          }
        },
        {
          "name": "Отправить карту (checkout)",
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/checkout/:token/payer-details",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "checkout",
                ":token",
                "payer-details"
              ],
              "variable": [
                {
                  "key": "token",
                  "value": ""
                }
              ]
            },
            "description": "Токен — из `checkoutUrl` (путь после `/pay/`), это не `data.id`. Подпись мерчанта не нужна.\n\nВ ответе `otpUrl` — откройте плательщику форму кода, если банк прислал SMS.",
            "body": {
              "mode": "raw",
              "raw": "{\n  \"pan\": \"4111111111111111\",\n  \"expMonth\": \"12\",\n  \"expYear\": \"30\",\n  \"cvv\": \"123\",\n  \"cardHolder\": \"Anar Rzayev\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          }
        },
        {
          "name": "Отправить код из SMS (checkout)",
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/checkout/:token/payer-otp",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "checkout",
                ":token",
                "payer-otp"
              ],
              "variable": [
                {
                  "key": "token",
                  "value": ""
                }
              ]
            },
            "description": "4–8 цифр. Если банк код не просит — шаг можно пропустить, итог придёт в webhook.",
            "body": {
              "mode": "raw",
              "raw": "{\n  \"otp\": \"123456\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          }
        },
        {
          "name": "Отменить оплату (checkout)",
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/checkout/:token/cancel",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "checkout",
                ":token",
                "cancel"
              ],
              "variable": [
                {
                  "key": "token",
                  "value": ""
                }
              ]
            },
            "description": "Платёж сразу становится cancelled, уйдёт webhook."
          }
        }
      ]
    },
    {
      "name": "Выплаты",
      "item": [
        {
          "name": "Создать выплату",
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/payins",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "payins"
              ],
              "variable": []
            },
            "description": "Укажите реквизиты получателя. На ключе должны быть включены выплаты. Итог — webhook. В ответе `beneficiary` — маска реквизита, статус обычно `waiting`.",
            "body": {
              "mode": "raw",
              "raw": "{\n  \"orderId\": \"payout-order-001\",\n  \"amount\": 500,\n  \"currency\": \"RUB\",\n  \"method\": \"sbp\",\n  \"address\": \"79001234567\",\n  \"recipient\": \"IVAN IVANOV\",\n  \"code\": \"sber\",\n  \"callbackUri\": \"https://example.com/hooks/protopays-payin\",\n  \"userId\": \"4095\",\n  \"userIp\": \"188.11.55.10\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          }
        },
        {
          "name": "Статус выплаты по вашему orderId",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/payins/by-order?orderId=payout-order-001&method=sbp",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "payins",
                "by-order"
              ],
              "query": [
                {
                  "key": "orderId",
                  "value": "payout-order-001",
                  "description": "Ваш id из создания выплаты."
                },
                {
                  "key": "method",
                  "value": "sbp",
                  "description": "sbp или c2c. Нужен, только если один orderId создан разными методами."
                }
              ],
              "variable": []
            },
            "description": "Опрос статуса по `orderId`, который вы передали при создании. Наш UUID не нужен: если создание оборвалось ошибкой, а выплата уже есть, здесь будет её статус. `404` и `payin_not_found` — выплаты нет. `200` — выплата есть, ту же сумму другому исполнителю не отправляйте. Несколько методов на один orderId — передайте `method` или получите список (`payin_order_ambiguous`)."
          }
        },
        {
          "name": "Статус выплаты по UUID",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/payins/:payin",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "payins",
                ":payin"
              ],
              "variable": [
                {
                  "key": "payin",
                  "value": ""
                }
              ]
            },
            "description": "Опрос по нашему UUID из ответа создания. Если UUID не получили — используйте `GET /api/v1/payins/by-order?orderId=`. Чужая выплата — 404 `payin_not_found`."
          }
        },
        {
          "name": "Чеки выплаты",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/payins/:payin/proofs",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "payins",
                ":payin",
                "proofs"
              ],
              "variable": [
                {
                  "key": "payin",
                  "value": ""
                }
              ]
            },
            "description": "После completed — список URL чеков. Пока выплата не завершена → 403. Файлы открываются обычным GET. В webhook при COMPLETED ссылки могут быть в `meta.proofUrls`."
          }
        }
      ]
    },
    {
      "name": "Баланс",
      "item": [
        {
          "name": "Начисления по приёму",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/balance",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "balance"
              ],
              "variable": []
            },
            "description": "Сколько начислено по успешным оплатам. Ключ на одну кассу — только она; общий ключ — все кассы."
          }
        },
        {
          "name": "USDT на кассе",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/cashboxes/:cashboxId/balance",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "cashboxes",
                ":cashboxId",
                "balance"
              ],
              "variable": [
                {
                  "key": "cashboxId",
                  "value": ""
                }
              ]
            },
            "description": "Всего, доступно и в резерве. Ключ должен быть привязан к этой кассе."
          }
        }
      ]
    },
    {
      "name": "Пополнение",
      "item": [
        {
          "name": "Заявка на пополнение USDT",
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/deposits",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "deposits"
              ],
              "variable": []
            },
            "description": "Идемпотентность по `idempotencyKey` (UUID) в рамках кассы. Тот же ключ на другой кассе — 409.",
            "body": {
              "mode": "raw",
              "raw": "{\n  \"amount\": \"250\",\n  \"network\": \"TRC20\",\n  \"currency\": \"USDT\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          }
        },
        {
          "name": "Статус пополнения",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/deposits/:deposit",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "deposits",
                ":deposit"
              ],
              "variable": [
                {
                  "key": "deposit",
                  "value": ""
                }
              ]
            },
            "description": ""
          }
        }
      ]
    }
  ]
}
