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, printed as Опционо поље купца. Allowed only on a Normal Sale: any other invoice type or transaction type is rejected with 422, because the official manual testing procedure lists the field appearing on a receipt that is not a Промет Продаја as a reason to reject an ESIR. A Copy of a Normal Sale that carried it is issued without it for the same reason, and closing an advance case applies it only to the final Normal Sale, never to the closing Advance Refund. |
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 |