Faktura1 API

Faktura1 Custom API v1

Тази документация е предназначена за клиенти и разработчици, които искат сами да свържат собствен сайт, ERP, CRM, онлайн магазин или друга система с Faktura1.

API-то позволява:

Адрес на 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"

Препоръчителен процес

  1. Създайте Custom API integration и запазете token-а.
  2. Извикайте GET /meta?lang_id=2.
  3. Покажете върнатите номенклатури като падащи менюта в настройките на вашата система.
  4. Запазете избраните internal_id стойности.
  5. Изпратете POST /documents.
  6. Запазете invoice_id, invoice_number, date_from, pdf_url и external_order_id.
  7. При повторение на 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 определя езика на имената в списъците:

Съкратен примерен 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-ът съдържа:

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=1 не се връщат.

Всеки документ съдържа managed_by_current_integration:

Поддържани 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