Skip to main content
POST
Create/update invoice

Calendar dates

Send basicInformation.issueDate, basicInformation.saleDate, payments.dueDate and optional payments.paymentDate as strings in YYYY-MM-DD format, for example "2026-09-14". These fields represent calendar dates without a time or time zone. Do not convert them to UTC or serialize them with toISOString(). For example, if the invoice date is September 15, send "2026-09-15", rather than "2026-09-14T22:00:00Z". Use the same date regardless of the client’s time zone. Timestamps representing an event time have different semantics and can include a time zone. Legacy date-time inputs may still be accepted for compatibility. Non-midnight values can be converted to the calendar date in Europe/Warsaw; the save response does not include a warning about that conversion. With strict date validation enabled, non-midnight date-time values are rejected with HTTP 400 and validationErrors[].code = "DATE_REQUIRES_LOCAL_DATE". Legacy midnight values are still accepted without changing their written date. Always send YYYY-MM-DD for new integrations. Validation errors include an English description in errorMessage, a Polish description in errorMessagePL, and the affected field in validationErrors[].field.

VAT-exempt invoices

If at least one invoice item uses the "vat": "zw" rate, provide vatExemptionReason at the top level of the request, alongside invoicePosition, additionalDetails, and payments. The field accepts exactly one of these three values:
  • Zwolnienie podmiotowe z art. 113 ust. 1 i 9
  • Zwolnienie przedmiotowe z art. 43 ust. 1
  • Zwolnienie przedmiotowe z art. 82 ust. 3
vatExemptionReasonDetailed is optional. It accepts up to 500 characters of additional wording displayed on the invoice below the selected legal basis. It does not replace vatExemptionReason. Altera submits vatExemptionReason to KSeF as P_19A. The following request fragment shows an invoice item using the zw rate:
When updating an existing invoice, use the same fields and provide the document identifier in basicInformation.invoiceId. If the invoice has no item using the zw rate, omit both fields.

Separate recipients and other additional parties

Keep the buyer in contractor. Add a separate recipient to the top-level additionalParties array, alongside contractor, basicInformation and payments. These are structured invoice parties (Podmiot3 in KSeF), rather than text in additionalDetails or contractor.houseNumber. The following request fragment adds a recipient. Replace the illustrative name, address and tax identity with the actual party data:
semanticRole accepts the following values: Use RECIPIENT for an ordinary separate recipient. Do not automatically select JST_RECIPIENT just because the recipient is a school: choose the role that matches the actual local government arrangement, because it changes the KSeF mapping. internalId is optional. When used, send a string containing exactly five digits, including any leading zeros. It is the suffix, not the complete KSeF identifier. For Podmiot3 export it requires a Polish 10-digit NIP and Polish country; the example produces IDWew equal to 5260250274-00123. Omit internalId when the party does not use an internal identifier. Address fields belong to this additional party. houseNumber contains only the building number (maximum 20 characters), and postCode contains the postal code. Do not combine buyer and recipient addresses in one field. For an update, provide basicInformation.invoiceId together with the intended invoice data and additional parties. This does not retroactively correct previously issued documents; invoices already submitted to or accepted by KSeF have content-edit restrictions and may require a correction invoice. The legacy alias additionalContractors is also accepted; use additionalParties for new integrations and avoid sending both.

Assigning a project to an invoice

Use the singular top-level project object in POST /sales/invoice, alongside basicInformation, contractor and payments. One project is assigned to the invoice. The following fragment must be combined with the remaining invoice data:
Use the actual project object from the same company. tagId identifies the existing project; name, enabled and color are also required by invoice validation. Sending only { "tagId": 161 } is insufficient. The name must be nonempty, enabled is a boolean, and color is the project’s numeric ARGB value (4278190080–4294967295). Fetch existing projects using List projects (GET /company/projects, or GET /company/projects?onlyActive=1 for active projects), find the desired project by name in data, and use its complete object as project. Saving an invoice does not create a project from its name. If necessary, first create the project using Add/modify a project (POST /company/projects), then use the returned project data including its tagId when saving the invoice. For an existing invoice, include basicInformation.invoiceId and the intended invoice data:
  • To retain the assignment, send the current project again.
  • To change it, send the new project object.
  • To remove it, omit project from the update payload. This endpoint is not a partial PATCH that preserves every omitted field. project: null is not accepted.
