Skip to content

RUC Verification

A RUC (Registro Único de Contribuyentes) is a Panamanian taxpayer ID. Before submitting an invoice, we verify the receiver's RUC against the DGI via Alanube. This:

  • Catches typos before they get rejected at the DGI step.
  • Returns the correct DV (verification digit).
  • Determines whether the receiver is a CONTRIBUYENTE, GOBIERNO, or CONSUMIDOR_FINAL.

The service

app/wrappers/pac/ruc_verification_service.py

async def verify_ruc(ruc: str, contributor_type: ContributorType) -> RucVerificationResult

contributor_type is NATURAL (individual) or JURIDICO (legal entity).

Endpoint

GET /pan/v1/check-digit?ruc={ruc}&type={NATURAL|JURIDICO}
Authorization: Bearer {pac_api_key}

Response (relevant fields):

Field Meaning
checkDigit The DV. Two digits. Used by InformacionReceptor.dv.
receiver The receptor type from Alanube's perspective. Mapped by map_receiver_to_receptor_fe_type.
type The contributor type echoed back.

Mapping to ReceptorFeType

Alanube receiver Cifras ReceptorFeType
CONTRIBUYENTE CONTRIBUYENTE
GOBIERNO GOBIERNO
anything else (or unknown) CONSUMIDOR_FINAL

CONSUMIDOR_FINAL is the catch-all for individual end-customers without a registered RUC.

Where it's called

  • InvoicePacService._resolve_ruc_types — before building the PAC payload, for both invoices and credit notes.
  • Optionally exposed through GraphQL for client-side verification before form submission (check the dgi GraphQL module for the public-facing query).

Retry behavior

verify_ruc is wrapped with tenacity:

  • 2 attempts.
  • Exponential backoff between 2s and 10s.
  • Retries only on aiohttp.ClientError. A 400 response (RUC not found) is not retried.

Ad-hoc RUC verification

When an invoice is issued to someone other than the registered client, the mutation can set:

  • adhoc_client_name
  • adhoc_client_ruc

In that case, _resolve_ruc_types verifies the ad-hoc RUC, not the client's. This lets you bill someone outside the master client list without permanently registering them.