DIAN REST API communicates with Colombia’s tax authority through a WCF/SOAP web service. TheDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/farojas85/fast-rest-api/llms.txt
Use this file to discover all available pages before exploring further.
DianSoapAdapter class, located at src/infrastructure/adapters/dian_soap/dian_adapter.py, implements the IDianSoapPort interface using zeep.AsyncClient over an httpx.AsyncTransport. This combination gives you fully non-blocking SOAP calls inside FastAPI’s async event loop without spawning threads.
DIAN Web Service Environments
The DIAN operates two independent SOAP endpoints. The active endpoint is selected automatically at runtime based on theENVIRONMENT variable: any value other than "production" routes traffic to the habilitación (testing) environment.
Habilitación (Testing)
Used when Accepts test invoices using
ENVIRONMENT != 'production'.DIAN_TEST_SET_ID. No fiscal effects.Producción
Used when Every document submitted has real legal and fiscal consequences.
ENVIRONMENT == 'production'.get_dian_adapter() in pedido_local_controller.py:
The DianSoapAdapter
DianSoapAdapter is constructed with three arguments — wsdl_url, cert_path, and password — and initializes the full zeep async stack during __init__. Here is the complete class from source:
Key constructor details
| Component | Purpose |
|---|---|
httpx.AsyncClient(timeout=30.0) | Creates a shared async HTTP client with a 30-second total timeout. Prevents a slow or unresponsive DIAN endpoint from blocking the event loop indefinitely. |
AsyncTransport(client=self.httpx_client) | Tells zeep to route all SOAP HTTP traffic through the httpx client instead of the default synchronous requests library, keeping all I/O non-blocking. |
HistoryPlugin() | Captures the raw SOAP XML envelopes (request and response) in self.history.last_sent and self.history.last_received. Invaluable for diagnosing DIAN validation errors. |
AsyncClient(wsdl=..., transport=..., plugins=[...]) | Initializes the zeep client, downloads the WSDL (or reads it from cache), and builds Python bindings for every SOAP operation defined by the DIAN service. |
SOAP Method: SendTestSetAsync
The adapter callsself.client.service.SendTestSetAsync(...), which maps to the DIAN WSDL operation of the same name. Zeep serializes the Python keyword arguments into a SOAP envelope automatically.
The three parameters zeep sends to the DIAN service are:
| Parameter | Source | Description |
|---|---|---|
fileName | invoice_data["filename"] | The logical file name of the XML invoice (e.g. "factura.xml"). The DIAN uses this for internal tracking. |
contentFile | invoice_data["xml_base64"] | The complete signed XML invoice, base64-encoded. The DIAN decodes and validates it server-side. |
testSetId | invoice_data["test_set_id"] | The DIAN_TEST_SET_ID UUID from your environment, issued during the habilitación registration. Required in the testing environment. |
ZipKey attribute becomes the track_id returned to the API caller:
track_id can be used in subsequent DIAN queries to retrieve the final validation status and the official CUFE (Código Único de Factura Electrónica).
Error Handling
The adapter converts all infrastructure-level exceptions into structured Python dictionaries so the application layer never receives raw SOAP or HTTP exceptions:httpx.TimeoutException → Timeout error dict
httpx.TimeoutException → Timeout error dict
Raised when the DIAN server does not respond within the 30-second window configured on the This allows the use case layer to log the failure and return an appropriate HTTP 500 to the client without crashing.
httpx.AsyncClient. The adapter returns:Generic Exception → named error dict
Generic Exception → named error dict
Any other exception (zeep The
Fault, network error, XML parse failure, etc.) is caught by the broad except Exception as e handler and returned as:error field carries the exception class name so callers can distinguish SOAP faults from network errors without parsing the message string.The IDianSoapPort Interface
DianSoapAdapter satisfies the IDianSoapPort Protocol defined in src/application/ports/dian_port.py:
IDianSoapPort is a structural Protocol, the application layer (FacturarPedidoLocalUseCase) depends only on this interface — not on DianSoapAdapter directly. This means:
- Tests can pass a lightweight
MockDianPortwith zero network calls. - Alternative adapters (e.g., a direct HTTPS adapter without zeep) can be swapped in by satisfying the same two-method contract.
- The domain and application layers remain completely decoupled from zeep, httpx, and SOAP concepts.
Credit Note Support
Thesend_credit_note method currently returns a stub response and has not yet been connected to the DIAN SOAP service:
IDianSoapPort interface and will eventually call the appropriate DIAN WSDL operation for credit notes (notas crédito). The interface contract is already in place, so adding the implementation will not require changes to the application or domain layers.
A note on X.509 XML signing in production: The DIAN’s production service (
vpfe.dian.gov.co) requires that the XML invoice be digitally signed with an X.509 signature before submission — the SOAP envelope itself must carry a WS-Security header containing the signature produced by the private key inside the PFX certificate. The current adapter abstracts this step. A full production implementation would extract the private key from the PFX at startup and pass it to zeep.wsse.Signature(key_file, certfile) (or a custom signxml-based plugin) so zeep adds the correct <wsse:Security> header to every outbound envelope automatically.