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.0 to 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/json for 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
HeaderRequiredDescription
Content-TypeYesapplication/json
Idempotency-KeyNoUnique 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 StatusWhen
200Operation executed successfully (body has status: 0).
400Invalid request/configuration (code 400) or an operational error reported by the device (most 5xx fiscal codes and 6xx POS codes).
403Origin rejected by the operator.
404Device not found (code 404).
408Timeout (code 408).
501Operation not supported by this device (code 1015).
503Device not reachable/hardware unavailable (code 1004 and hardware-type fiscal codes such as 500, 502, 520…).
500Internal 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)