Faktura1 Custom API v1
Тази документация е предназначена за клиенти и разработчици, които искат сами да свържат собствен сайт, ERP, CRM, онлайн магазин или друга система с Faktura1.
API-то позволява:
- създаване на фактура и проформа;
- създаване на кредитно известие към издадена фактура;
- проверка на създаден документ;
- намиране на документ по номер на поръчка от външната система;
- промяна на статус на плащане;
- изтриване на документ, когато бизнес правилата го позволяват;
- използване на фирмени номенклатури и custom mappings;
- получаване на PDF линкове за основен и втори език;
- изпращане на документа по имейл.
Адрес на API
Production base URL:
https://api.faktura1.com/api/v1
Всички endpoint-и в документацията са относителни спрямо този адрес.
Например:
GET https://api.faktura1.com/api/v1/meta
POST https://api.faktura1.com/api/v1/documents
Създаване на API достъп
Във Faktura1 се създава интеграция от:
Settings -> API integrations
За самостоятелно разработена връзка полето Source трябва да бъде:
custom
След създаването Faktura1 показва API token. Token-ът се показва само веднъж и трябва да бъде съхранен като парола.
Препоръчителни права:
| Scope | Предназначение |
|---|---|
documents:create |
Създаване на фактури, проформи и кредитни известия |
documents:read |
Преглед и търсене на документи |
documents:update |
Промяна на статус на плащане |
documents:delete |
Изтриване на документ |
mappings:read |
Преглед на custom mappings |
mappings:write |
Създаване и редактиране на custom mappings |
Не давайте documents:delete и mappings:write, ако интеграцията няма нужда от тях.
Authentication и HTTP headers
Всеки request трябва да съдържа:
Authorization: Bearer YOUR_API_TOKEN
Accept: application/json
Content-Type: application/json
X-Faktura-Integration: custom
При създаване на документ трябва да се изпрати и стабилен idempotency key:
Idempotency-Key: custom:invoice:order-10001
Пълен пример:
curl "https://api.faktura1.com/api/v1/meta?lang_id=2" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Accept: application/json" \
-H "X-Faktura-Integration: custom"
Препоръчителен процес
- Създайте
CustomAPI integration и запазете token-а. - Извикайте
GET /meta?lang_id=2. - Покажете върнатите номенклатури като падащи менюта в настройките на вашата система.
- Запазете избраните
internal_idстойности. - Изпратете
POST /documents. - Запазете
invoice_id,invoice_number,date_from,pdf_urlиexternal_order_id. - При повторение на request използвайте същия
Idempotency-Key.
Endpoint-и
| Method | Endpoint | Scope | Резултат |
|---|---|---|---|
GET |
/meta?lang_id=2 |
валиден token | Фирмени номенклатури и настройки |
GET |
/documents |
documents:read |
Връща всички активни документи на фирмата |
POST |
/documents |
documents:create |
Създава фактура или проформа |
GET |
/documents/{invoice_id} |
documents:read |
Връща документ по Faktura1 ID |
GET |
/documents/by-external/custom/{external_order_id} |
documents:read |
Намира документ по външна поръчка |
POST |
/documents/{invoice_id}/credit-note |
documents:create |
Създава кредитно известие |
PATCH |
/documents/{invoice_id}/payment-status |
documents:update |
Променя статус на плащане |
PATCH |
/documents/by-external/custom/{external_order_id}/payment-status |
documents:update |
Променя статус по външна поръчка |
DELETE |
/documents/{invoice_id} |
documents:delete |
Изтрива документа с hidden=1 |
GET |
/mappings |
mappings:read или mappings:write |
Връща custom mappings |
POST |
/mappings |
mappings:write |
Добавя или редактира mapping |
DELETE |
/mappings/{mapping_id} |
mappings:write |
Изключва mapping |
Номенклатури: GET /meta
ID стойностите за кочан, склад, банкова сметка и другите номенклатури са различни за всяка фирма. Не използвайте ID, взето от друга фирма или от пример в документацията.
Request:
GET /meta?lang_id=2
lang_id определя езика на имената в списъците:
1- English;2- Български;3- Română.
Съкратен примерен response:
{
"status": "success",
"data": {
"api": {
"base_url": "https://api.faktura1.com/api/v1",
"public_base_url": "https://api.faktura1.com",
"version": "v1"
},
"integration": {
"source": "custom",
"fallback_mode": "default_with_warnings",
"defaults": {
"kochan_id": 58,
"warehouse_id": 10,
"unit_id": 10,
"currency_id": 33,
"payment_type_id": 25,
"payment_status_id": 85,
"bank_account_id": 17
},
"scopes": [
"documents:create",
"documents:read"
]
},
"currencies": [
{
"id": 33,
"code": "EUR",
"name": "Euro",
"is_default": 1
}
],
"units": [
{
"id": 10,
"code": "pcs",
"name": "бр.",
"is_default": 1
}
],
"vat_rates": [
{
"id": 0,
"name": "ДДС 20%",
"vat_percent": 20,
"is_default": 1
}
],
"languages": [
{
"id": 1,
"code": "en",
"name": "English"
},
{
"id": 2,
"code": "bg",
"name": "Български"
}
]
}
}
Response-ът съдържа:
invoice_books;units;currencies;payment_methods;payment_statuses;bank_accounts;vat_rates;warehouses;languages;mappings.
API-то валидира всяко подадено internal_id спрямо типа, фирмата и правата на потребителя. Например ID на банкова сметка не може да бъде използвано като склад и банкова сметка от друга фирма не може да бъде подадена с чужд token.
Два начина за подаване на номенклатура
Вариант A: internal_id
Това е препоръчителният вариант. ID-то се взема от /meta и се пази в настройките на интеграцията.
{
"currency": {
"internal_id": 33
},
"payment_method": {
"internal_id": 25
}
}
Вариант B: external_code и custom mapping
Подходящ е, когато външната система има собствени кодове, например cod, bank, paid или piece.
{
"payment_method": {
"external_code": "cod"
},
"payment_status": {
"external_code": "paid"
}
}
Преди използването тези кодове трябва да бъдат свързани с Faktura1 стойности в настройките на Custom API integration или чрез /mappings.
Поддържани map_type стойности:
invoice_book
unit
currency
payment_method
payment_status
language
vat_rate
warehouse
bank_account
Създаване на фактура
Endpoint:
POST /documents
Примерните ID стойности по-долу са само илюстративни. Използвайте ID стойностите от вашия /meta response.
{
"external_order_id": "order-10001",
"type": "invoice",
"issue_date": "2026-07-27",
"tax_date": "2026-07-27",
"due_date": "2026-08-03",
"currency": {
"internal_id": 33
},
"currency_en": {
"internal_id": 33
},
"payment_method": {
"internal_id": 25
},
"payment_status": {
"internal_id": 85
},
"invoice_book": {
"internal_id": 58
},
"bank_account": {
"internal_id": 17
},
"warehouse": {
"internal_id": 10
},
"vat_rate": {
"internal_id": 0
},
"lang_id": 2,
"lang2_id": 1,
"send_email": true,
"email_to": "client@example.com",
"round_numbers": 2,
"customer": {
"name": "Примерна фирма ООД",
"reg_number": "123456789",
"vat_id": "BG123456789",
"country_code": "BG",
"city": "София",
"postcode": "1000",
"address": "ул. Пример 1",
"mol": "Иван Иванов",
"email": "client@example.com",
"is_person": false
},
"items": [
{
"product_id": 1001,
"name": "Абонаментна услуга",
"description": "Месечен абонамент",
"quantity": "1",
"unit": {
"internal_id": 10
},
"unit_price": "100.00",
"unit_price_includes_vat": false,
"discount_percent": "0",
"vat_rate": {
"internal_id": 0
},
"vat_percent": "20",
"total": "100.00"
}
],
"totals": {
"total_no_vat": "100.00",
"total_vat": "20.00",
"total": "120.00"
},
"short_comment": "Поръчка order-10001",
"comment": "Създадена автоматично от клиентска система"
}
Пример с cURL:
curl -X POST "https://api.faktura1.com/api/v1/documents" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-H "X-Faktura-Integration: custom" \
-H "Idempotency-Key: custom:invoice:order-10001" \
--data @invoice.json
Задължителни данни
| Поле | Забележка |
|---|---|
external_order_id |
Уникален номер на поръчката във външната система |
type |
invoice или proforma |
customer.name |
Име на фирма или физическо лице |
customer.reg_number |
Задължително за фирма |
customer.is_person |
false за фирма, true за физическо лице |
items |
Поне един ред |
items[].name |
Име на продукта/услугата |
items[].quantity |
Не може да бъде нула |
items[].unit |
Или валидна default unit в integration настройките |
currency |
Или валидна default currency |
payment_method |
Или валиден default payment method |
payment_status |
Или валиден default payment status |
invoice_book |
Задължителен за фактура, освен ако има default invoice book |
issue_date по подразбиране е текущата дата. tax_date по подразбиране е равна на issue_date, но е препоръчително и двете да се подават изрично.
totals е незадължителен. Ако бъде подаден, API-то го сравнява с изчислените стойности от редовете и връща TOTALS_MISMATCH при съществена разлика.
Фирма
За фирма:
{
"customer": {
"name": "Примерна фирма ООД",
"reg_number": "123456789",
"vat_id": "BG123456789",
"country_code": "BG",
"city": "София",
"postcode": "1000",
"address": "ул. Пример 1",
"mol": "Иван Иванов",
"email": "office@example.com",
"is_person": false
}
}
Задължителни са name и reg_number. vat_id и mol са незадължителни. Държава, град, пощенски код и адрес е препоръчително да се подават винаги.
Физическо лице
{
"customer": {
"name": "Иван Петров",
"country_code": "BG",
"city": "София",
"address": "ул. Пример 2",
"email": "ivan@example.com",
"is_person": true
}
}
При is_person: true може да не се подава reg_number.
Създаване на проформа
Използва се същият endpoint:
POST /documents
Основната разлика е:
{
"external_order_id": "order-10001-proforma",
"type": "proforma"
}
Проформа не изисква invoice_book. Останалите данни за клиент, валута, плащане и редове са същите.
Препоръчителен idempotency key:
custom:proforma:order-10001
Езици и изпращане по имейл
lang_id е основният език на документа.
lang2_id е вторият език. Ако е различен от основния, response-ът съдържа и links.pdf_secondary.
Пример:
{
"lang_id": 2,
"lang2_id": 1,
"currency_en": {
"internal_id": 33
},
"send_email": true,
"email_to": "client@example.com"
}
Ако езикът на клиента не присъства в /meta.languages, използвайте английския език с code: "en".
При send_email: true и валиден получател документът се добавя в опашката за изпращане. Когато има втори език, към клиента се изпраща вторичната езикова версия.
Допълнителни полета:
{
"email_to": "client@example.com",
"email_copy": "accounting@example.com",
"email_subject": "Фактура за поръчка order-10001",
"email_description": "Благодарим за поръчката."
}
Успешен response при създаване
Нов документ връща HTTP 201 Created:
{
"status": "success",
"data": {
"invoice_id": 2075501,
"document_type": "invoice",
"parent_invoice_id": 2075501,
"for_invoice_id": 0,
"invoice_number": 300000021,
"date_from": "2026-07-27",
"date_danuchno": "2026-07-27",
"lang_id": 2,
"lang2_id": 1,
"currency_id": 33,
"currency_id_en": 33,
"totals": {
"total_no_vat": 100,
"total_vat": 20,
"total": 120
},
"hidden": 0,
"accounted_status": 0,
"payment_status_id": 85,
"managed_by_current_integration": true,
"external_order_id": "order-10001",
"external_refund_id": "",
"idempotency_key": "custom:invoice:order-10001",
"pdf_url": "https://www2.faktura1.com/view-pdf/ENCRYPTED_VALUE",
"links": {
"pdf": "https://www2.faktura1.com/view-pdf/ENCRYPTED_VALUE",
"pdf_original": "https://www2.faktura1.com/view-pdf/ENCRYPTED_VALUE",
"pdf_copy": "https://www2.faktura1.com/view-pdf/ENCRYPTED_VALUE",
"pdf_secondary": "https://www2.faktura1.com/view-pdf/ENCRYPTED_VALUE",
"pdf_secondary_copy": "https://www2.faktura1.com/view-pdf/ENCRYPTED_VALUE"
},
"idempotent": false,
"warnings": [],
"email_queued": true
}
}
Във външната система трябва да се запазят поне:
data.invoice_id
data.invoice_number
data.date_from
data.external_order_id
data.pdf_url
invoice_id е вътрешният уникален ID на записа. Номерът, който трябва да се показва на потребителя, е invoice_number, заедно с date_from.
Защита от дублиране
Използвайте един и същ Idempotency-Key при повторен опит за същата операция.
custom:invoice:order-10001
Ако request-ът се повтори със същия key и същия payload, API-то връща съществуващия документ с HTTP 200:
{
"status": "success",
"data": {
"invoice_id": 2075501,
"invoice_number": 300000021,
"idempotent": true,
"matched_by": "idempotency_key"
}
}
Ако същият key бъде използван с различен payload:
{
"status": "error",
"code": "IDEMPOTENCY_CONFLICT",
"message": "Idempotency-Key was already used with different payload."
}
Списък с издадени документи
Endpoint:
GET /documents
Този endpoint връща:
- активни документи с
hidden=0; - документи на фирмата, към която принадлежи API token-ът;
- документи независимо дали са създадени ръчно, от текущата API интеграция или от друга интеграция.
Документи на друга фирма и изтрити документи с hidden=1 не се връщат.
Всеки документ съдържа managed_by_current_integration:
true- документът е създаден и се управлява от текущата API интеграция;false- документът може да бъде прочетен, но не може да бъде променян, изтриван или използван за кредитно известие от текущата интеграция.
Поддържани query параметри:
| Параметър | По подразбиране | Описание |
|---|---|---|
page |
1 |
Номер на страницата, започващ от 1 |
limit |
50 |
Брой записи; максималната използвана стойност е 100 |
type |
всички | invoice, proforma, credit_note или stock |
date_from |
няма | Документи с дата от тази дата включително |
date_to |
няма | Документи с дата до тази дата включително |
external_order_id |
няма | Точно съвпадение по външна поръчка на текущата интеграция |
invoice_number |
няма | Точно съвпадение с номера на документа |
reg_number |
няма | Точно съвпадение с contractors.reg_number (Булстат/ЕИК на клиента) |
payment_status |
няма | Точно съвпадение с един активен код от GET /meta → payment_statuses |
Датите могат да бъдат подадени като YYYY-MM-DD, например 2026-07-01. Резултатите са подредени от най-новите към най-старите.
Пример за всички активни документи, издадени на клиент с Булстат/ЕИК 123456789:
GET /documents?reg_number=123456789
reg_number се сравнява точно. Когато съдържа букви или други специални знаци, стойността трябва да бъде URL encoded.
Пример за документи с един платежен статус:
GET /documents?payment_status=paid
Подаваният payment_status трябва да е един код от GET /meta, полето data.payment_statuses. Не се приемат няколко статуса или списък със стойности. При непознат или неактивен код API-то връща HTTP 422 с code: "INVALID_PAYMENT_STATUS".
Примерно извикване:
curl --request GET \
--url "https://api.faktura1.com/api/v1/documents?page=1&limit=20&type=invoice&date_from=2026-07-01&date_to=2026-07-31" \
--header "Authorization: Bearer YOUR_API_TOKEN" \
--header "X-Faktura-Integration: custom" \
--header "Accept: application/json"
Съкратен примерен response:
{
"status": "success",
"data": {
"documents": [
{
"invoice_id": 2075501,
"document_type": "invoice",
"invoice_number": 300000021,
"date_from": "2026-07-25",
"totals": {
"total_no_vat": 100,
"total_vat": 20,
"total": 120
},
"hidden": 0,
"managed_by_current_integration": true,
"external_order_id": "order-10001",
"pdf_url": "https://www2.faktura1.com/view-pdf/..."
}
],
"pagination": {
"page": 1,
"limit": 20,
"total_items": 1,
"total_pages": 1,
"has_next_page": false,
"has_previous_page": false
},
"filters": {
"type": "invoice",
"date_from": "2026-07-01",
"date_to": "2026-07-31",
"external_order_id": null,
"invoice_number": null,
"reg_number": null,
"payment_status": "paid"
}
}
}
При ръчно създаден документ managed_by_current_integration е false, а external_order_id, external_refund_id и idempotency_key са null.
С готовия PHP клиент:
$response = $api->listDocuments([
'page' => 1,
'limit' => 20,
'type' => 'invoice',
'date_from' => '2026-07-01',
'date_to' => '2026-07-31',
'reg_number' => '123456789',
'payment_status' => 'paid',
]);
foreach ($response['data']['documents'] as $document) {
echo $document['invoice_number'] . PHP_EOL;
echo $document['pdf_url'] . PHP_EOL;
}
Преглед на документ
По invoice_id:
GET /documents/2075501
Това извикване може да върне всеки активен документ на фирмата, независимо как е създаден.
По външен номер на поръчка:
GET /documents/by-external/custom/order-10001
Path стойностите трябва да бъдат URL encoded.
Търсенето по външен номер остава ограничено до текущата API интеграция, защото ръчно създадените документи нямат external_order_id. Изтритите документи са с hidden=1 и не се връщат от тези endpoint-и.
Промяна на статус на плащане
По invoice_id:
PATCH /documents/2075501/payment-status
{
"payment_status": {
"internal_id": 86
}
}
По външен номер на поръчка:
PATCH /documents/by-external/custom/order-10001/payment-status
{
"document_type": "invoice",
"payment_status": {
"external_code": "paid"
}
}
Изтриване на документ
DELETE /documents/2075501
При успешно изтриване API-то задава hidden=1 и връща документа с:
{
"status": "success",
"data": {
"invoice_id": 2075501,
"invoice_number": 300000021,
"hidden": 1
}
}
Осчетоводен документ не може да бъде изтрит и връща:
{
"status": "error",
"code": "DOCUMENT_ACCOUNTED",
"message": "Accounted document cannot be deleted."
}
След изтриване може да бъде създаден нов документ със същия external_order_id. Скритият запис няма да бъде използван повторно.
Създаване на кредитно известие
POST /documents/2075501/credit-note
{
"external_refund_id": "refund-5001",
"issue_date": "2026-07-28",
"comment": "Върната стока",
"items": [
{
"name": "Абонаментна услуга",
"quantity": "1",
"unit": {
"internal_id": 10
},
"unit_price": "100.00",
"vat_percent": "20",
"total": "100.00"
}
],
"totals": {
"total_no_vat": "100.00",
"total_vat": "20.00",
"total": "120.00"
}
}
Липсващите данни за клиент, плащане, валута и кочан се наследяват от фактурата. Използвайте отделен idempotency key:
custom:credit-note:refund-5001
Custom mappings
Mappings са налични само за integration със Source: custom.
Създаване или редактиране:
POST /mappings
{
"map_type": "payment_method",
"external_code": "cod",
"external_label": "Cash on delivery",
"internal_id": 25,
"is_default": false
}
Примерен response:
{
"status": "success",
"data": {
"api_mapping_id": 501,
"map_type": "payment_method",
"external_code": "cod",
"external_label": "Cash on delivery",
"internal_id": 25,
"is_default": 0,
"status": 1
}
}
След това документ може да подаде:
{
"payment_method": "cod"
}
или:
{
"payment_method": {
"external_code": "cod"
}
}
Грешки
Всички грешки имат единен формат:
{
"status": "error",
"code": "INVALID_NOMENCLATURE_ID",
"message": "Invalid internal nomenclature id.",
"details": {
"field": "bank_account",
"map_type": "bank_account",
"internal_id": 99999
}
}
Основни HTTP status кодове:
| HTTP status | Значение |
|---|---|
200 |
Успешен request или idempotent повторение |
201 |
Нов документ е създаден |
400 |
Невалиден JSON/request |
401 |
Липсващ или невалиден token |
403 |
Липсващо право, грешен source или забранено IP |
404 |
Документът не е намерен или е изтрит |
409 |
Конфликт, дублиране или бизнес ограничение |
422 |
Невалидни полета, номенклатури или суми |
500 |
Вътрешна грешка |
Често срещани code стойности:
AUTHORIZATION_MISSING
TOKEN_INVALID
INTEGRATION_DISABLED
INTEGRATION_SOURCE_MISMATCH
IP_NOT_ALLOWED
SCOPE_FORBIDDEN
INVALID_JSON
EXTERNAL_ORDER_ID_REQUIRED
INVALID_DOCUMENT_TYPE
INVALID_PAYMENT_STATUS
CUSTOMER_NAME_REQUIRED
CUSTOMER_REG_NUMBER_REQUIRED
DOCUMENT_LINES_REQUIRED
INVALID_NOMENCLATURE_ID
NOMENCLATURE_NOT_MAPPED
TOTALS_MISMATCH
IDEMPOTENCY_CONFLICT
DOCUMENT_NOT_FOUND
DOCUMENT_NOT_OWNED_BY_INTEGRATION
DOCUMENT_ACCOUNTED
DOCUMENT_NUMBER_EXISTS
INVOICE_BOOK_FULL
Клиентският код трябва да проверява едновременно HTTP status и JSON полето status.
Готов PHP клиент
Готовият framework-independent PHP клиент е:
docs/api-public/examples/Faktura1ApiClient.php
Той предоставя методи за:
$api->getMeta();
$api->listDocuments();
$api->createDocument();
$api->getDocument();
$api->findDocument();
$api->createCreditNote();
$api->updatePaymentStatus();
$api->updatePaymentStatusByExternal();
$api->deleteDocument();
$api->getMappings();
$api->saveMapping();
$api->deleteMapping();
Минимална употреба:
<?php
require_once __DIR__ . '/Faktura1ApiClient.php';
$api = new Faktura1ApiClient(
'YOUR_API_TOKEN',
'custom',
'https://api.faktura1.com/api/v1'
);
$response = $api->createDocument(
$payload,
'custom:invoice:order-10001'
);
$document = $response['data'];
echo $document['invoice_number'];
echo $document['pdf_url'];
Пълният работещ пример е:
docs/api-public/examples/create-document.php
PowerShell:
$env:F1_API_TOKEN = "YOUR_API_TOKEN"
$env:F1_EXTERNAL_ORDER_ID = "order-10001"
$env:F1_SEND_EMAIL = "0"
php docs/api-public/examples/create-document.php invoice
php docs/api-public/examples/create-document.php proforma
Linux/macOS:
export F1_API_TOKEN="YOUR_API_TOKEN"
export F1_EXTERNAL_ORDER_ID="order-10001"
export F1_SEND_EMAIL="0"
php docs/api-public/examples/create-document.php invoice
php docs/api-public/examples/create-document.php proforma
За реална интеграция заменете demo customer/items данните в примера с данните от поръчката. external_order_id и Idempotency-Key трябва да останат стабилни при повторен опит.
Production checklist
- Token-ът не се записва в публичен source control.
- Използва се HTTPS.
- Token-ът е с минимално необходимите scopes.
- По възможност са зададени
Allowed IPs. - Номенклатурите се вземат от
/meta. - Запазва се
invoice_id, а на потребителя се показватinvoice_numberиdate_from. - Всеки write request използва стабилен
Idempotency-Key. - Обработват се HTTP грешките и JSON полето
code. - При timeout request-ът се повтаря със същия idempotency key.
- Изтритите документи не се приемат за активни.
- Token-ът се регенерира при съмнение за компрометиране.