API за фактури
Вашият сайт, магазин или програма може да издава фактури и проформи в BFaktura сама: с правилен номер, ДДС по ставки и PDF, и да ги праща на купувача по имейл. Нужни са акаунт в BMail и попълнен профил на фирмата.
Начало
Създайте ключ в Интеграции. Ключовете са два вида: bf_test_… за проба и bf_live_… за работа. Ключът се показва само веднъж; пазете го като парола, на сървъра, не в браузъра.
Всички адреси започват с https://faktura.bizzupp.bg/api/v1. Ключът се праща в заглавка Authorization: Bearer <ключ>. Данните са JSON с UTF-8, суми в евро, дати във вид 2026-10-07. Проверка дали ключът работи: GET /api/v1/key.
Нов документ
Една заявка създава документа и, ако поискате, го издава и праща. Създаването и издаването са едно цяло: или документът е издаден, или нищо не е записано и отговорът казва кое поле да се поправи.
curl https://faktura.bizzupp.bg/api/v1/documents \
-H "Authorization: Bearer bf_live_…" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: order-1001" \
-d '{
"type": "INVOICE",
"issue": true,
"send": true,
"externalId": "1001",
"recipient": {
"name": "Строй Комплект ООД",
"eik": "121212121",
"vatNumber": "BG121212121",
"address": "София, бул. Витоша 1",
"mol": "Петър Петров",
"email": "orders@stroi.bg"
},
"lines": [
{ "description": "Боя фасадна 15 л", "unit": "бр.", "quantity": 2, "unitPrice": 54, "vatRate": 20 }
],
"pricesIncludeVat": true,
"paymentMethod": "CARD",
"paidOn": "2026-10-07"
}'Отговорът е 201 с документа. Повторената заявка връща 200 със същия документ и "duplicate": true.
{
"id": 412,
"type": "INVOICE",
"status": "ISSUED",
"number": "0000000123",
"issueDate": "2026-10-07",
"taxBase": 90.00,
"vatAmount": 18.00,
"total": 108.00,
"paidOn": "2026-10-07",
"source": "API",
"externalId": "1001",
"pdfUrl": "https://faktura.bizzupp.bg/api/v1/documents/412/pdf",
…
}Същото на PHP
$ch = curl_init('https://faktura.bizzupp.bg/api/v1/documents');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('BFAKTURA_KEY'),
'Content-Type: application/json',
'Idempotency-Key: order-' . $order['id'],
],
CURLOPT_POSTFIELDS => json_encode($invoice, JSON_UNESCAPED_UNICODE),
]);
$document = json_decode(curl_exec($ch), true);Полета
typeINVOICEилиPROFORMA. Кредитното известие има свой адрес.issuetrueиздава веднага с номер; без него остава чернова, която издавате по-късно.sendtrueпраща издадения документ наrecipient.emailот faktura@bizzupp.bg. Отговорите на купувача отиват на имейла от профила ви.externalId- Номерът на поръчката във вашата система, до 100 знака. Пази от двойни документи.
recipientnameиaddressса задължителни за издаване;eik,vatNumber,mol,emailпо желание. Физическо лице е само с име и адрес.lines- До 200 реда с
description,unit(по подразбиране „бр.“),quantity(до 3 знака),unitPriceиvatRate(0, 9 или 20). Ако профилът не е по ЗДДС, ставката е 0 и основанието се пише само. pricesIncludeVattrue, ако цените са крайни, с ДДС. Тогава цената без ДДС се смята с 4 знака; сборът може да се различава от платеното с до 0,01 € за ставка.paymentMethodBANK(иска IBAN в профила),CASH,CARDилиOTHERсpaymentNote.paidOn- Дата на плащане; само за фактура, която се издава.
vatNote- Основанието при ставка 9% или 0%, например „чл. 41 от ЗДДС“.
issueDate, taxEventDate, dueDate- По подразбиране днес и падежът от настройките ви. Номерата вървят по датите, затова документ не може да е с дата преди последния издаден.
template, language- Шаблонът от „Дизайн“ (
CLASSIC,MODERNи др.) и езикът:BGилиBG_ENза двуезичен документ.
Повторения
Мрежата понякога прекъсва и заявката се праща пак. За да не излязат две фактури за една поръчка, пращайте externalId или заглавка Idempotency-Key:
- Същият
externalIdвинаги връща съществуващия документ. - Същият
Idempotency-Keyдо 24 часа връща същия отговор. Със същия ключ и друго тяло отговорът е409.
Проба
С ключ bf_test_… заявката минава всички проверки като истинската и връща документа с "test": true и PDF в pdfBase64 с надпис „ПРОБА“. Нищо не се записва, не се взима номер и не се праща писмо. Другите адреси с пробен ключ връщат 403.
Други адреси
GET /documents: списък, най-новите първо. Филтриtype,status,from,to,externalId; страници сbefore=<id>иlimitдо 100.GET /documents/{id}иGET /documents/{id}/pdf.POST /documents/{id}/issue: издава чернова.POST /documents/{id}/paidс{"paidOn": "2026-10-07"}иDELETE /documents/{id}/paid.POST /documents/{id}/credit-noteсreason, по желаниеlines(за частично известие) иissue.POST /documents/{id}/send, по желание с{"email": "…"}.
Грешки и граници
Грешката е JSON с error (за хора, на български), code (invalid, unauthorized, forbidden, not_found, conflict, rate_limited) и при грешни полета fields, например {"lines.0.quantity": "Количеството трябва да е над нула"}.
- 60 заявки в минута на ключ; след тях
429сRetry-After. - До 500 издадени документа за 24 часа през API и връзките, до 200 писма. Пишете ни, ако ви трябват повече.
Известия
В Интеграции задайте https адрес и събитията: document.issued, credit_note.issued, document.paid, document.unpaid, email.sent, email.failed. BFaktura праща POST с JSON. Известия идват и за документите, издадени в самото приложение.
{
"id": "evt_5f0c…",
"type": "document.issued",
"created": 1791370800,
"data": {
"document": { "id": 412, "number": "0000000123", "total": 108.00, "externalId": "1001", … }
}
}Отговорете с код 2xx до 10 секунди. Иначе опитваме пак след 1 и 5 минути, след 30 минути и после след 2, 6 и 24 часа. Всяко известие е подписано в заглавка BFaktura-Signature: t=<време>,v1=<подпис>: HMAC-SHA256 на време.тяло с тайната на адреса. Проверете го, преди да вярвате на известието:
import crypto from "node:crypto";
// header е стойността на BFaktura-Signature, body е суровият текст на заявката.
function verify(secret, header, body) {
const parts = Object.fromEntries(header.split(",").map((part) => part.split("=")));
const expected = crypto.createHmac("sha256", secret).update(`${parts.t}.${body}`).digest("hex");
const fresh = Math.abs(Date.now() / 1000 - Number(parts.t)) < 300;
return fresh && crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(parts.v1));
}function verify(string $secret, string $header, string $body): bool
{
parse_str(str_replace(',', '&', $header), $parts);
$expected = hash_hmac('sha256', $parts['t'] . '.' . $body, $secret);
return abs(time() - (int) $parts['t']) < 300 && hash_equals($expected, $parts['v1']);
}Връзки без код
За WooCommerce, Shopify и Stripe не е нужно програмиране. В Интеграции създайте връзка, копирайте адреса в платформата и поставете ключа за подпис. Новата връзка е в проба: поръчките само се проверяват и се виждат в дневника. Когато излизат както трябва, я пуснете на живо.
- WooCommerce: издава при избрания статус на поръчката; ЕИК, ДДС номер и МОЛ се вземат от полетата на българските добавки за фактури.
- Shopify: издава при платена поръчка; ЕИК и ДДС номер се вземат от допълнителните полета на поръчката.
- Stripe: издава при завършено плащане в Checkout и при платена фактура на Stripe.
Ако поръчка не може да се издаде (например липсва адрес), тя остава чернова и в дневника пише защо. Въпроси: info@bmail.bg.