Fakturnia Developers Quickstart API reference Polski

Clients

A client is the buyer or receiver on your documents. The API exposes full CRUD under /clients, and when creating documents you can reference a client by id instead of sending their details every time.

Required scopes: clients:browse, clients:read, clients:create, clients:update, clients:delete (one per operation).

Listing clients

curl -s "https://prod.api.fakturnia.pl/external/v1/clients?searchQuery=Kowalski&currentPage=1&itemsPerPage=20" \
  -H "Authorization: Bearer $TOKEN"

searchQuery filters by name. The list is paginated: the response includes totalCount and totalPages.

Creating a client

A client is either a company (type: "company") or a person (type: "person"). A company requires name, a person requires firstName and lastName.

curl -s -X POST https://prod.api.fakturnia.pl/external/v1/clients \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "company",
    "name": "Przyklad Sp. z o.o.",
    "identifierType": "nip",
    "nip": "5252248481",
    "street": "ul. Prosta 1",
    "postalCode": "00-001",
    "city": "Warszawa",
    "countryCode": "PL",
    "email": "biuro@przyklad.pl"
  }'

The identifierType field says which identifier identifies the contractor in KSeF; the rules are in Contractor identifiers.

Everything else is optional: regon, krs, bdo, pesel, idNumber, address fields (street, postalCode, city, country, countryCode), contact fields (phoneNumber, email, emailAddresses, www, fax) and description.

For Polish companies you can fetch registry data automatically with the NIP lookup instead of retyping it.

Contractor identifiers

A KSeF invoice identifies the buyer (and the receiver) with exactly one identifier. identifierType picks which one, and the API checks it and stores it in the form KSeF accepts. The same rules apply to contractors (POST and PUT /clients) and to a buyer and receiver given as data when creating documents (POST /documents, POST /documents/validate, PUT and PATCH /documents/{id}).

identifierType Contractor Required fields Example In KSeF
nip Polish company nip "nip": "5261040828" NIP
vatEu company from another EU country vatUE with the country prefix a contractor from Germany: "identifierType": "vatEu", "vatUE": "DE123456789" KodUE + NrVatUE
other company outside the EU, or an EU company without a VAT UE number countryCode, otherTaxIdentifier "countryCode": "US", "otherTaxIdentifier": "12-3456789" KodKraju + NrID
idWew internal unit, only as the receiver of a document idWew "idWew": "5252248481-16006" IDWew
none consumer, or no identifier none "type": "person" BrakID

How the API stores identifiers:

  • NIP is 10 digits: spaces, dashes and the PL prefix are removed (PL 526-104-08-28 is stored as 5261040828), and the check digit must match.
  • The VAT UE number is stored in vatUE with its country prefix, in uppercase and without spaces (de 123 456 789 becomes DE123456789). A number without a prefix gets the prefix from countryCode. Greece uses the EL prefix in VAT numbers (a GR prefix is turned into EL), while countryCode stays GR. After the prefix, digits, uppercase letters, + and * are allowed, 1 to 12 characters. The nip field never holds a foreign number.
  • A Polish company with a VAT UE number (e.g. for intra-EU supply invoices) has identifierType: "nip", the NIP in nip and PL with the same NIP in vatUE.
  • Northern Ireland (XI) is not an EU country in KSeF: send it as other with countryCode: "XI".
  • other needs a country (countryCode, an ISO code such as US, CH, GB, UA) and an identifier of up to 50 characters; the identifier is stored as you send it.
  • idWew has the form NIP-NNNNN and belongs to a receiver only: a buyer with idWew gets an error.

When identifierType is missing

The API infers the type from the data and returns every inference in data.warnings, so the integration can start sending the type explicitly:

Data Inferred type What the API stores
nip with a Polish NIP (10 digits, also with PL, spaces or dashes) nip the NIP as 10 digits
nip with a VAT UE number of an EU country, e.g. DE123456789 vatEu the number in vatUE, an empty nip, countryCode from the prefix when missing
nip with a number without a prefix and the countryCode of an EU country other than Poland, e.g. 123456789 and DE vatEu vatUE = DE123456789
vatUE with the countryCode of an EU country other than Poland, or vatUE alone with an EU prefix vatEu the number in vatUE
vatUE alone with the PL prefix nip the NIP from the VAT UE number
nip or vatUE with a number of a non-EU country (e.g. GB…, XI…), or nip with a non-EU countryCode other the number in otherTaxIdentifier
otherTaxIdentifier alone other unchanged
idWew alone idWew unchanged
no identifier none unchanged

A Polish NIP with a wrong check digit is refused also when the type was inferred.

Warnings in the response

POST and PUT /clients return data.warnings next to data.client, and documents next to data.document (next to data.preview for validate). The list is empty when the identifiers were sent explicitly and correctly.

{
  "success": true,
  "data": {
    "client": { "identifierType": "vatEu", "nip": null, "vatUE": "DE123456789", "countryCode": "DE" },
    "warnings": [
      { "code": "IDENTIFIER_TYPE_INFERRED", "field": "identifierType", "message": "Nie podano identifierType: przyjęto vatEu (numer VAT UE). Podawaj identifierType jawnie." },
      { "code": "IDENTIFIER_MOVED", "field": "vatUE", "message": "Numer DE123456789 przeniesiono z pola nip do vatUE: pole nip jest tylko na polski NIP." },
      { "code": "COUNTRY_CODE_INFERRED", "field": "countryCode", "message": "Nie podano countryCode: przyjęto DE z prefiksu numeru VAT UE DE123456789." }
    ]
  }
}
code Meaning
IDENTIFIER_TYPE_INFERRED identifierType was missing and the API inferred it
IDENTIFIER_MOVED a number given in the wrong field was moved to vatUE or otherTaxIdentifier
IDENTIFIER_IGNORED a field that does not match the type was ignored (e.g. nip with vatEu)
COUNTRY_CODE_INFERRED countryCode was taken from the prefix of the number
VAT_UE_PREFIX_NORMALIZED the Greek prefix GR was turned into EL

On documents field carries the party prefix, e.g. buyer.vatUE. Messages are in Polish; branch on code.

Contradictions

The API refuses contradictions and names the field in errors: contractors with 422 VALIDATION_ERROR, documents with 422 PARTY_IDENTIFIER_INVALID (the field prefixed with buyer. or receiver.). Examples: identifierType: "nip" with DE123456789, vatEu with a PL… or XI… number, a VAT UE number without a prefix and without an EU country, a NIP with a wrong length or check digit, different VAT UE numbers in nip and vatUE, other without a country, idWew for a buyer, an unknown identifierType value.

A contractor saved earlier with data the API would not accept today stays editable: PUT does not re-check identifiers equal to the stored ones. A buyer given as data with the same wrong NIP as a saved contractor is taken from the contractor list.

Fetching, updating and deleting

# Details
curl -s https://prod.api.fakturnia.pl/external/v1/clients/{id} \
  -H "Authorization: Bearer $TOKEN"

# Update (PUT, full replacement)
curl -s -X PUT https://prod.api.fakturnia.pl/external/v1/clients/{id} \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "type": "company", "name": "Przyklad Sp. z o.o.", "email": "faktury@przyklad.pl" }'

# Delete
curl -s -X DELETE https://prod.api.fakturnia.pl/external/v1/clients/{id} \
  -H "Authorization: Bearer $TOKEN"

PUT is a full update: send the complete set of fields the client should have afterwards. Deleting a client does not change previously issued documents, the buyer details are preserved on them.

Webhooks

Write operations emit webhook events: client.created, client.updated, client.deleted.