Обновление API: новые методы версионирования
Invoicx API v3 переосмысливает модель версий и генерации счетов: стабильные контракты, семантические теги и предсказуемые breaking-изменения. Ниже — что сломалось, как мигрировать и как писать новый код.
Релиз v3.0 · 12 марта 2025 · Поддержка v2 до 30 сентября 2025
Версия теперь часть контракта, а не заголовок
В v3 мы перешли от «одной живой версии» к явной семантической модели. Каждая мажорная версия — отдельный, неизменяемый контракт, который не меняется под ногами у клиента.
В v2 версия передавалась в заголовке Accept: application/vnd.invoicx.v2+json и могла «тихо» меняться. В v3 версия закреплена в URL-префиксе (/v3/...) и дополняется семантическим тегом X-Invoicx-Api-Version. Мажорные изменения больше не появляются без отдельного релиза и changelog — вы всегда знаете, какой контракт обслуживает ваш код.
Как устроено версионирование
URL-префикс версии
Версия живёт в пути: /v3/invoices. Никаких скрытых переключателей — видно сразу, какой контракт вы вызываете.
Семантические теги
Ответы несут X-Invoicx-Api-Version: 3.2.1. Пэтчи добавляются без изменений контракта, мажор — только отдельным релизом.
Замороженные контракты
Поля, которые вы используете, не удаляются и не переименовываются внутри мажорной версии. Изменения — только в новой мажорке.
Явный sunset
Каждая версия получает дату отключения. Для v2 это 30.09.2025 — у вас есть время на спокойную миграцию.
Предсказуемые ошибки
Единый формат error с кодом, trace_id и ссылками на документацию. Никаких «500 без причины».
Идемпотентность
Все мутации принимают Idempotency-Key. Повторный вызов не создаст дубликат счёта — даже при ретраях.
Что именно поменять в коде
В подавляющем большинстве случаев миграция — это смена префикса и пара переименований полей. Ниже — полный список breaking-изменений.
Префикс и заголовок
Замените /v2/ на /v3/ и уберите Accept: application/vnd.invoicx.v2+json. Версию теперь определяет путь.
Переименование полей
invoice.total → invoice.amount_total, customer → counterparty. Старые имена отключены в v3.
Статусы оплат
Перечисление payment_state расширено: добавлены partially_paid и disputed. Проверьте все сравнения.
Формат дат
Все даты-время теперь строго ISO 8601 с часовым поясом (2025-03-12T14:30:00+03:00). Без таймзоны — ошибка 422.
Постраничные ответы
Списки возвращают объект { items, next_cursor } вместо массива. Пагинация — по курсору, а не по page.
Аутентификация
Ключ передаётся в Authorization: Bearer. Заголовок X-Invoicx-Key из v2 больше не принимается.
Генерация счетов — одним вызовом
v3 добавляет endpoints, которые в v2 требовали цепочку из трёх-четырёх запросов. Теперь генерация, проверка и отправка — предсказуемо и атомарно.
/v3/invoices
Создаёт счёт по правилам выставления. Принимает rule_id или полный payload; возвращает объект со статусом draft.
/v3/invoices/{id}:generate
Пересчитывает суммы и формирует финальные реквизиты из черновика. Идемпотентно — повторный вызов не изменит результат.
/v3/invoices/{id}:issue
Выставляет счёт контрагенту и запускает слежение оплат. Статус переходит в issued, фиксируется issued_at.
/v3/invoices/{id}/audit
Возвращает полный аудит-трейл: кто и когда менял суммы, условия и статусы. Каждое действие — с trace_id.
Python и JavaScript на v3
Оба примера генерируют и выставляют счёт по правилу, передавая Idempotency-Key для безопасных ретраев.
Генерация и выставление
import requests
API = "https://api.invoicx.io/v3"
H = {
"Authorization": "Bearer ix_live_9f2a…",
"Idempotency-Key": "inv-gen-2025-03-12-001",
}
# Генерация по правилу выставления
gen = requests.post(
f"{API}/invoices",
headers=H,
json={"rule_id": "rule_recurring_04", "due_in_days": 14},
)
gen.raise_for_status()
invoice_id = gen.json()["id"]
# Финализация сумм
requests.post(f"{API}/invoices/{invoice_id}:generate", headers=H)
# Выставление контрагенту
issued = requests.post(f"{API}/invoices/{invoice_id}:issue", headers=H)
print(issued.json()["payment_state"]) # "issued"
Генерация и выставление
const API = "https://api.invoicx.io/v3";
const H = {
"Authorization": "Bearer ix_live_9f2a…",
"Idempotency-Key": "inv-gen-2025-03-12-001",
};
async function issueFromRule(ruleId) {
const gen = await fetch(`${API}/invoices`, {
method: "POST",
headers: H,
body: JSON.stringify({ rule_id: ruleId, due_in_days: 14 }),
});
if (!gen.ok) throw new Error("gen " + gen.status);
const { id } = await gen.json();
await fetch(`${API}/invoices/${id}:generate`, { method: "POST", headers: H });
const issued = await fetch(`${API}/invoices/${id}:issue`, {
method: "POST",
headers: H,
});
const data = await issued.json();
console.log(data.payment_state); // "issued"
}
issueFromRule("rule_recurring_04");
Проверьте свой код на v3
Подключите тестовый ключ и прогоните миграцию в песочнице — до того, как v2 уйдёт в sunset 30 сентября.