Launching ECF SSD API: DGII electronic invoicing as infrastructure, not as a task
Why we built another e-CF API
There are dozens of electronic invoicing solutions for the Dominican Republic. Before we started, we asked ourselves honestly: does the world need one more?
The answer came from the clients. Companies we work with arrived saying things like:
- “My vendor charges per document, and my volume makes it unviable.”
- “The API we use doesn’t let us sign locally; they receive an unsigned XML on their server.”
- “I have no visibility into what happened when a document fails.”
- “Every time DGII changes something, I wait two weeks for my vendor to update.”
What was missing wasn’t another API. It was an API designed for integrators, not end users.
Today we’re publicly launching ECF SSD API — the same one already running in production for several clients in banking, retail, and manufacturing.
Design principles
1. You sign, not us
XAdES-BES signing happens where your certificate lives, not on our servers. We offer:
- An SDK that signs locally with your P12 certificate.
- An endpoint that accepts already-signed XML and only handles submission to DGII.
Why it matters: your private key should never leave your infrastructure. If an e-CF vendor asks you to upload your P12, switch vendors.
2. Real idempotency
Every operation accepts an Idempotency-Key. Retry three times if you want: you’ll only generate one e-CF.
POST /v1/comprobantes
Authorization: Bearer ssd_live_...
Idempotency-Key: 8f3d2c9a-7b1e-4a5f-9d2c-1e8b3f7a9c4d
Content-Type: application/xml
<ECF xmlns="...">...</ECF>
Implemented correctly: if the first call fails halfway through (after submission to DGII but before returning a response to you), your retry recovers the actual state — it doesn’t duplicate the submission.
3. End-to-end observability
Every e-CF has a tracking_id that follows the transaction through:
- Your submission to SSD.
- Our submission to DGII.
- The acknowledgement (ACECF) response.
- Your confirmation webhook.
GET /v1/comprobantes/E310000000123/timeline
{
"tracking_id": "trk_01HXY...",
"events": [
{ "at": "2026-05-25T10:14:02Z", "type": "received", "duration_ms": 12 },
{ "at": "2026-05-25T10:14:02Z", "type": "signed_locally" },
{ "at": "2026-05-25T10:14:03Z", "type": "submitted_to_dgii", "duration_ms": 847 },
{ "at": "2026-05-25T10:14:04Z", "type": "acecf_received", "result": "ACEPTADO" },
{ "at": "2026-05-25T10:14:04Z", "type": "webhook_delivered", "endpoint": "https://..." }
]
}
4. Webhooks with exponential retries
When a DGII acknowledgement arrives, we notify you. If your endpoint is down, we retry for 24 hours with exponential backoff. Every webhook is signed with HMAC-SHA256 so you can verify authenticity.
import { verifyWebhook } from '@ssd/ecf-sdk'
export async function POST(req: Request) {
const signature = req.headers.get('x-ssd-signature')
const body = await req.text()
if (!verifyWebhook(body, signature, process.env.SSD_WEBHOOK_SECRET)) {
return new Response('Invalid signature', { status: 401 })
}
const event = JSON.parse(body)
// event.type === 'acecf.received'
// event.data.tracking_id === 'trk_01HXY...'
}
5. Sandbox with real parity
Our sandbox environment points to DGII’s TesteCF, not an internal mock. When you issue a test e-CF, it goes through the same cycle as production — just against the official testing environment. If it works in sandbox, it’ll work in production.
Architecture under the hood
┌─────────────────┐ XML+P12 ┌──────────────────┐
│ Your app │ ──────────────▶ │ SSD SDK │
│ (ERP, POS, etc.)│ │ (local signing) │
└─────────────────┘ └────────┬─────────┘
│ signed XML
▼
┌──────────────────┐
│ SSD Edge Worker │
│ (Cloudflare) │
└────────┬─────────┘
│ HTTPS
▼
┌──────────────────┐
│ DGII Endpoint │
│ (Production or │
│ TesteCF) │
└──────────────────┘
- Edge runtime (Cloudflare Workers): the API lives in 300+ cities. Your call goes to the nearest node, not to a central server. Average latency to DGII: <45ms.
- D1 + R2: we store tracking and signed XML (the originals, not the keys). Retention configurable to match your compliance requirements.
- Zero in-RAM state: each request is independent. If a region goes down, the next one picks up traffic with no loss.
What it covers today
| Document type | Supported |
|---|---|
| 31 — Tax Credit Invoice | ✅ |
| 32 — Consumer Invoice | ✅ |
| 33 — Debit Note | ✅ |
| 34 — Credit Note | ✅ |
| 41 — Purchases | ✅ |
| 43 — Minor Expenses | ✅ |
| 44 — Special Regimes | ✅ |
| 45 — Government | ✅ |
| 46 — Exports | ✅ |
| 47 — Payments Abroad | ✅ |
| RFCE — Summary of Issued Documents | ✅ |
| ARECF — Commercial Approval | ✅ |
Pricing: pay per use, no surprises
We charge per document successfully submitted to DGII. Not per attempt. Not per status query. Not per test document. Full pricing details on the product page.
What’s next
- Official SDKs: TypeScript/Node is live. C#/.NET, Python and PHP land next quarter.
- Odoo integration: native module, no middleware.
- 606 / 607 reports: accounting annexes generated from your e-CF history.
- Multi-tenant: for software houses who want to offer e-CF to their clients without building from scratch.
If you want sandbox credentials, reach out. We respond in hours, not weeks.
— The SSD team
Recommended for you