Разработчикам/Интеграция
Пополнение мобильной связи
Пополнение мобильной связи зачисляет деньги прямо на предоплаченный номер телефона. Ваш покупатель получает на свою линию минуты или интернет. Никакого кода передавать не нужно. Оплата идёт с вашего кошелька CardV, так же как и за другие заказы.
См. также: Аутентификация · Общие правила · Вебхуки
#Как это работает
GET /recharge/countries страны, где доступно пополнение
GET /recharge/operators?country=US операторы, типы пополнения и суммы
POST /recharge/quote ваша цена и quote_token, действует 300 с
POST /recharge/orders оформить заказ с оплатой из кошелька
GET /recharge/orders/{order_id} проверять статус или ждать вебхук- Все пути начинаются с
/api/v1. Передавайте те же заголовки, что и в любом запросе. - Оба запроса
POSTнужно подписать. Подписывайте их так же, какPOST/orders, но со своим путём, например/api/v1/recharge/quote. - Заказы на пополнение хранятся отдельно от заказов подарочных карт. Читайте их через методы
/recharge. - Доступно только прямое пополнение. PIN-товаров (код, который покупатель вводит сам) нет.
#Страны
GET/api/v1/recharge/countries показывает страны, где пополнение доступно сейчас.
{
"count": 2,
"results": [
{"code": "MX", "name": "Mexico", "currency_codes": ["MXN"], "operator_count": 4, "offer_count": 37},
{"code": "US", "name": "United States", "currency_codes": ["USD"], "operator_count": 6, "offer_count": 52}
]
}code— код страны по ISO 3166-1 alpha-2. В следующих запросах передавайте его какcountry.currency_codes— местные валюты, в которых продают операторы этой страны.- Список меняется, когда операторы добавляются или становятся недоступны. Загружайте его раз в несколько часов.
#Операторы
GET/api/v1/recharge/operators?country=US показывает операторов одной страны.
Добавьте search=att, чтобы отфильтровать по названию оператора.
{
"count": 1,
"results": [
{
"operator_key": "us-att",
"name": "AT&T",
"country": "US",
"country_name": "United States",
"logo_url": "https://b2b.cardv.net/api/v1/catalog-assets/3f5c...a1.png",
"subtypes": ["airtime", "data"],
"amount_model": "range",
"currency_codes": ["USD"],
"amounts": [
{"min": "5.0000", "max": "100.0000", "currency": "USD", "subtype": "airtime", "label": "5.0000-100.0000 USD"},
{"min": "15.0000", "max": "15.0000", "currency": "USD", "subtype": "data", "label": "15.0000 USD"}
],
"offer_count": 3
}
]
}| Поле | Что значит |
|---|---|
operator_key | ID, который вы передаёте в запрос цены и заказ, например us-att. Храните его как строку. |
subtypes | Что можно купить: airtime (баланс для звонков), data или bundle (звонки и интернет). |
amount_model | fixed, если все суммы заданы заранее, range, если хотя бы одна сумма — диапазон. |
amounts[] | Варианты суммы. Если min равно max, сумма фиксированная. Иначе подходит любая сумма между ними. |
amounts[].currency | Местная валюта этого варианта. Передавайте её как local_currency. |
logo_url | Картинка на серверах CardV или "". |
- Суммы указаны в местной валюте: столько получит телефонная линия.
- Неизвестный или неправильно записанный
countryвернёт HTTP 400.
#Запрос цены
POST/api/v1/recharge/quote возвращает вашу цену за одно пополнение. Этот запрос нужно подписать.
{
"country": "US",
"operator_key": "us-att",
"amount": "10.00",
"local_currency": "USD",
"subtype": "airtime"
}| Поле | Обязательно | Что значит |
|---|---|---|
country | Да | Код страны из списка стран. |
operator_key | Да | Из списка операторов. |
amount | Да | Сумма в местной валюте, строкой. Для fixed — одно из указанных значений. Для range — от min до max. |
local_currency | Желательно | Код ISO 4217 для amount из amounts[].currency. Передавайте его, если у оператора несколько валют. |
subtype | Нет | airtime (по умолчанию), data или bundle. |
Ответ:
{
"country": "US",
"country_name": "United States",
"operator": {"operator_key": "us-att", "name": "AT&T", "logo_url": ""},
"subtype": "airtime",
"local_amount": "10.0000",
"local_currency": "USD",
"merchant_price": "9.6200",
"merchant_currency": "USD",
"expires_at": "2026-09-30T08:20:30.123456+00:00",
"quote_token": "eyJ2ZXJzaW9uIjox...:1uXyZa:8c1f..."
}merchant_price— сколько спишется с вашего кошелька, в валютеmerchant_currency.quote_tokenфиксирует эту цену на 300 секунд, доexpires_at. Передайте его в заказе без изменений.- Токен привязан к вашему аккаунту и к этим стране, оператору, типу и сумме.
- Перед заказом проверьте, что
local_currency— та валюта, которую вы ожидали. - Запрос цены не резервирует деньги. Новую цену можно запросить в любой момент.
#Оформление заказа на пополнение
POST/api/v1/recharge/orders пополняет телефон и списывает деньги с кошелька. Этот запрос нужно подписать.
{
"external_order_id": "SHOP-RC-20260930-0001",
"country": "US",
"operator_key": "us-att",
"amount": "10.00",
"local_currency": "USD",
"subtype": "airtime",
"account": "12125550100",
"quote_token": "eyJ2ZXJzaW9uIjox...:1uXyZa:8c1f..."
}| Поле | Обязательно | Что значит |
|---|---|---|
external_order_id | Да | Ваш номер заказа. Уникален среди всех ваших заказов, включая заказы подарочных карт. |
country, operator_key, amount, local_currency, subtype | Да | Те же значения, что вы передали в запрос цены. |
account | Да | Номер телефона для пополнения: только цифры, с кодом страны, без + и пробелов. |
quote_token | Да | Из ответа на запрос цены, пока он не истёк. |
Примеры номеров: 12125550100 (США), 525512345678 (Мексика).
Убедитесь, что номер принадлежит выбранному оператору. Пополнение на неверный номер отменить нельзя.
CardV проверяет цену, сразу списывает merchant_price с вашего кошелька и запускает пополнение в фоне.
Новый заказ возвращает HTTP 201:
{
"idempotent_replay": false,
"order": {
"order_id": "O-00005678",
"external_order_id": "SHOP-RC-20260930-0001",
"status": "accepted",
"status_title": "Recharge accepted",
"poll_after_seconds": 12,
"account": "12***00",
"local_amount": "10.0000",
"local_currency": "USD",
"merchant_price": "9.6200",
"merchant_currency": "USD",
"...": "more fields"
}
}- Сохраните
order.order_id. - Номер телефона в ответе всегда скрыт, целиком он не возвращается.
#Безопасный повтор
external_order_id защищает от двойного пополнения.
| Что вы отправляете | Что получаете |
|---|---|
| Новый номер заказа | HTTP 201. Новый заказ. Деньги списываются с кошелька. |
| Тот же номер и то же пополнение | HTTP 200 и "idempotent_replay": true. Существующий заказ. Без списания. |
| Тот же номер, но другое пополнение | HTTP 400 с ошибкой external_order_id. Ничего не происходит. |
«То же пополнение» — это те же страна, оператор, тип, сумма и номер телефона.
Повторный заказ распознаётся ещё до проверки цены, поэтому даже с истёкшим quote_token вернётся первый заказ.
- После тайм-аута, ответа 5xx или обрыва соединения отправьте то же тело с тем же номером заказа. Подпишите его заново с новыми временем и nonce.
- Никогда не придумывайте новый номер заказа из-за того, что ответ потерялся. Так телефон может пополниться дважды.
#Получение заказов на пополнение
GET/api/v1/recharge/orders/{order_id} возвращает один заказ.
Можно использовать номер заказа CardV (O-00005678).
{
"order_id": "O-00005678",
"external_order_id": "SHOP-RC-20260930-0001",
"status": "processing",
"order_status": "processing",
"status_title": "Recharge processing",
"status_message": "The recharge request is being processed. Delivery is not confirmed yet.",
"next_step": "Keep this order open and wait for confirmation before placing another recharge.",
"poll_after_seconds": 12,
"country": "US",
"operator": {"operator_key": "us-att", "name": "AT&T", "logo_url": ""},
"subtype": "airtime",
"account": "12***00",
"local_amount": "10.0000",
"local_currency": "USD",
"merchant_price": "9.6200",
"merchant_currency": "USD",
"attempts": [{"attempt_no": 1, "status": "processing", "error_message": "", "submitted_at": "2026-09-30T08:16:02.511201Z", "completed_at": null}],
"created_at": "2026-09-30T08:16:01.004211Z",
"updated_at": "2026-09-30T08:16:02.611978Z",
"...": "more fields"
}- Неизвестный номер заказа или заказ другого аккаунта вернёт HTTP 404.
status_title,status_messageиnext_step— текст на английском, его можно показывать вашим сотрудникам.poll_after_seconds— сколько ждать до следующей проверки.0означает, что заказ завершён.
#Список заказов на пополнение
GET/api/v1/recharge/orders показывает ваши заказы на пополнение, сначала самые новые.
GET /api/v1/recharge/orders?status=processing&limit=50&offset=0{"count": 3, "limit": 50, "results": ["..."]}- Фильтры:
statusиsearch(номер заказа CardV, ваш номер заказа или название оператора). - По умолчанию
limitравен 20, максимум — 100. Большие значения уменьшаются до 100. - Отрицательный или нечисловой
limitилиoffsetвернёт HTTP 400.
#Статус
accepted ──► processing ──► succeeded
│
├──► manual_review ──► succeeded или refunded
│
└──► failed ──► refunded (деньги вернулись в кошелёк)| Статус | Завершён? | Что делать |
|---|---|---|
accepted | Нет | Ждать. Деньги списаны, пополнение ещё не началось. |
processing | Нет | Ждать. Это может занять несколько минут. Не оформляйте заказ повторно. |
manual_review | Нет | CardV уточняет результат у оператора. Ждать. |
succeeded | Да | Телефон пополнен. Сообщите покупателю. |
failed | Ещё нет | Пополнение не прошло. Дождитесь refunded. |
refunded | Да | Деньги вернулись в кошелёк. Можно оформить новый заказ. |
- Проверяйте через
poll_after_seconds, затем реже: 30 с, 60 с, а дальше каждые 5 минут. Не выходите за лимит запросов. - Если статус вам незнаком, считайте, что заказ ещё не завершён.
- Пока заказ не завершён, не отправляйте на тот же номер новое пополнение с новым номером заказа. Если первое тоже пройдёт, телефон пополнится дважды.
#Вебхуки и возвраты
Заказы на пополнение присылают те же вебхуки, что и другие заказы:
order.succeeded, order.failed и order.refunded.
В вебхуке есть номер заказа CardV, ваш номер заказа и пустой список items.
Получив вебхук, прочитайте заказ через GET/api/v1/recharge/orders/{order_id}.
Возвраты происходят автоматически. Когда оператор подтверждает сбой, CardV возвращает весь
merchant_price в ваш кошелёк, и заказ переходит в статус refunded.
Возврат виден на странице операций в кабинете.
Успешное пополнение нельзя вернуть или отменить.
#Ошибки
Ошибки устроены по общим правилам. Отклонённый запрос цены или заказ возвращает HTTP 400, деньги не списываются.
| Ключ | Где | Что делать |
|---|---|---|
detail | Запрос цены, заказ | Страна, оператор, тип или сумма недоступны. Сверьтесь со списком операторов. |
amount | Запрос цены, заказ | Не число, ноль или вне диапазона. |
local_currency | Запрос цены, заказ | Не трёхбуквенный код ISO 4217. |
account | Заказ | Не указан номер телефона. |
quote_token | Заказ | Нет, истёк, изменён или не совпадает. Посмотрите code и запросите цену заново. |
balance | Заказ | Пополните кошелёк в кабинете. |
risk | Заказ | Вы упёрлись в лимит заказов. Свяжитесь с CardV. |
external_order_id | Заказ | Уже использован для другого заказа. См. Безопасный повтор. |
wallet | Заказ | Нет активного кошелька. Свяжитесь с CardV. |
Ошибки quote_token приходят с полем code:
{"code": "quote_expired", "quote_token": "This quote expired. Refresh the price and confirm again."}code | Что значит |
|---|---|
quote_required | quote_token не передан. |
quote_expired | Прошло больше 300 секунд. Запросите цену заново. |
quote_invalid | Изменён или выдан для другого пополнения. Запросите цену заново. |
price_changed | Ваша цена изменилась после запроса. Запросите цену заново и подтвердите новую. |
HTTP 403 означает проблему с учётными данными, подписью, IP или одобрением. См. Аутентификация.
Вопросы по интеграции? Напишите на [email protected], указав ваш Merchant ID и ID заказа или запроса.