Issue a Proforma or Training document
post/v1/proforma-training-workflows
Scope proforma-training:writeRequires Idempotency-Key
A Proforma is an offer without tax effect; Training is practice. A Training Sale must not carry a reference; a refund must exactly repeat the source document and identify the buyer.
Contract notes (OpenAPI)
Accepts only Proforma or Training transactions through the dedicated workflow scope. Training Sale forbids a reference. Training Refund must reference an exact Boka-issued Training Sale. Proforma Sale may omit a reference or reference a Boka-issued Proforma Sale or Refund; Proforma Refund must reference a Boka-issued Proforma Sale. Refunds must exactly reproduce every source item and payment, identify the buyer, and only one unresolved or completed full refund may reserve a source. External and legacy references remain outside this bounded workflow. An unknown PFR outcome is terminal for automatic submission and an idempotent replay never creates a second fiscal request.
Request body application/json
| Field | Type | Description |
|---|---|---|
taxpayerIdrequired | uuid | |
businessPremiseIdrequired | uuid | |
clientReferencerequired | string | min 1max 200 |
invoiceTyperequired | string |
|
transactionTyperequired | TransactionType |
|
cashierrequired | Cashier | |
idrequired | string | |
displayNameoptional | string | |
buyeroptional | Buyer | |
idoptional | string | Official prefix and value, for example 10:123456789. |
optionalFieldoptional | string | Official buyer-cost-center prefix and value where applicable. |
originaloptional | BokaDocumentReference | |
sourcerequired | const "BOKA" | |
fiscalDocumentIdrequired | uuid | |
itemsrequired | array<LineItem> | min 1 items |
catalogProductIdoptional | uuid | Optional; arbitrary inline items are permitted. |
namerequired | string | min 1max 2048 |
unitOfMeasureoptional | string | Required on every item except the codebook advance literals (10: Аванс (Ђ) and siblings), which are prescribed verbatim without a unit. The API refuses any other item without one (422, Items.UnitOfMeasure) and composes it into the signed item name as name/unit. min 1max 50 |
quantityrequired | number | V-PFR Decimal(14,3). >= 0.001<= 99999999999.999step 0.001 |
unitPricerequired | number | Final gross unit price sent to V-PFR as Decimal(28,4). Boka applies the mandated fiscal rounding rules. >= 0step 0.01 |
unitPriceBeforeDiscountoptional | number | Optional Boka-local immutable gross unit price before discount. When present it must be greater than unitPrice; it is displayed outside the exact PFR journal and is never sent as a supplier field. >= 0step 0.0001 |
gtinoptional | string | min 8max 14 |
taxLabelsrequired | array<string> | min 1 itemsunique |
paymentsrequired | array<Payment> | min 1 items |
typerequired | PaymentType |
|
amountrequired | number | At most two decimals (the V-PFR rejects more with validation code 2804); the field type on the wire is Decimal(28,4). >= 0step 0.01 |
commercialFooteroptional | string | max 2000 |
metadataoptional | object | Non-fiscal caller metadata. |
Example
curl -X POST "https://api.bokapos.rs/v1/proforma-training-workflows" \
-H "Authorization: Bearer $BOKAPOS_TOKEN" \
-H "Idempotency-Key: quote-2210-proforma-1" \
-H "Content-Type: application/json" \
-d '{
"taxpayerId": "3f9c2a8e-6b1d-4e5a-9c47-1d2b8e6f0a11",
"businessPremiseId": "b7d4e2c1-9a3f-4c8e-8f21-6e5a0c9d3b22",
"clientReference": "QUOTE-2210",
"invoiceType": "PROFORMA",
"transactionType": "SALE",
"cashier": {
"id": "web-shop"
},
"buyer": {
"id": "10:106952811"
},
"items": [
{
"name": "Bluetooth slušalice",
"unitOfMeasure": "kom",
"quantity": 1,
"unitPrice": 8990,
"gtin": "8606012345678",
"taxLabels": [
"F"
]
}
],
"payments": [
{
"type": "WIRE_TRANSFER",
"amount": 8990
}
],
"commercialFooter": "Ponuda važi 7 dana."
}'Responses
| 200 OK | Idempotent replay of a completed workflowProformaTrainingWorkflow |
|---|---|
| 201 Created | Fiscalized Proforma or Training documentProformaTrainingWorkflow |
| 202 Accepted | The request is durably reserved but has not been submittedProformaTrainingWorkflow |
| 404 Not Found | Resource does not exist within the authenticated tenant scopeErrorCode |
| 409 Conflict | Idempotency, source-reservation, or terminal workflow conflict |
| 422 Unprocessable Content | The command violates a Boka or fiscal rule, or PFR definitively rejected the reserved operation |
| 503 Service Unavailable | No fiscal receipt is claimed; the workflow is unavailable or its outcome is unresolved |
{
"id": "0a1b2c3d-4e5f-4a6b-8c7d-8e9f0a1b2c3d",
"taxpayerId": "3f9c2a8e-6b1d-4e5a-9c47-1d2b8e6f0a11",
"businessPremiseId": "b7d4e2c1-9a3f-4c8e-8f21-6e5a0c9d3b22",
"clientReference": "QUOTE-2210",
"invoiceType": "PROFORMA",
"transactionType": "SALE",
"state": "COMPLETED",
"original": null,
"document": {
"id": "1b2c3d4e-5f6a-4b7c-8d9e-0f1a2b3c4d5e",
"taxpayerId": "3f9c2a8e-6b1d-4e5a-9c47-1d2b8e6f0a11",
"businessPremiseId": "b7d4e2c1-9a3f-4c8e-8f21-6e5a0c9d3b22",
"idempotencyKey": "quote-2210-proforma-1",
"clientReference": "QUOTE-2210",
"invoiceType": "PROFORMA",
"transactionType": "SALE",
"cashierId": "web-shop",
"buyerId": "10:106952811",
"buyerDetails": null,
"status": "FISCALIZED",
"fiscalized": true,
"failureCode": null,
"retryable": false,
"pfr": {
"invoiceNumber": "JWX4K9PL-JWX4K9PL-1047",
"sdcTime": "2026-09-01T10:15:32.483+02:00",
"requestedBy": "JWX4K9PL",
"signedBy": "JWX4K9PL",
"transactionTypeCounter": 902,
"totalCounter": 1047,
"invoiceCounterExtension": "ПрП",
"totalAmount": 8990,
"totalTax": 890.9009,
"verificationUrl": "https://sandbox.suf.purs.gov.rs/v/?vl=A0pXWDRLOVBMSldYNEs5UEwSBAAAEAQAAKCLPAAAAAAAAAABnAqJa1EAAAA...",
"journal": "============ ФИСКАЛНИ РАЧУН ============\n...\nПФР број рачуна: JWX4K9PL-JWX4K9PL-1047\nБројач рачуна: 902/1047ПрП\n========================================\n======== КРАЈ ФИСКАЛНОГ РАЧУНА ========="
},
"receipt": {
"textUrl": "/v1/fiscal-documents/1b2c3d4e-5f6a-4b7c-8d9e-0f1a2b3c4d5e/representations/official-text",
"jsonUrl": "/v1/fiscal-documents/1b2c3d4e-5f6a-4b7c-8d9e-0f1a2b3c4d5e/representations/canonical-json",
"pdfA4Url": "/v1/fiscal-documents/1b2c3d4e-5f6a-4b7c-8d9e-0f1a2b3c4d5e/representations/pdf-a4",
"pdf80mmUrl": "/v1/fiscal-documents/1b2c3d4e-5f6a-4b7c-8d9e-0f1a2b3c4d5e/representations/pdf-80mm",
"pdf58mmUrl": "/v1/fiscal-documents/1b2c3d4e-5f6a-4b7c-8d9e-0f1a2b3c4d5e/representations/pdf-58mm",
"previewImageUrl": "/v1/fiscal-documents/1b2c3d4e-5f6a-4b7c-8d9e-0f1a2b3c4d5e/representations/preview-png",
"qrImageUrl": "/v1/fiscal-documents/1b2c3d4e-5f6a-4b7c-8d9e-0f1a2b3c4d5e/representations/qr-svg",
"verificationUrl": "https://sandbox.suf.purs.gov.rs/v/?vl=A0pXWDRLOVBMSldYNEs5UEwSBAAAEAQAAKCLPAAAAAAAAAABnAqJa1EAAAA...",
"preferredPaperFormat": "a4"
},
"createdAt": "2026-09-01T08:15:31.902Z",
"updatedAt": "2026-09-01T08:15:32.611Z"
},
"failureCode": null,
"createdAt": "2026-09-02T07:02:10.000Z",
"updatedAt": "2026-09-02T07:02:11.204Z"
}Examples
training
curl -X POST "https://api.bokapos.rs/v1/proforma-training-workflows" \
-H "Authorization: Bearer $BOKAPOS_TOKEN" \
-H "Idempotency-Key: training-2026-09-02-1" \
-H "Content-Type: application/json" \
-d '{
"taxpayerId": "3f9c2a8e-6b1d-4e5a-9c47-1d2b8e6f0a11",
"businessPremiseId": "b7d4e2c1-9a3f-4c8e-8f21-6e5a0c9d3b22",
"clientReference": "TRAINING-1",
"invoiceType": "TRAINING",
"transactionType": "SALE",
"cashier": {
"id": "operater-1"
},
"items": [
{
"name": "Test artikal",
"unitOfMeasure": "kom",
"quantity": 1,
"unitPrice": 100,
"taxLabels": [
"F"
]
}
],
"payments": [
{
"type": "CASH",
"amount": 100
}
]
}'{
"id": "2c3d4e5f-6a7b-4c8d-9e0f-1a2b3c4d5e6f",
"taxpayerId": "3f9c2a8e-6b1d-4e5a-9c47-1d2b8e6f0a11",
"businessPremiseId": "b7d4e2c1-9a3f-4c8e-8f21-6e5a0c9d3b22",
"clientReference": "TRAINING-1",
"invoiceType": "TRAINING",
"transactionType": "SALE",
"state": "COMPLETED",
"original": null,
"document": {
"id": "3d4e5f6a-7b8c-4d9e-8f0a-1b2c3d4e5f6a",
"taxpayerId": "3f9c2a8e-6b1d-4e5a-9c47-1d2b8e6f0a11",
"businessPremiseId": "b7d4e2c1-9a3f-4c8e-8f21-6e5a0c9d3b22",
"idempotencyKey": "training-2026-09-02-1",
"clientReference": "TRAINING-1",
"invoiceType": "TRAINING",
"transactionType": "SALE",
"cashierId": "web-shop",
"buyerId": null,
"buyerDetails": null,
"status": "FISCALIZED",
"fiscalized": true,
"failureCode": null,
"retryable": false,
"pfr": {
"invoiceNumber": "JWX4K9PL-JWX4K9PL-1048",
"sdcTime": "2026-09-01T10:15:32.483+02:00",
"requestedBy": "JWX4K9PL",
"signedBy": "JWX4K9PL",
"transactionTypeCounter": 903,
"totalCounter": 1048,
"invoiceCounterExtension": "ОП",
"totalAmount": 100,
"totalTax": 9.9099,
"verificationUrl": "https://sandbox.suf.purs.gov.rs/v/?vl=A0pXWDRLOVBMSldYNEs5UEwSBAAAEAQAAKCLPAAAAAAAAAABnAqJa1EAAAA...",
"journal": "============ ФИСКАЛНИ РАЧУН ============\n...\nПФР број рачуна: JWX4K9PL-JWX4K9PL-1048\nБројач рачуна: 903/1048ОП\n========================================\n======== КРАЈ ФИСКАЛНОГ РАЧУНА ========="
},
"receipt": {
"textUrl": "/v1/fiscal-documents/3d4e5f6a-7b8c-4d9e-8f0a-1b2c3d4e5f6a/representations/official-text",
"jsonUrl": "/v1/fiscal-documents/3d4e5f6a-7b8c-4d9e-8f0a-1b2c3d4e5f6a/representations/canonical-json",
"pdfA4Url": "/v1/fiscal-documents/3d4e5f6a-7b8c-4d9e-8f0a-1b2c3d4e5f6a/representations/pdf-a4",
"pdf80mmUrl": "/v1/fiscal-documents/3d4e5f6a-7b8c-4d9e-8f0a-1b2c3d4e5f6a/representations/pdf-80mm",
"pdf58mmUrl": "/v1/fiscal-documents/3d4e5f6a-7b8c-4d9e-8f0a-1b2c3d4e5f6a/representations/pdf-58mm",
"previewImageUrl": "/v1/fiscal-documents/3d4e5f6a-7b8c-4d9e-8f0a-1b2c3d4e5f6a/representations/preview-png",
"qrImageUrl": "/v1/fiscal-documents/3d4e5f6a-7b8c-4d9e-8f0a-1b2c3d4e5f6a/representations/qr-svg",
"verificationUrl": "https://sandbox.suf.purs.gov.rs/v/?vl=A0pXWDRLOVBMSldYNEs5UEwSBAAAEAQAAKCLPAAAAAAAAAABnAqJa1EAAAA...",
"preferredPaperFormat": "a4"
},
"createdAt": "2026-09-01T08:15:31.902Z",
"updatedAt": "2026-09-01T08:15:32.611Z"
},
"failureCode": null,
"createdAt": "2026-09-02T07:10:00.000Z",
"updatedAt": "2026-09-02T07:10:01.100Z"
}Response: ProformaTrainingWorkflow
Field descriptions come from the OpenAPI contract; field names and values are identical in both languages.
| Field | Type | Description |
|---|---|---|
idrequired | uuid | |
taxpayerIdrequired | uuid | |
businessPremiseIdrequired | uuid | |
clientReferencerequired | string | |
invoiceTyperequired | string |
|
transactionTyperequired | TransactionType |
|
staterequired | string |
|
originaloptional | ProformaTrainingWorkflowOriginal| null (nullable) | |
sourcerequired | const "BOKA" | |
fiscalDocumentIdrequired | uuid | |
pfrNumberrequired | string | |
pfrTimerequired | date-time | |
invoiceTyperequired | string |
|
transactionTyperequired | TransactionType |
|
documentrequired | FiscalDocument | |
idrequired | uuid | |
taxpayerIdrequired | uuid | |
businessPremiseIdrequired | uuid | |
idempotencyKeyrequired | string | |
clientReferencerequired | string | |
invoiceTyperequired | InvoiceType |
|
transactionTyperequired | TransactionType |
|
cashierIdrequired | string | |
buyerIdoptional | string| null (nullable) | |
buyerDetailsoptional | FiscalBuyerDetails| null (nullable) | The buyer's company-registry facts stored with the document at reservation and printed under the buyer identification. Null when the buyer is not a domestic company (prefixes 10, 12, 14 with a valid PIB) or the register could not answer at issuance. |
legalNamerequired | string | max 350 |
taxIdentifierrequired | string | pattern ^[0-9]{9}$ |
registrationNumberoptional | string| null (nullable) | pattern ^[0-9]{8}$ |
addressoptional | string| null (nullable) | max 300 |
cityoptional | string| null (nullable) | max 100 |
sourcerequired | string |
|
resolvedAtrequired | date-time | |
statusrequired | FiscalDocumentStatus |
|
fiscalizedrequired | boolean | |
failureCodeoptional | string| null (nullable) | |
pfrRejectionoptional | object| null (nullable) | Present only on a single-document read of a REJECTED operation. The V-PFR's own validation result, bounded to the property path of the caller's request and the supplier's numeric codes (2310 invalid tax label; 2800 to 2808 required, length, range, value, format and list-size validation). Lists never carry it. |
itemsrequired | array<object> | max 10 items |
propertyrequired | string | max 120 |
codesrequired | array<string> | max 5 items |
retryablerequired | boolean | |
pfroptional | PfrResult| null (nullable) | |
invoiceNumberrequired | string | |
sdcTimerequired | date-time | |
requestedByrequired | string | |
signedByrequired | string | |
transactionTypeCounteroptional | integer| null (nullable) | V-PFR transaction-type counter (the left half of the printed counter). Null when the stored receipt does not carry it; the printed counter is always in the journal text. |
totalCounteroptional | integer| null (nullable) | V-PFR total counter (the right half of the printed counter and the last segment of invoiceNumber). Null under the same condition as transactionTypeCounter. |
invoiceCounterExtensionoptional | string| null (nullable) | Official Cyrillic invoice/transaction type pair printed after the counter (ПП, ПР, АП, АР, КП, КР, ОП, ОР, РП, РР). Null under the same condition as transactionTypeCounter. |
totalAmountrequired | number | |
totalTaxoptional | number| null (nullable) | Sum of the V-PFR signed tax amounts of the document (the printed "Укупан износ пореза" before its two-decimal display rounding). Null under the same condition as transactionTypeCounter. |
verificationUrlrequired | uri | |
journalrequired | string | |
receiptoptional | ReceiptRepresentations| null (nullable) | |
textUrlrequired | uri-reference | |
jsonUrlrequired | uri-reference | |
pdfA4Urlrequired | uri-reference | |
pdf80mmUrlrequired | uri-reference | |
pdf58mmUrlrequired | uri-reference | |
previewImageUrlrequired | uri-reference | |
qrImageUrlrequired | uri-reference | |
verificationUrlrequired | uri | |
preferredPaperFormatrequired | string | Immutable preferred print/PDF format captured when this fiscal operation was reserved.
|
referenceoptional | ResolvedReference | |
fiscalDocumentIdoptional | uuid | |
pfrNumberrequired | string | |
pfrTimerequired | date-time | |
createdAtrequired | date-time | |
updatedAtrequired | date-time | |
failureCodeoptional | string| null (nullable) | |
createdAtrequired | date-time | |
updatedAtrequired | date-time |