Skip to content
Documentation
Get started

Invoice

Issue an invoice from your system

With the Timbro invoicing API, your point of sale or ERP keeps recording the sale and Timbro issues the e-invoice to the DGII. You can issue before or after collecting, and the customer can pay with Timbro, in cash, by transfer, or on your card terminal. Invoicing does not require a merchant account.

To issue, you need invoicing set up and an API key with Invoicing access, which these examples store in TIMBRO_INVOICES_API_KEY. The key determines the business and the mode, Test or Live, so your requests do not state them.

Install the SDK on your server:

Ventana de terminal
npm install @timbro/invoices

Send the real fiscal data of the sale. This example issues a Consumer Invoice paid up front:

import { createTimbroInvoices } from "@timbro/invoices";
const timbro = createTimbroInvoices({ apiKey: process.env.TIMBRO_INVOICES_API_KEY! });
const invoice = await timbro.invoices.create({
invoiceReference: "sale-842-invoice",
type: "E32",
currency: "DOP",
incomeType: "01",
paymentTerms: { type: "immediate" },
items: [{
description: "Service",
quantity: "1",
unit: "unit",
kind: "service",
unitPrice: "1250.00",
tax: { kind: "itbis_18", included: true },
}],
});
Field What it states
invoiceReference This invoice’s identifier in your system. It must be unique per business and mode
type The e-CF type: E31, E32, E33, E34, E41, E43, E44, E45, E46, or E47
incomeType The DGII income type. 01 is income from nonfinancial operations. If you do not send it, Timbro uses the one from the business profile
paymentTerms Whether the customer paid up front, bought on credit, or the sale is free
items Each item with its quantity, unit of measure, price, and tax. Amounts are strings with a decimal point

Each type asks for different data, and the InvoiceRequest schema in the REST reference details them. Do not invent data to complete a request.

Use HTTP directly

Save the same body as invoice.json and send it from your server:

Ventana de terminal
curl --request POST 'https://api.timbro.do/v1/invoices' \
--header "Authorization: Bearer $TIMBRO_INVOICES_API_KEY" \
--header 'Content-Type: application/json' \
--data-binary @invoice.json

Avoid issuing two invoices for the same sale

Section titled “Avoid issuing two invoices for the same sale”

invoiceReference identifies the invoice. If you repeat the request with the same reference and the same data, Timbro returns the same invoice instead of issuing another one. So store the request in your system before sending it, and if you lose the response, repeat it exactly as it was, without changing its data. A new reference asks for another invoice.

If your system sends invoices from a work queue, look up the reference first and issue only if it does not exist:

const found = await timbro.invoices.list({ invoiceReference: "sale-842-invoice" });

To store on the invoice the document in your system that originated it, send source: { id, version }, for example the document’s ID and its version number. If your system has to invoice a sale again, for example after a rejection, send the same id with a new version and a new invoiceReference.

paymentTerms describes the payment as it must appear on the invoice:

  • { "type": "immediate" } for a sale paid up front. If you want the invoice to show how the customer paid, add allocations with one entry per payment method, up to 7. Each payment method (method) is cash, bank_transfer, card, credit_sale, gift_certificate, barter, credit_note, or other. Amounts are in Dominican pesos and must add up to the invoice total.
  • { "type": "credit", "dueOn": "2026-11-30" } for a credit sale, with the date it is due.
  • { "type": "free" } for a free sale. The DGII does not accept this case for types E31, E33, E34, and E45.

For example, a sale of RD$ 1,250.00 paid partly in cash and partly by card:

{
"type": "immediate",
"allocations": [
{ "method": "cash", "amount": "500.00" },
{ "method": "card", "amount": "750.00" }
]
}

A credit invoice can be collected in partial payments with Timbro, as Collect an invoice in partial payments explains.

  • A Tax Credit Invoice (E31) needs in buyer the buyer’s RNC or cédula (taxId) and their name or business name (legalName).
  • A Consumer Invoice (E32) under RD$ 250,000.00 can have no buyer. From that amount, the DGII requires the buyer to be identified. If the customer gave you their details, send them in buyer.
  • A Government Invoice (E45) needs, besides the buyer, governmentEligibility with the entity type.

For a foreign buyer, send kind: "foreign" with their identification in foreignId.

Timbro calculates totals with the DGII rounding rules. If your system already calculated the sale’s totals, send them in expectedTotals with net, tax, total, and nonBillable. If they do not match Timbro’s to the cent, Timbro rejects the invoice instead of issuing other amounts, so your accounting and the e-CF never differ.

To check the data and totals without issuing, use invoices.preview with the same request. The preview does not assign an e-NCF or send anything to the DGII.

To invoice in dollars or euros, send currency and the exchange rate in exchangeRate.rate: how many Dominican pesos one unit of that currency is worth, with up to 4 decimals. The DGII reference rate for a date is at GET /v1/exchange-rates/USD?date=2026-10-21. For euros, replace USD with EUR.

The Consumer Invoice (E32) and the notes that modify it are issued only in Dominican pesos. A sale with a legal tip or with non-billable charges is also issued in pesos. Timbro always collects in Dominican pesos.

To print the invoice on a receipt printer, send pdfLayout: "receipt80mm"; the PDF will be 80 mm wide. If you do not send it, the PDF uses A4 size.

If your system prints the invoice in its own format, read fiscalIdentity.signature when the DGII accepts it. It carries the signing date (signedAt), the security code (securityCode), and the QR link (verificationUrl) that the printed invoice must show. It is null until Timbro has signed the e-CF.

The response has the invoice’s id, its e-NCF once assigned, and its status:

Status What it means
processing, verifying Timbro sent it to the DGII and is waiting for its response. Check later
accepted The DGII accepted it
acceptedWithObservations The DGII accepted it with observations you must review
rejected Timbro rejected it before sending it to the DGII. Correct the data and issue another one
authorityRejected The DGII rejected it. You can replace it
operatorRequired It needs the Timbro team to review it
closed An administrator of the business closed it before it reached the DGII. You can replace it

Retrieve the invoice by its id. The invoice.accepted and invoice.rejected webhooks notify you when it changes:

const current = await timbro.invoices.retrieve(invoice.id);
if (!current) throw new Error("Invoice not found");
const isAccepted =
current.status === "accepted" || current.status === "acceptedWithObservations";

DGII acceptance does not mean the XML and PDF are ready. To download them or send them to the customer, follow Download and send the invoice. To collect the invoice with Timbro, follow Collect an invoice you already issued.

Issuing the invoice does not record an accounting entry or confirm a payment. Your system still keeps the sale’s accounting.