Troubleshooting¶
A runbook for the most common "my invoice is broken" scenarios.
"The invoice was created but has no CUFE"¶
Diagnose:
SELECT id, legal_status, document_id, invoice_number, pac_input IS NOT NULL AS has_input
FROM invoices
WHERE id = '<uuid>';
legal_status |
document_id |
What it means |
|---|---|---|
NULL |
NULL |
The invoice is in PROFORM mode, or submission was never attempted. |
NULL |
NULL + has_input = true |
Submission was attempted but failed before persisting the response. Check logs. |
PAC_REJECTED |
set | Alanube rejected. Look at pac_response.errors. |
PAC_AUTHORIZED |
set, invoice_number empty |
Highly unusual — invoice_number should be set with the CUFE on success. |
"It's stuck in PAC_AUTHORIZED forever"¶
This means PAC accepted but DGI hasn't yet (or didn't) respond. Check:
- Did the polling task run? Check taskiq worker logs for
pac_status_poll_taskentries with thisdocument_id. - Did a webhook arrive? Check the webhook log table or
app/webhooks/router.pytraces. - What does Alanube say now? Manually GET:
If Alanube reports DGI_AUTHORIZED but our DB doesn't, run attachPacPdf to force a sync.
"It's PAC_REJECTED — what now?"¶
PAC rejection is terminal. The fix is:
- Read
pac_response.errorsto understand what failed. - Common causes:
- Invalid receiver RUC.
- Missing CPBS for government receiver.
- Invalid retention configuration.
- Numeration collision (rare).
- Create a new invoice with the corrected data. The old one stays as
PAC_REJECTED.
You cannot "fix and resubmit" the same invoice — Alanube treats it as a finalized rejected document.
"The PDF didn't attach"¶
If empty:
- Check
legal_status— must be at leastPAC_AUTHORIZEDfor a PDF to exist. - Run
attachPacPdf(sourceId: "<id>", sourceType: INVOICE). - If that returns
false, inspect the worker logs — Alanube may not have a PDF yet, or the URL is expired.
"Webhook signature is invalid"¶
The X-Pac-Signature header didn't match settings.pac_webhook_secret. Causes:
- Secret was rotated on the Alanube side but not in our env.
- Wrong env (staging secret in prod or vice versa).
- Manually-crafted test request without the header.
Fix: align the secret in both places, restart the API.
"Webhook arrives but we can't find the tenant"¶
Path is /webhooks/pac/{company_id}. We look up tenant.pac_company_id = company_id. If no match → 404.
Causes:
- The tenant was deleted/soft-deleted.
- The
company_idin the URL is wrong (typo, copy-paste error). - Multi-region: the document was issued under a different deployment.
"Voiding fails with 'outside void window'"¶
The DGI's void window has passed. Issue a credit note instead. See Voiding.
"RUC verification fails for a real RUC"¶
- Confirm the RUC type (
NATURALvsJURIDICO). A juridico RUC sent as natural will fail. - Confirm the format. Panamanian RUCs have a specific shape; Alanube's docs are authoritative.
- If Alanube returns
404for a known-active RUC, retry — sometimes the DGI sync lags.
Manual document recovery¶
If you need to fully re-sync a single document end-to-end:
- Note the
document_id. GET /pan/v1/invoices/{document_id}?documents=pdffrom Alanube directly to confirm current state.- Call
attachPacPdfto refresh the file attachment. - If
legal_statusis wrong in our DB, manuallyUPDATE invoices SET legal_status = '...' WHERE id = '...'— there's no public mutation for this; it's a recovery operation.
When in doubt, don't mutate manually in production. Open a ticket and let an engineer with full context handle it.
Rotating the PAC API key¶
- Get the new key from Alanube.
- Update the env secret in k8s.
- Roll the deployment.
- Verify with a single test invoice.
- Revoke the old key in Alanube's dashboard.
The webhook secret rotates the same way — but since signature verification is direct equality, you must coordinate so that both sides flip at the same time, or briefly accept either secret during the transition.