code that your integration can evaluate without reading the message text.
Base URL
X-API-Key) and the same permissions as v1, plus the new currencies permission. Authentication, the rate limit and the business scope are identical.
v2 does not replace v1: it only exposes the endpoints that change. Everything else (customers, suppliers, products, inventory, the rest of HR, accounting, accounts receivable and payable, etc.) remains only in
/api/external/v1. An integration can use v1 and v2 at the same time with the same API Key.Available endpoints
The
currencies permission is assigned in External integrations, just like sales and expenses: an integration with full (inherited) access already includes it; one with selected permissions must have it checked. If you call a currency endpoint without it, you receive 403 with required_scope: "currencies".
What changes compared to v1
Within v2, the rest of the contract (sale and purchase fields, totals, cost centers, point of sale, etc.) is the same as in v1: see Sales and Purchases for the fields that don’t change.
How currency works
1
The business has a base currency
It is the currency in which FileXpress stores and posts everything. Query it with
GET /currencies (base_currency_code).2
You send the document in its currency
You pass
currency_code (for example GTQ) and all the document amounts (lines, taxes, payments and totals) in that currency. If you omit currency_code or send the base currency, the document is treated as in v1.3
The server converts to the base currency
It applies the document rate (the
exchange_rate sent, or the one in effect on the document date), validates the taxes and issues. The electronic tax document (DTE) is issued in the country’s legal currency, always in the base currency.0.128 for GTQ, 1 GTQ = 0.128 USD and 1,000 GTQ = 128.00 USD.
Safe retries with Idempotency-Key
If a POST /sales or POST /expenses request is cut off (timeout, network), you don’t know whether the document was created. Sending it again could duplicate it. To avoid this, add the Idempotency-Key header with a unique value per operation (for example, a UUID that you generate and store):
- The header is optional: without it everything works as before.
- The key is unique per integration and is remembered for 24 hours.
- Only successful responses (
2xx) and validation errors (422) are stored. If the server responds5xx, the key is released so you can retry with the same one. - The order of the JSON properties does not change the body fingerprint.
Errors and codes
Every v2 error response follows this format:errors is optional and its shape depends on the error: a field → message(s) object in validation and currencies, or a list of { field, code, message, tax_id? } objects in tax_invalid. Always evaluate code; the message text may change.
Responses generated by the access layer itself before reaching the endpoint (missing or invalid API Key, disabled integration, missing permission, rate limit) and the
404 for a resource that belongs to another business (for example, GET /sales/{id} with a foreign id) keep the { "status": false, "message": ... } format and may not include code. If code is missing, use the HTTP code (401, 403, 404, 429) as a fallback. The 403 for a missing permission adds required_scope.Next steps
Currencies and rates
Query active currencies and rates.
Sales
Issue sales in a foreign currency.
Purchases
Register purchases in a foreign currency.