The sales save flow copies the header project to all invoice line items, replacing line-level project values. Removing the header project also clears line-level assignments. Set the project at the invoice level rather than trying to assign different projects per sales line. Do not send projects: [], an array of projects, or a project name as a plain string. The current request validator expects project to be an object and rejects the unknown top-level field projects.

Immediate KSeF submission

Set the top-level boolean sendToKSEF to true to request submission during the save flow, after the invoice has been persisted. To issue a new invoice and request immediate submission, use this fragment together with the remaining required buyer, line-item and payment data:
  • The default is false. Omitting the flag or sending false does not request immediate submission, but does not disable normal automatic KSeF processing. Eligible invoices can still enter the pending workflow.
  • The flag does not issue a draft. The invoice must be ISSUED or SENT; a draft is not submitted.
  • KSeF integration and outgoing submission must be enabled for the company. The flag does not override company settings, private-person invoice policy or KSeF validation. If the integration or outgoing submission is disabled, the save flow can skip submission without returning a KSeF warning.
  • sendToKSEF: true is rejected for PRO_FORMA, ORDER and DEBIT_NOTE.
  • The compatibility spelling sendToKsef is also accepted. Prefer sendToKSEF; if both are sent, their values must agree.

Save success is not KSeF acceptance

A normal save returns HTTP 200 with the saved invoice identifier:
When immediate submission returns an unsuccessful result after saving, the endpoint still returns HTTP 200 and result: "OK", with optional KSeF details. For example:
Inspect ksefWarning, ksefErrorMessage and ksefReason even on HTTP 200. Reason codes are an open set; another possible value is KSEF_SUBMISSION_FAILED. Absence of these fields is not proof of KSeF acceptance. Retrieve the saved invoice through Get invoice data and inspect ksef.ksefStatus, ksef.ksefId and any ksef.ksefErrorMessage. Keep the returned invoiceId. Do not create the same invoice again because KSeF submission failed. Resolve the KSeF issue and use the existing invoice’s submission/retry workflow. For request validation errors, correct the input before retrying; do not repeatedly resend the same invalid payload. This warning response describes unsuccessful submission results after save; other validation or processing failures can still return an error response.

Authorizations

Authorization
string
header
required

OpenApi Key created within Altera.app for a certain company

Body

application/json
override
boolean
default:false

Defines whether we wish to override split payments warning, in Machine-machine integrations should be set to true

sendToKSEF
boolean
default:false

Request immediate KSeF submission after saving an eligible ISSUED or SENT invoice. Defaults to false; false does not disable normal automatic KSeF processing. Requires KSeF and outgoing submission enabled for the company and an eligible invoice. Does not issue a DRAFT or guarantee KSeF acceptance. Inspect data.ksefWarning, data.ksefErrorMessage and data.ksefReason even on HTTP 200, then check the saved invoice KSeF status. Not allowed for PRO_FORMA, ORDER or DEBIT_NOTE. See the endpoint guide for examples and retry handling.

basicInformation
object
contractor
object
invoicePosition
object[]
additionalDetails
string

Describes extra information that we wish to present on the invoice

correctionReason
string

Additional information regarding the reason behing correcting your invoice

vatExemptionReason
enum<string>

Required when at least one invoicePosition item uses the zw VAT rate. The selected value is used as the VAT exemption legal basis and is submitted to KSeF as P_19A.

Available options:
Zwolnienie podmiotowe z art. 113 ust. 1 i 9,
Zwolnienie przedmiotowe z art. 43 ust. 1,
Zwolnienie przedmiotowe z art. 82 ust. 3
Maximum string length: 50
vatExemptionReasonDetailed
string

Optional detailed wording shown on the invoice below vatExemptionReason. It does not replace the required vatExemptionReason value.

Maximum string length: 500
payments
object
additionalParties
object[]

Additional parties, including a separate recipient (Podmiot3). Each entry is a snapshot; contractor continues to identify the buyer.

project
object

Single project assigned to the invoice. Pass an existing project from the same company, including tagId, name, enabled and color. Assignment is persisted by tagId; saving an invoice does not create a project. On update, resend project to retain the assignment; omitting it removes the assignment. The header project is propagated to sales line items. Use project, not projects.

Example:

Response

Invoice saved. HTTP 200 confirms the save, not acceptance by KSeF. A failed immediate submission can be reported in optional data.ksefWarning, data.ksefErrorMessage and data.ksefReason fields.

Regular format of success response in Altera API Retrieved information will always be stored in the 'data' node

data
object
result
enum<string>
default:OK
Available options:
OK
Example:

"OK"