Pre-allocate numbers for offline emission
curl --request POST \
--url https://api.contazen.ro/v1/invoice-series/{id}/reserve-numbers \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '{
"count": 10
}'import requests
url = "https://api.contazen.ro/v1/invoice-series/{id}/reserve-numbers"
payload = { "count": 10 }
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({count: 10})
};
fetch('https://api.contazen.ro/v1/invoice-series/{id}/reserve-numbers', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.contazen.ro/v1/invoice-series/{id}/reserve-numbers",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'count' => 10
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.contazen.ro/v1/invoice-series/{id}/reserve-numbers"
payload := strings.NewReader("{\n \"count\": 10\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.contazen.ro/v1/invoice-series/{id}/reserve-numbers")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"count\": 10\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.contazen.ro/v1/invoice-series/{id}/reserve-numbers")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"count\": 10\n}"
response = http.request(request)
puts response.read_body{
"success": true,
"data": {
"object": "list",
"data": [
{
"object": "number_reservation",
"token": "<string>",
"series_id": "<string>",
"number": 123,
"status": "pending",
"device_id": "<string>",
"reserved_at": 123,
"expires_at": 123,
"consumed_at": 123,
"client_local_uuid": "<string>"
}
],
"total": 123
},
"meta": {
"version": "v1",
"request_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"response_time": "23.45ms"
}
}{
"success": false,
"error": {
"message": "<string>",
"type": "api_error",
"code": "<string>",
"param": "<string>",
"doc_url": "<string>"
},
"meta": {
"version": "v1",
"request_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"response_time": "23.45ms"
}
}{
"success": false,
"error": {
"message": "<string>",
"type": "api_error",
"code": "<string>",
"param": "<string>",
"doc_url": "<string>"
},
"meta": {
"version": "v1",
"request_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"response_time": "23.45ms"
}
}Invoice Series
Reserve Numbers
Pre-allocate N invoice numbers from a locked series so the mobile device can emit invoices offline with correct numbering.
POST
/
invoice-series
/
{id}
/
reserve-numbers
Pre-allocate numbers for offline emission
curl --request POST \
--url https://api.contazen.ro/v1/invoice-series/{id}/reserve-numbers \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '{
"count": 10
}'import requests
url = "https://api.contazen.ro/v1/invoice-series/{id}/reserve-numbers"
payload = { "count": 10 }
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({count: 10})
};
fetch('https://api.contazen.ro/v1/invoice-series/{id}/reserve-numbers', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.contazen.ro/v1/invoice-series/{id}/reserve-numbers",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'count' => 10
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.contazen.ro/v1/invoice-series/{id}/reserve-numbers"
payload := strings.NewReader("{\n \"count\": 10\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.contazen.ro/v1/invoice-series/{id}/reserve-numbers")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"count\": 10\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.contazen.ro/v1/invoice-series/{id}/reserve-numbers")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"count\": 10\n}"
response = http.request(request)
puts response.read_body{
"success": true,
"data": {
"object": "list",
"data": [
{
"object": "number_reservation",
"token": "<string>",
"series_id": "<string>",
"number": 123,
"status": "pending",
"device_id": "<string>",
"reserved_at": 123,
"expires_at": 123,
"consumed_at": 123,
"client_local_uuid": "<string>"
}
],
"total": 123
},
"meta": {
"version": "v1",
"request_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"response_time": "23.45ms"
}
}{
"success": false,
"error": {
"message": "<string>",
"type": "api_error",
"code": "<string>",
"param": "<string>",
"doc_url": "<string>"
},
"meta": {
"version": "v1",
"request_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"response_time": "23.45ms"
}
}{
"success": false,
"error": {
"message": "<string>",
"type": "api_error",
"code": "<string>",
"param": "<string>",
"doc_url": "<string>"
},
"meta": {
"version": "v1",
"request_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"response_time": "23.45ms"
}
}Overview
Pullscount sequential numbers off the series counter and hands back one reservation token per slot. The caller mobile device carries these tokens in local storage and spends them when creating invoices offline.
When the device later syncs the drafts with POST /invoices, it includes reservation_token in the body — the backend uses the reservation’s pre-allocated number_idx instead of incrementing the counter again. This keeps invoice numbers gapless even across long offline periods.
The series must be locked to the calling device first (see Lock Series). Calling this on an unlocked series, or from a different device than the one holding the lock, returns
series_not_locked_to_device.Body
integer
default:"10"
required
Number of reservation slots to allocate. Maximum 50 per call — request again if the device needs more.
Response
Returns a list of reservation objects.array
Show Reservation properties
Show Reservation properties
string
Opaque token. Pass as
reservation_token when emitting the invoice.integer
The pre-allocated sequence number within the series.
string
pending, consumed, released, or expired.string
Device this reservation is bound to.
integer
Unix timestamp (seconds).
integer
Unix timestamp (seconds). Reservations expire after 30 days by default.
integer
Unix timestamp when consumed, else
null.Behavior after TTL
If a reservation expires without being consumed, the pre-allocated number becomes a gap in the series. Romanian fiscal practice accepts gaps when documented — keep the reservation TTL generous (default 30 days) and refresh the pool whenever the device comes back online. The cleanup cron flips expired rows tostatus = 'expired' but does not renumber downstream invoices.
Lifecycle
┌──────────────┐ consumed
reserve ────► │ pending │ ───────────────► consumed (by POST /invoices)
└──────────────┘
│
├─ released (by POST /invoice-series/reservations/{token}/release)
│
└─ expired (by TTL cron)
Authorizations
Use your API key (sk_live_xxx or sk_test_xxx)
Path Parameters
Body
application/json
Required range:
1 <= x <= 50Was this page helpful?