Расчёт стоимости и сроков

POST /v1/rates: параметры посылки, формат тарифов, типы доставки и условия списания запросов.

POST /v1/rates

Один вызов параллельно рассчитывает доставку всеми выбранными активными перевозчиками. При отсутствии carriers используются все активные интеграции.

ПолеТипПравило
from / toobjectОбязательные адреса
from.city / to.citystringНепустое название города
from.country / to.countrystringRU; по умолчанию RU
postal_codestring | nullШесть цифр для РФ; нужен Почте России
parcel.weight_gramsintegerОт 1 до 1 000 000 граммов
parcel.length_cm / width_cm / height_cmnumberБольше 0 и не больше 1 000 см
declared_value_kopecksintegerОт 0 до 100 000 000 000 копеек, необязательно
carriersstring[]Необязательный список от 1 до 10 уникальных кодов

У перевозчиков есть дополнительные ограничения на направления, размеры и вид груза. Успешная валидация Доставометра не гарантирует наличие тарифа.

cURLПример запроса
curl --fail-with-body https://api.dostavometr.ru/v1/rates \
  -H "Authorization: Bearer $DOSTAVOMETR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "from": {
    "country": "RU",
    "city": "Чита",
    "postal_code": "672000"
  },
  "to": {
    "country": "RU",
    "city": "Москва",
    "postal_code": "101000"
  },
  "parcel": {
    "weight_grams": 1000,
    "length_cm": 30,
    "width_cm": 20,
    "height_cm": 15
  }
}'
PythonПример запроса
import json
import os
import urllib.request

payload = {
  "from": {
    "country": "RU",
    "city": "Чита",
    "postal_code": "672000"
  },
  "to": {
    "country": "RU",
    "city": "Москва",
    "postal_code": "101000"
  },
  "parcel": {
    "weight_grams": 1000,
    "length_cm": 30,
    "width_cm": 20,
    "height_cm": 15
  }
}
request = urllib.request.Request(
    "https://api.dostavometr.ru/v1/rates",
    data=json.dumps(payload).encode("utf-8"),
    headers={
        "Authorization": "Bearer " + os.environ["DOSTAVOMETR_API_KEY"],
        "Content-Type": "application/json",
    },
)
with urllib.request.urlopen(request, timeout=30) as response:
    print(json.load(response))
PHPПример запроса
<?php
$key = getenv('DOSTAVOMETR_API_KEY');
if (!$key) { throw new RuntimeException('Set DOSTAVOMETR_API_KEY'); }
$ch = curl_init('https://api.dostavometr.ru/v1/rates');
$options = [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 30,
    CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . $key, 'Content-Type: application/json'],
];
$payload = json_decode(<<<'JSON'
{
  "from": {
    "country": "RU",
    "city": "Чита",
    "postal_code": "672000"
  },
  "to": {
    "country": "RU",
    "city": "Москва",
    "postal_code": "101000"
  },
  "parcel": {
    "weight_grams": 1000,
    "length_cm": 30,
    "width_cm": 20,
    "height_cm": 15
  }
}
JSON, true, 512, JSON_THROW_ON_ERROR);
$options[CURLOPT_POST] = true;
$options[CURLOPT_POSTFIELDS] = json_encode($payload, JSON_THROW_ON_ERROR);
curl_setopt_array($ch, $options);
$body = curl_exec($ch);
if ($body === false) { throw new RuntimeException(curl_error($ch)); }
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($status >= 400) { throw new RuntimeException($body); }
print_r(json_decode($body, true, 512, JSON_THROW_ON_ERROR));
JavaScriptПример запроса
// Node.js 20+; запускайте на сервере, чтобы не раскрыть API-ключ.
const apiKey = process.env.DOSTAVOMETR_API_KEY;
if (!apiKey) throw new Error('Set DOSTAVOMETR_API_KEY');
const response = await fetch('https://api.dostavometr.ru/v1/rates', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${apiKey}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
  "from": {
    "country": "RU",
    "city": "Чита",
    "postal_code": "672000"
  },
  "to": {
    "country": "RU",
    "city": "Москва",
    "postal_code": "101000"
  },
  "parcel": {
    "weight_grams": 1000,
    "length_cm": 30,
    "width_cm": 20,
    "height_cm": 15
  }
}),
  signal: AbortSignal.timeout(30000),
});
const result = await response.json();
if (!response.ok) throw new Error(JSON.stringify(result));
console.log(result);

Нормализованный ответ

{
  "request_id": "req_example",
  "rates": [
    {
      "carrier": "russian_post",
      "carrier_name": "Почта России",
      "service_code": "parcel",
      "service_name": "Посылка",
      "delivery_type": "post_office",
      "price_kopecks": 48700,
      "currency": "RUB",
      "days_min": 5,
      "days_max": 7,
      "price_type": "public"
    }
  ],
  "unavailable": [
    {
      "carrier": "dellin",
      "reason": "not_configured"
    }
  ],
  "balance_remaining": 99
}

Пример формата, без обещания указанных цены и сроков.

  • price_kopecks — целые копейки. Валюта RUB.
  • service_code и service_name обозначают услугу конкретного перевозчика.
  • days_min / days_max — ориентировочное число дней или null.
  • price_type — источник ценовых условий; публичные тарифы помечены public.
  • balance_remaining — остаток на момент завершения запроса.

Типы доставки

delivery_typeЗначение
doorДо двери
pickup_pointПункт выдачи
terminalТерминал
post_officeПочтовое отделение
unknownПеревозчик не уточнил тип

Списание и кэш

Один корректный расчёт стоит один запрос, независимо от числа перевозчиков. Кэшированный расчёт также списывает один запрос. Частичный результат — HTTP 200 и один запрос. Технический отказ всех перевозчиков — HTTP 503 и возврат зарезервированного запроса. Корректный пустой результат с причиной no_rates — HTTP 200 и списание одного запроса.

Повтор операции после сетевого сбоя выполняйте с тем же Idempotency-Key и тем же телом. Правила идемпотентности.