Skip to content

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:

  1. Did the polling task run? Check taskiq worker logs for pac_status_poll_task entries with this document_id.
  2. Did a webhook arrive? Check the webhook log table or app/webhooks/router.py traces.
  3. What does Alanube say now? Manually GET:
    GET {pac_base_url}/pan/v1/invoices/{document_id}?idCompany={pac_company_id}&documents=pdf
    

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:

  1. Read pac_response.errors to understand what failed.
  2. Common causes:
  3. Invalid receiver RUC.
  4. Missing CPBS for government receiver.
  5. Invalid retention configuration.
  6. Numeration collision (rare).
  7. 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"

SELECT * FROM files WHERE entity_id = '<invoice-uuid>' AND entity_type = 'INVOICES';

If empty:

  1. Check legal_status — must be at least PAC_AUTHORIZED for a PDF to exist.
  2. Run attachPacPdf(sourceId: "<id>", sourceType: INVOICE).
  3. 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_id in 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 (NATURAL vs JURIDICO). 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 404 for 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:

  1. Note the document_id.
  2. GET /pan/v1/invoices/{document_id}?documents=pdf from Alanube directly to confirm current state.
  3. Call attachPacPdf to refresh the file attachment.
  4. If legal_status is wrong in our DB, manually UPDATE 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

  1. Get the new key from Alanube.
  2. Update the env secret in k8s.
  3. Roll the deployment.
  4. Verify with a single test invoice.
  5. 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.