HTTP API
The FisCool driver embeds a RESTful HTTP server for device operations and system queries. The API is stateless and easy to integrate from any language that can make HTTP requests.
Base Configuration
- Default URL:
http://127.0.0.1:10123 - Host: default
127.0.0.1(localhost only); configurable in the FisCool settings (e.g.0.0.0.0to expose the API on the LAN). - Port: default
10123, configurable. - Enabled: the API server can be disabled entirely from settings (it is enabled by default).
- Content-Type:
application/jsonfor all POST requests. - Authentication: none. CORS is open, but see Browser access below.
Browser access (Origin check)
Requests that carry an Origin header (i.e. from a web page) are gated: the first time a new origin calls the API, FisCool shows a confirmation dialog to the operator ("Allow <origin> to interact with the fiscal devices?"). If accepted, the origin is persisted in the allow-list and never asked again; if rejected, the request fails with HTTP 403. Requests without an Origin header (curl, backend services) are not gated.
System Endpoints
GET /
Description: Health check.
Response: plain text
FisCool API Server running.
GET /status
Description: Returns the full application state snapshot: fiscal devices, POS terminals, API configuration, application configuration, active printers, licence summary. The fiscal_devices and pos_terminals arrays are identical to the dedicated endpoints below.
GET /devices/fiscal
Description: Lists all configured fiscal devices.
Response:
{
"fiscal_devices": [
{
"config": {
"id": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d", // configuration UUID - use as device_id
"name": "Casa 1 - DATECS DP25",
"manufacturer": "DATECS",
"model": "DP25",
"connection_details": {
"type": "Serial",
"details": { "port": "COM3", "baud_rate": 115200 }
},
"notes": "Main cash register",
"enabled": true,
"scan_folder": "C:\\FisCool\\INP", // optional: INP watch folder
"auto_send_card_to_pos": true, // optional features
"linked_pos_device_id": "b2c3d4e5-f6a7-5b8c-9d0e-1f2a3b4c5d6e",
"is_system_device": false
},
"status": "Connected", // Disconnected | Connecting | Connected | Disabled | {"Error": "..."}
"status_text": "Conectat",
"busy_external": false, // true while an external app holds the device
"vat_rates": { // VAT groups read from the device (basis points)
"A": 1900, "B": 900, "E": 0
},
"connected_device_id": "DT123456", // HARDWARE SERIAL - null while disconnected
"connected_device_data": {
"id": "DT123456", // hardware serial (same as connected_device_id)
"cif": "RO12345678", // company fiscal code programmed in the device
"print_width": 32 // printer characters per line (may be absent)
},
"scheduled_vat_rate_changes": [] // pending schedule_vat_rate_change entries
}
]
}
Note: connected_device_id/connected_device_data are populated only while the device is connected; they are null otherwise. config.id is the UUID used for operations - not the hardware serial.
GET /devices/pos
Description: Lists all configured POS terminals. Hybrid fiscal devices with a built-in POS also appear here (marked "is_virtual": true) once their POS serial is known.
Response:
{
"pos_terminals": [
{
"config": {
"id": "b2c3d4e5-f6a7-5b8c-9d0e-1f2a3b4c5d6e",
"name": "POS Terminal 1",
"manufacturer": "PAX",
"model": "A920 Pro",
"bank": "BCR",
"connection_details": {
"type": "Network",
"details": { "ip_address": "192.168.1.100", "port": 8080 }
},
"enabled": true
},
"status": "Connected",
"status_text": "Conectat",
"connected_device_id": "PAX001",
"connected_device_data": { "id": "PAX001", "cif": null },
"is_virtual": false
}
]
}
Device Operations
POST /devices/operation
Description: Executes a device operation on a fiscal device or POS terminal. This is the primary endpoint for all device interactions. All operations and their payloads are documented on the Device Operations page.
Request Headers
| Header | Required | Description |
|---|---|---|
Content-Type | Yes | application/json |
Idempotency-Key | No | Unique key preventing duplicate execution (see Idempotency). |
Request Body Structure
{
"device_id": "UUID", // target device UUID (config.id)
"operation": {
"type": "operation_name",
// ... operation-specific parameters
}
}
Complete Examples
Example 1: Print a Simple Receipt
POST /devices/operation
Content-Type: application/json
{
"device_id": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d",
"operation": {
"type": "print_receipt",
"lines": [
{
"type": "item",
"description": "Cafea Espresso",
"quantity_thousandths": 1000,
"unit_price_cents": 850,
"vat": "19%",
"um": "buc"
},
{
"type": "text",
"text": "Multumim pentru cumparaturi!"
}
],
"payments": [
{ "method": "cash", "amount_cents": 850 }
],
"close_action": "close"
}
}
Example 2: Receipt with Buyer Fiscal Code and Card Payment
POST /devices/operation
Content-Type: application/json
{
"device_id": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d",
"operation": {
"type": "print_receipt",
"lines": [
{
"type": "item",
"description": "Servicii Consultanta IT",
"quantity_thousandths": 1000,
"unit_price_cents": 120000,
"vat": "19%"
}
],
"payments": [
{ "method": "card", "amount_cents": 120000 }
],
"buyer": { "vat_number": "RO12345678" },
"flags": { "is_invoice": true },
"close_action": "close"
}
}
Example 3: Print a Z Report
{
"device_id": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d",
"operation": { "type": "print_z" }
}
Example 4: Cash Deposit
{
"device_id": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d",
"operation": { "type": "deposit_cash", "amount": 5000 }
}
Example 5: POS Sale
{
"device_id": "b2c3d4e5-f6a7-5b8c-9d0e-1f2a3b4c5d6e",
"operation": { "type": "sale", "amount": 2500, "suppress_print": false }
}
Example 6: Electronic Journal Report
{
"device_id": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d",
"operation": {
"type": "je_report",
"range": { "type": "date", "start": "2024-01-01", "end": "2024-01-31" },
"doc_type": "fiscal_receipts",
"output_mode": "read_line_by_line"
}
}
Response Format
Success (HTTP 200)
{
"status": 0,
"msg": "Receipt printed",
"slip_number": 1234,
"z_report_number": 45,
"fiscal_receipt_count": 1050
}
The exact fields depend on the operation - see Device Operations.
Error (HTTP 4xx/5xx)
Any failure - validation, connection, or an error reported by the device - is returned with a non-2xx HTTP status and this JSON body:
// HTTP 400 Bad Request - the device reported "no paper" (code 500)
{
"status": 500,
"error": "Lipsă hârtie în imprimantă."
}
// HTTP 404 Not Found - unknown device UUID
{
"status": 404,
"error": "Dispozitivul nu a fost găsit: a1b2c3d4-..."
}
// HTTP 400 Bad Request - declined POS sale, with the decline slip attached
{
"status": 600,
"error": "Tranzacție POS refuzată.",
"receipt": "...text of the decline slip..."
}
Important: the status field in the body is the application error code (always a positive integer - see Error Codes); it is not the HTTP status. Rely on the body's status/error for programmatic handling, and treat any non-200 HTTP response as a failure.
HTTP Status Mapping
| HTTP Status | When |
|---|---|
| 200 | Operation executed successfully (body has status: 0). |
| 400 | Invalid request/configuration (code 400) or an operational error reported by the device (most 5xx fiscal codes and 6xx POS codes). |
| 403 | Origin rejected by the operator. |
| 404 | Device not found (code 404). |
| 408 | Timeout (code 408). |
| 501 | Operation not supported by this device (code 1015). |
| 503 | Device not reachable/hardware unavailable (code 1004 and hardware-type fiscal codes such as 500, 502, 520…). |
| 500 | Internal errors (codes 1000-1003, …). |
Idempotency
For critical operations (receipt printing, POS sales) use the Idempotency-Key header to prevent duplicate execution on retries:
POST /devices/operation
Content-Type: application/json
Idempotency-Key: receipt-2024-01-15-001
{ "device_id": "...", "operation": { ... } }
All requests carrying the same key share a single execution - concurrent and later duplicates receive the same result without re-executing the operation.
Printing Endpoints
GET /printers
Description: Lists the system printers enabled (activated) in FisCool, with driver details.
Response:
{
"status": 0,
"printers": [
{ "name": "POS-80", "paper_width_mm": 80, "dpi": 203, "render_width_px": 576 }
]
}
POST /printers/print_html
Description: Renders HTML and prints it as a bitmap on an enabled system printer (thermal-printer pipeline). Printing to a printer that is not enabled in FisCool returns error 400.
Request Body:
{
"printer_name": "POS-80",
"html": "<h1>Hello</h1><p>Order #42</p>"
}
Response:
{
"status": 0,
"msg": "Print job completed"
}
Management Endpoints
The driver can also be managed programmatically (saving/deleting devices, journal queries, updates) via the /manage/* endpoints - see the Headless API page.
Integration Examples
cURL
# Print a simple receipt
curl -X POST http://127.0.0.1:10123/devices/operation \
-H "Content-Type: application/json" \
-d '{
"device_id": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d",
"operation": {
"type": "print_receipt",
"lines": [{"type": "item", "description": "Test", "quantity_thousandths": 1000, "unit_price_cents": 100, "vat": "19%"}],
"payments": [{"method": "cash", "amount_cents": 100}],
"close_action": "close"
}
}'
# List fiscal devices
curl http://127.0.0.1:10123/devices/fiscal
JavaScript / Node.js
const axios = require('axios');
async function printReceipt(deviceId, items, payments) {
try {
const response = await axios.post('http://127.0.0.1:10123/devices/operation', {
device_id: deviceId,
operation: {
type: 'print_receipt',
lines: items,
payments: payments,
close_action: 'close'
}
});
// HTTP 200 => success
console.log('Receipt printed, slip:', response.data.slip_number);
} catch (error) {
// non-2xx => failure; the body carries {status, error}
const body = error.response?.data;
console.error('Failed:', body?.status, body?.error);
}
}
Python
import requests
def print_receipt(device_id, items, payments):
url = "http://127.0.0.1:10123/devices/operation"
payload = {
"device_id": device_id,
"operation": {
"type": "print_receipt",
"lines": items,
"payments": payments,
"close_action": "close",
},
}
response = requests.post(url, json=payload)
if response.ok:
result = response.json()
print(f"Receipt printed: {result.get('slip_number')}")
else:
err = response.json()
print(f"Failed ({err.get('status')}): {err.get('error')}")
items = [{
"type": "item",
"description": "Coffee",
"quantity_thousandths": 1000,
"unit_price_cents": 250,
"vat": "19%",
}]
payments = [{"method": "cash", "amount_cents": 250}]
print_receipt("a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d", items, payments)