Быстрый старт
Цель этой страницы — первый успешный подписанный запрос за 10 минут. Полная механика подписи и тестовый вектор для сверки своей реализации — в Аутентификации.
Что у вас должно быть заранее
X-API-Keyи HMAC-секрет, выданные AploDelivery для вашего credential (role: ingress, ровно одинsource, списокexternalPoints).- Базовый URL сервиса: прод
https://api.aplosnab.ru, резервный/pilothttps://delivery.beta.aplosoft.ru(тот же backend и ключи; в примерах ниже подставляйте выданный вам хост). opensslиuuidgen(для curl-примера) или Go 1.21+ (для примера на Go SDK).
Ключ и секрет храните только на своём backend — см. Безопасность.
Шаг 1. Проверить, что сервис жив
curl -s https://api.aplosnab.ru/health/live
# {"status":"ok"}
Этот запрос не подписывается.
Шаг 2. Первый подписанный запрос — список точек
BASE_URL='https://api.aplosnab.ru'
APLO_API_KEY='ваш-api-key'
APLO_API_SECRET='ваш-hmac-секрет'
TIMESTAMP="$(date +%s)"
REQUEST_ID="$(uuidgen)"
METHOD='GET'
REQ_PATH='/v1/points'
BODY_HASH="$(printf '' | sha256sum | awk '{print $1}')"
CANONICAL="$(printf '%s\n%s\n%s\n%s\n%s' \
"$TIMESTAMP" "$REQUEST_ID" "$METHOD" "$REQ_PATH" "$BODY_HASH")"
SIGNATURE="$(printf '%s' "$CANONICAL" |
openssl dgst -sha256 -hmac "$APLO_API_SECRET" -hex |
sed 's/^.* //')"
curl --fail-with-body "$BASE_URL$REQ_PATH" \
-H "X-API-Key: $APLO_API_KEY" \
-H "X-Timestamp: $TIMESTAMP" \
-H "X-Request-ID: $REQUEST_ID" \
-H "X-Signature: $SIGNATURE"
Ожидаемый ответ:
{"points":[{"externalPointId":"3","active":true,"streetsSyncedAt":null}]}
streetsSyncedAt: null означает, что словарь улиц для точки ещё ни разу не загружался плагином — это не ошибка, см. Быстрый старт → проверка адреса и order-lifecycle.
Шаг 3. Отфильтровать блюда по точке
Показывайте на сайте только блюда, которые реально смаппены на точку — это снижает риск 422 product_mapping_not_found при создании заказа:
METHOD='GET'
REQ_PATH='/v1/points/3/products'
BODY_HASH="$(printf '' | sha256sum | awk '{print $1}')"
TIMESTAMP="$(date +%s)"
REQUEST_ID="$(uuidgen)"
CANONICAL="$(printf '%s\n%s\n%s\n%s\n%s' \
"$TIMESTAMP" "$REQUEST_ID" "$METHOD" "$REQ_PATH" "$BODY_HASH")"
SIGNATURE="$(printf '%s' "$CANONICAL" |
openssl dgst -sha256 -hmac "$APLO_API_SECRET" -hex |
sed 's/^.* //')"
curl --fail-with-body "$BASE_URL$REQ_PATH" \
-H "X-API-Key: $APLO_API_KEY" -H "X-Timestamp: $TIMESTAMP" \
-H "X-Request-ID: $REQUEST_ID" -H "X-Signature: $SIGNATURE"
{"externalPointId":"3","products":[{"externalProductId":"321","kind":"product"}]}
Шаг 4. Проверить адрес до оформления
METHOD='POST'
REQ_PATH='/v1/addresses/check'
BODY='{"externalPointId":"3","street":"Ленина","house":"5","city":"Балашиха"}'
BODY_HASH="$(printf '%s' "$BODY" | sha256sum | awk '{print $1}')"
TIMESTAMP="$(date +%s)"
REQUEST_ID="$(uuidgen)"
CANONICAL="$(printf '%s\n%s\n%s\n%s\n%s' \
"$TIMESTAMP" "$REQUEST_ID" "$METHOD" "$REQ_PATH" "$BODY_HASH")"
SIGNATURE="$(printf '%s' "$CANONICAL" |
openssl dgst -sha256 -hmac "$APLO_API_SECRET" -hex |
sed 's/^.* //')"
curl --fail-with-body "$BASE_URL$REQ_PATH" \
-H "Content-Type: application/json" \
-H "X-API-Key: $APLO_API_KEY" -H "X-Timestamp: $TIMESTAMP" \
-H "X-Request-ID: $REQUEST_ID" -H "X-Signature: $SIGNATURE" \
-d "$BODY"
status в ответе: ok (можно продолжать), ambiguous (попросите гостя выбрать улицу из candidates), not_found (адрес не найден), unknown (словарь ещё не загружен — это НЕ блокирует оформление заказа). Поле house возвращается эхом и не проверяется — в POS-словаре домов нет.
Шаг 5. Создать заказ
Минимальный валидный CanonicalOrder (совпадает с полями openapi.yaml, total обязан точно равняться сумме price.amountMinor × quantity по всем позициям — если это не так, сервер отвечает 400 invalid_request):
{
"schemaVersion": 1,
"source": "website",
"externalOrderId": "site-1042",
"externalPointId": "3",
"createdAt": "2026-09-23T10:15:00+03:00",
"deliverAt": "2026-09-23T11:00:00+03:00",
"guest": {
"externalClientId": "c-9001",
"name": "Иван",
"phone": "+79261234567"
},
"address": {
"street": "Ленина",
"house": "5"
},
"items": [
{
"externalProductId": "321",
"quantity": "2",
"price": {"amountMinor": 42000, "currency": "RUB"}
}
],
"total": {"amountMinor": 84000, "currency": "RUB"}
}
Подпишите POST /v1/orders этим телом (метод и путь в canonical-строке — POST и /v1/orders, без query). Ответ:
201 Created— заказ создан впервые;200 OK— повторная идемпотентная отправка того жеexternalOrderIdс тем же содержимым (см. Идемпотентность);409— тот жеexternalOrderId, но другое содержимое;422 route_mapping_not_found— для этой точки нет активного маршрута.
Тело ответа (JSON, независимо от языка клиента) — полная проекция заказа с полями id, iikoOrderId, iikoDeliveryId (стабильные UUID, выданные AploDelivery сразу при создании — они существуют с первой секунды, ещё до того, как плагин на кассе увидел заказ), state, deliveryStatus, cancelState и другими — см. Жизненный цикл заказа.
Гоча для Go SDK: Client.Submit (единственный метод для POST /v1/orders) декодирует ответ в узкий тип ingressclient.OrderStatus — там только ID, ExternalOrderID, Source, State, IIKOOrderID, IIKODeliveryID. Поля deliveryStatus/cancelState в JSON присутствуют, но Submit их отбрасывает. Если сразу после создания заказа вам нужны эти поля — прочитайте заказ повторно через Client.GetOrder/Client.FindByExternalOrderID, которые декодируют в полный ingressclient.OrderView.
comment поля в схеме есть у заказа и у каждой позиции, но modifiers для source: website сейчас не используются (сайт ВиЛ не продаёт модификаторы) — не заполняйте это поле в v1.
Шаг 6. Отследить заказ
Основной канал — вебхуки. Резервный — поллинг:
METHOD='GET'
REQ_PATH='/v1/orders'
QUERY='externalOrderId=site-1042'
BODY_HASH="$(printf '' | sha256sum | awk '{print $1}')"
TIMESTAMP="$(date +%s)"
REQUEST_ID="$(uuidgen)"
CANONICAL="$(printf '%s\n%s\n%s\n%s\n%s' \
"$TIMESTAMP" "$REQUEST_ID" "$METHOD" "$REQ_PATH" "$BODY_HASH")"
SIGNATURE="$(printf '%s' "$CANONICAL" |
openssl dgst -sha256 -hmac "$APLO_API_SECRET" -hex |
sed 's/^.* //')"
# подпись строится ТОЛЬКО от REQ_PATH (без query-строки), см. authentication.md;
# query добавляется только к URL самого curl-запроса:
curl --fail-with-body "$BASE_URL$REQ_PATH?$QUERY" \
-H "X-API-Key: $APLO_API_KEY" -H "X-Timestamp: $TIMESTAMP" \
-H "X-Request-ID: $REQUEST_ID" -H "X-Signature: $SIGNATURE"
Пример на Go (пакет pkg/ingressclient)
SDK сам строит canonical-строку, подписывает запрос и не следует HTTP-редиректам:
package main
import (
"context"
"log"
"os"
"aplo-loyalty-delivery/pkg/ingressclient"
)
func main() {
client, err := ingressclient.New(ingressclient.Options{
BaseURL: os.Getenv("APLODELIVERY_URL"),
APIKey: os.Getenv("APLODELIVERY_API_KEY"),
Secret: os.Getenv("APLODELIVERY_API_SECRET"),
Source: ingressclient.SourceWebsite,
})
if err != nil {
log.Fatal(err)
}
points, err := client.ListPoints(context.Background())
if err != nil {
log.Fatal(err)
}
log.Printf("available points: %d", len(points))
}
ingressclient.New требует абсолютный HTTPS origin без пути/query/фрагмента (HTTP разрешён только для loopback в тестах), API-ключ ≥ 8 символов и секрет ≥ 32 символов — иначе конструктор вернёт ошибку сразу, без сетевого запроса.
Дальше
- Аутентификация и подпись запроса — точная механика подписи + тестовый вектор для сверки собственной реализации.
- Идемпотентность
- Жизненный цикл заказа
- Чеклист перед запуском в проде