curl -X POST "https://api.dcycle.io/v2/invoices/refrigerants" \
-H "x-api-key: ${DCYCLE_API_KEY}" \
-H "x-organization-id: ${DCYCLE_ORG_ID}" \
-H "Idempotency-Key: 4d3c2b1a-0f9e-4d8c-b7a6-5f4e3d2c1b0a" \
-H "Content-Type: application/json" \
-d '{
"records": [
{
"facility_id": "0b8e4d2a-1c3f-4e5a-9b7d-6c8e0f2a4b6d",
"start_date": "2026-01-01",
"end_date": "2026-01-31",
"quantity": 3.5,
"unit_id": "61743a63-ff70-459c-9567-5eee8f7dfd5c",
"refrigerant_fuel_id": "475c39ac-1435-4b10-9559-70966ea0800c",
"invoice_number": "MNT-2026-0042",
"client_row_id": "RF-0001"
},
{
"facility_id": "7f6e5d4c-3b2a-4190-8e7f-6d5c4b3a2918",
"start_date": "2026-01-01",
"end_date": "2026-03-31",
"quantity": 1.2,
"unit_id": "61743a63-ff70-459c-9567-5eee8f7dfd5c",
"refrigerant_fuel_id": "8fd1ff5d-3f57-47cf-ae83-a841fd084b95"
}
]
}'
{
"id": "6a5b4c3d-2e1f-4a0b-9c8d-7e6f5a4b3c2d",
"status": "processing",
"entity_type": "invoices",
"operation": "create",
"source": "api_bulk",
"counts": { "submitted": 2, "succeeded": 0, "failed": 0 },
"chunks_total": 1,
"chunks_done": 0,
"created_at": "2026-10-13T10:41:07.512Z",
"finished_at": null,
"links": {
"self": "/v2/ingest-jobs/6a5b4c3d-2e1f-4a0b-9c8d-7e6f5a4b3c2d",
"items": "/v2/ingest-jobs/6a5b4c3d-2e1f-4a0b-9c8d-7e6f5a4b3c2d/items"
}
}
{
"type": "https://code.dcycle.io/api-reference/errors#BULK_RECORDS_REJECTED",
"title": "Unprocessable Content",
"status": 422,
"code": "BULK_RECORDS_REJECTED",
"detail": "1 of the submitted records are invalid; nothing was written.",
"errors": [
{
"source_row_index": 0,
"client_row_id": "RF-0001",
"error_code": "REFERENCE_NOT_FOUND",
"error_params": { "field": "refrigerant_fuel_id", "value": "00000000-0000-0000-0000-000000000000" }
}
],
"rejected": 1,
"request_id": "b2248a31-0f1b-4a7d-83ce-b29bd5977b4c"
}
{ "dry_run": true, "submitted": 2, "valid": 2 }
Create Refrigerant Invoices (v2)
Create up to 5,000 refrigerant recharges (fugitive emissions) in one request; emissions are calculated asynchronously
POST
/
v2
/
invoices
/
refrigerants
curl -X POST "https://api.dcycle.io/v2/invoices/refrigerants" \
-H "x-api-key: ${DCYCLE_API_KEY}" \
-H "x-organization-id: ${DCYCLE_ORG_ID}" \
-H "Idempotency-Key: 4d3c2b1a-0f9e-4d8c-b7a6-5f4e3d2c1b0a" \
-H "Content-Type: application/json" \
-d '{
"records": [
{
"facility_id": "0b8e4d2a-1c3f-4e5a-9b7d-6c8e0f2a4b6d",
"start_date": "2026-01-01",
"end_date": "2026-01-31",
"quantity": 3.5,
"unit_id": "61743a63-ff70-459c-9567-5eee8f7dfd5c",
"refrigerant_fuel_id": "475c39ac-1435-4b10-9559-70966ea0800c",
"invoice_number": "MNT-2026-0042",
"client_row_id": "RF-0001"
},
{
"facility_id": "7f6e5d4c-3b2a-4190-8e7f-6d5c4b3a2918",
"start_date": "2026-01-01",
"end_date": "2026-03-31",
"quantity": 1.2,
"unit_id": "61743a63-ff70-459c-9567-5eee8f7dfd5c",
"refrigerant_fuel_id": "8fd1ff5d-3f57-47cf-ae83-a841fd084b95"
}
]
}'
{
"id": "6a5b4c3d-2e1f-4a0b-9c8d-7e6f5a4b3c2d",
"status": "processing",
"entity_type": "invoices",
"operation": "create",
"source": "api_bulk",
"counts": { "submitted": 2, "succeeded": 0, "failed": 0 },
"chunks_total": 1,
"chunks_done": 0,
"created_at": "2026-10-13T10:41:07.512Z",
"finished_at": null,
"links": {
"self": "/v2/ingest-jobs/6a5b4c3d-2e1f-4a0b-9c8d-7e6f5a4b3c2d",
"items": "/v2/ingest-jobs/6a5b4c3d-2e1f-4a0b-9c8d-7e6f5a4b3c2d/items"
}
}
{
"type": "https://code.dcycle.io/api-reference/errors#BULK_RECORDS_REJECTED",
"title": "Unprocessable Content",
"status": 422,
"code": "BULK_RECORDS_REJECTED",
"detail": "1 of the submitted records are invalid; nothing was written.",
"errors": [
{
"source_row_index": 0,
"client_row_id": "RF-0001",
"error_code": "REFERENCE_NOT_FOUND",
"error_params": { "field": "refrigerant_fuel_id", "value": "00000000-0000-0000-0000-000000000000" }
}
],
"rejected": 1,
"request_id": "b2248a31-0f1b-4a7d-83ce-b29bd5977b4c"
}
{ "dry_run": true, "submitted": 2, "valid": 2 }
← Invoices API
Create one or many refrigerant recharges: the gas topped up in air conditioning, heat pumps or cold rooms, which
replaces what leaked (the fugitive emissions of scope 1). The request checks every record and writes them at once; their
emissions (the kilograms recharged times the gas’s global warming potential) are calculated in the background. The
answer is
202 Accepted with a job: follow it with GET /v2/ingest-jobs/{id}
or the ingest_job.finished webhook.
This route only takes what a refrigerant recharge has. The other categories get their own route; until then they
keep POST /v1/invoices.
Beta. Part of the bulk ingest API, currently in beta. The contract may still change before general availability.
curl -X POST "https://api.dcycle.io/v2/invoices/refrigerants" \
-H "x-api-key: ${DCYCLE_API_KEY}" \
-H "x-organization-id: ${DCYCLE_ORG_ID}" \
-H "Idempotency-Key: 4d3c2b1a-0f9e-4d8c-b7a6-5f4e3d2c1b0a" \
-H "Content-Type: application/json" \
-d '{
"records": [
{
"facility_id": "0b8e4d2a-1c3f-4e5a-9b7d-6c8e0f2a4b6d",
"start_date": "2026-01-01",
"end_date": "2026-01-31",
"quantity": 3.5,
"unit_id": "61743a63-ff70-459c-9567-5eee8f7dfd5c",
"refrigerant_fuel_id": "475c39ac-1435-4b10-9559-70966ea0800c",
"invoice_number": "MNT-2026-0042",
"client_row_id": "RF-0001"
},
{
"facility_id": "7f6e5d4c-3b2a-4190-8e7f-6d5c4b3a2918",
"start_date": "2026-01-01",
"end_date": "2026-03-31",
"quantity": 1.2,
"unit_id": "61743a63-ff70-459c-9567-5eee8f7dfd5c",
"refrigerant_fuel_id": "8fd1ff5d-3f57-47cf-ae83-a841fd084b95"
}
]
}'
{
"id": "6a5b4c3d-2e1f-4a0b-9c8d-7e6f5a4b3c2d",
"status": "processing",
"entity_type": "invoices",
"operation": "create",
"source": "api_bulk",
"counts": { "submitted": 2, "succeeded": 0, "failed": 0 },
"chunks_total": 1,
"chunks_done": 0,
"created_at": "2026-10-13T10:41:07.512Z",
"finished_at": null,
"links": {
"self": "/v2/ingest-jobs/6a5b4c3d-2e1f-4a0b-9c8d-7e6f5a4b3c2d",
"items": "/v2/ingest-jobs/6a5b4c3d-2e1f-4a0b-9c8d-7e6f5a4b3c2d/items"
}
}
{
"type": "https://code.dcycle.io/api-reference/errors#BULK_RECORDS_REJECTED",
"title": "Unprocessable Content",
"status": 422,
"code": "BULK_RECORDS_REJECTED",
"detail": "1 of the submitted records are invalid; nothing was written.",
"errors": [
{
"source_row_index": 0,
"client_row_id": "RF-0001",
"error_code": "REFERENCE_NOT_FOUND",
"error_params": { "field": "refrigerant_fuel_id", "value": "00000000-0000-0000-0000-000000000000" }
}
],
"rejected": 1,
"request_id": "b2248a31-0f1b-4a7d-83ce-b29bd5977b4c"
}
{ "dry_run": true, "submitted": 2, "valid": 2 }
How it works
- Every record is checked. If any is invalid the whole request is rejected with
422and nothing is written; the answer lists every invalid record, so you can fix them all at once. - The invoices are written at once, with status
loading. An invoice split across facilities (facility_percentages) becomes one invoice per facility, each with its share ofquantityandtotal_spend. - The job calculates their emissions in the background. Each invoice ends
active, orerrorwhen it could not be calculated (CALCULATION_FAILEDin the job’s items). - When every chunk is done the job is
completed(orcompleted_with_errors) andingest_job.finishedis sent to your webhook endpoints.
Request
Headers
string
required
Your API key for authentication
string
required
Your organization UUID
string
required
1 to 255 characters, unique per batch. A retry with the same key and body returns the original job instead of
creating the invoices again; the same key with another body is
422 IDEMPOTENCY_KEY_REUSED.Query Parameters
boolean
default:"false"
Check only: the same
422 for invalid records, nothing written, no job; 200 with
{"dry_run": true, "submitted": n, "valid": n} when every record is valid.Body Parameters
array[object]
required
The invoices to create, 1 to 5,000.
Show record
Show record
uuid
The facility that consumed the whole invoice. Send it or
facility_percentages.array[object]
Split the invoice across facilities:
[{"facility_id": "...", "percentage": 0.6}, ...]. Each facility once;
each share above 0 and at most 1, four decimals; the shares add up to 1 at most.date
required
First day of the billing period,
YYYY-MM-DD.date
required
Last day of the billing period, on or after
start_date.number
required
Kilograms of gas recharged in the period, 0 or more, for the whole invoice.
uuid
required
Kilograms:
61743a63-ff70-459c-9567-5eee8f7dfd5c. Put what the recharge cost in total_spend.uuid
The refrigerant gas recharged (
GET /v1/recharge/gases), e.g. R-134a 475c39ac-1435-4b10-9559-70966ea0800c, R-32
8fd1ff5d-3f57-47cf-ae83-a841fd084b95. Required unless custom_ef_record_id is sent.uuid
A custom emission factor record to calculate with, instead of the gas’s default one.
string
The invoice number of the maintenance company, up to 255 characters.
number
What the invoice cost, 0 or more, in
currency_unit_id (sent together). Informative.uuid
A currency unit of
GET /v2/units, e.g. euros
d3e37f2b-0fc3-4532-82f8-3890ab56ad37.string
Your own reference for the record, up to 255 characters, echoed in errors and in the job’s items.
Response
202 Accepted, the job (entity_type: invoices, operation: create) and a Location header to it.
GET /v2/ingest-jobs/{id}/items has one item per record, in the order sent,
whose entity_id is the invoice’s id (for a split invoice, the id of its first facility’s invoice).
Errors
Problem details. Per-record codes inerrors[].error_code:
error_code | Cause |
|---|---|
SCHEMA_INVALID | The record does not match the schema: a missing field, both or neither of facility_id and facility_percentages, neither refrigerant_fuel_id nor custom_ef_record_id, shares above 1, end_date before start_date, total_spend without currency_unit_id… error_params.errors says where. |
FACILITY_NOT_FOUND | A facility does not exist or is outside your organization’s perimeter (both answer the same). |
UNIT_NOT_SUPPORTED | unit_id is not kg, or currency_unit_id is not a currency (error_params.field). |
REFERENCE_NOT_FOUND | refrigerant_fuel_id is not a refrigerant gas Dcycle knows. |
MULTIDB_CUSTOM_RECORD_NOT_FOUND_OR_DISABLED | custom_ef_record_id does not exist, is disabled or is not visible from the facility’s organization. |
MULTIDB_CUSTOM_RECORD_INCOMPATIBLE_CATEGORY | custom_ef_record_id is not configured for refrigerant recharges. |
401 for a missing or invalid API key, 403 LOGGED_USER_NOT_MEMBER when the key’s user is not a member of the
organization, 422 REQUEST_VALIDATION_FAILED for a malformed body (no records, more than 5,000, no
Idempotency-Key), 422 IDEMPOTENCY_KEY_REUSED for a key already used with another body.
Limits
| Limit | Value |
|---|---|
| Records per request | 1 to 5,000 |
Related Endpoints
Create Fuel Invoices (v2)
The fuel route
Delete Invoices (v2)
Delete invoices of any category
Get Ingest Job
Follow the calculation
Was this page helpful?