Saltar al contenido principal

Comprobante de Crédito Fiscal (03)

El CCF (tipo 03) se emite entre contribuyentes IVA. El receptor debe tener NRC asignado por el MH. A diferencia de la Factura (01), el CCF desglosa explícitamente el IVA del 13% en el documento y permite al receptor deducirlo en su declaración.

Cuándo usar CCF

Cuando el receptor:

  • Tiene NRC asignado (está inscrito como contribuyente IVA).
  • Requiere el crédito fiscal para su contabilidad.
  • Es persona jurídica o natural con actividad económica formal.

Si el receptor no tiene NRC, emite Factura (01) en lugar de CCF.

Detalles técnicos

MétodoPOST
URLhttps://ocote.io/api/connect/invoice (mismo endpoint, doc_type: "03")
Content-Typeapplication/json
AutenticaciónHeader Authorization: Bearer odt_...

Request

El request es idéntico al de Factura (01) en estructura, con tres diferencias críticas:

  1. doc_type debe ser "03".
  2. customer es obligatorio y requiere campos específicos.
  3. customer.type_contributor determina si se aplica retención IVA automática.

Campos obligatorios del cliente en CCF

CampoRequeridoDescripción
nameRazón social del contribuyente.
nitNIT del contribuyente receptor.
nrcNRC del contribuyente.
type_contributor1=Pequeño, 2=Mediano, 3=Grande, 4=Gobierno.

Los demás campos (activity_code, department, municipality, email, etc.) son opcionales pero recomendados — ver tabla completa en Factura (01) > Cliente.

Retención automática sobre Grande Contribuyente y Gobierno

Cuando type_contributor es 3 (Grande) o 4 (Gobierno) y amount_taxable >= 100.00, el API aplica automáticamente una retención IVA del 1% sobre la base gravable. No envías ningún campo extra ni haces cálculos. Ver Wildcard items > Retención IVA 1%.

Response

Response idéntico a Factura 01 en estructura. En CCF los campos de montos son especialmente relevantes:

CampoCálculo
amount_taxableBase gravable = suma de (quantity × unit_price × (1 − discount)) quitando el 13% IVA.
amount_vatIVA 13% = amount_taxable × 0.13.
amount_grossTotal con IVA = amount_taxable + amount_vat.
amount_retentionamount_taxable × 0.01 si type_contributor4 y amount_taxable >= 100; sino 0.
amount_totalTotal neto = amount_gross − amount_retention.

Ejemplo: CCF a Gran Contribuyente

curl
curl -X POST https://ocote.io/api/connect/invoice \
-H "Authorization: Bearer odt_xxx" \
-H "Content-Type: application/json" \
-d '{
"doc_type": "03",
"external_ref": "CCF-2026-0042",
"customer": {
"name": "EMPRESA GRANDE, S.A. DE C.V.",
"nit": "06140710141035",
"nrc": "2360090",
"type_contributor": 3,
"activity_code": "86902",
"department": "06",
"municipality": "14",
"address": "Boulevard Los Héroes, San Salvador",
"email": "contabilidad@empresagrande.com"
},
"lines": [
{
"description": "Desarrollo de software a la medida - Abril 2026",
"quantity": 1,
"unit_price": 5000.00
}
],
"payment_method": "05",
"transaction_condition": 2,
"deadline": 30
}'
Node.js (axios)
const { data } = await axios.post(
'https://ocote.io/api/connect/invoice',
{
doc_type: '03',
external_ref: 'CCF-2026-0042',
customer: {
name: 'EMPRESA GRANDE, S.A. DE C.V.',
nit: '06140710141035',
nrc: '2360090',
type_contributor: 3,
activity_code: '86902',
department: '06',
municipality: '14',
address: 'Boulevard Los Héroes, San Salvador',
email: 'contabilidad@empresagrande.com',
},
lines: [
{ description: 'Desarrollo de software a la medida - Abril 2026',
quantity: 1, unit_price: 5000.00 },
],
payment_method: '05',
transaction_condition: 2,
deadline: 30,
},
{ headers: { Authorization: `Bearer ${process.env.OCOTE_API_KEY}` } }
);
Python (requests)
r = requests.post(
"https://ocote.io/api/connect/invoice",
headers={"Authorization": f"Bearer {API_KEY}"},
json={
"doc_type": "03",
"external_ref": "CCF-2026-0042",
"customer": {
"name": "EMPRESA GRANDE, S.A. DE C.V.",
"nit": "06140710141035",
"nrc": "2360090",
"type_contributor": 3,
"activity_code": "86902",
"department": "06",
"municipality": "14",
"address": "Boulevard Los Héroes, San Salvador",
"email": "contabilidad@empresagrande.com",
},
"lines": [
{
"description": "Desarrollo de software a la medida - Abril 2026",
"quantity": 1,
"unit_price": 5000.00,
},
],
"payment_method": "05",
"transaction_condition": 2,
"deadline": 30,
},
)
PHP (Guzzle)
$response = $client->post('invoice', [
'headers' => ['Authorization' => 'Bearer ' . getenv('OCOTE_API_KEY')],
'json' => [
'doc_type' => '03',
'external_ref' => 'CCF-2026-0042',
'customer' => [
'name' => 'EMPRESA GRANDE, S.A. DE C.V.',
'nit' => '06140710141035',
'nrc' => '2360090',
'type_contributor' => 3,
'activity_code' => '86902',
'department' => '06',
'municipality' => '14',
'address' => 'Boulevard Los Héroes, San Salvador',
'email' => 'contabilidad@empresagrande.com',
],
'lines' => [
[
'description' => 'Desarrollo de software a la medida - Abril 2026',
'quantity' => 1,
'unit_price' => 5000.00,
],
],
'payment_method' => '05',
'transaction_condition' => 2,
'deadline' => 30,
],
]);

Respuesta exitosa con retención

{
"success": true,
"dte_success": true,
"contingency": false,
"rejected": false,
"posted": true,
"is_duplicate": false,

"document_id": "a1b2c3d4-1234-5678-9abc-def012345678",
"external_ref": "CCF-2026-0042",
"control_number": "DTE-03-M001P001-000000000000042",
"generation_code": "A1B2C3D4-1234-5678-9ABC-DEF012345678",
"reception_stamp": "20260421154532...",

"amount_taxable": 4424.78,
"amount_vat": 575.22,
"amount_gross": 5000.00,
"amount_retention": 44.25,
"amount_total": 4955.75,

"ticket_url": "",
"json_url": "https://ocote.io/api/connect/file/a1b2c3d4-1234-5678-9abc-def012345678?type=json&key=odt_xxx"
}

Observa:

  • Enviaste unit_price: 5000.00 con IVA incluido. El API extrajo el IVA: base gravable 4424.78, IVA 575.22, suma 5000.00.
  • Como el receptor es type_contributor: 3 (Gran Contribuyente) y la base supera $100, se aplicó retención IVA: 4424.78 × 0.01 = 44.25.
  • El total neto que el receptor debe pagar es 5000.00 − 44.25 = 4955.75.
  • ticket_url es vacío — los CCF no generan ticket térmico; se usa el json_url o el PDF accesible desde la plataforma Ocote.

Errores de validación específicos del CCF

Además de los errores generales de /invoice, el CCF valida:

MensajeCausa
Crédito Fiscal requiere datos del clienteNo enviaste customer.
NIT es requerido para Crédito Fiscalcustomer.nit vacío.
NRC es requerido para Crédito Fiscalcustomer.nrc vacío.
Nombre del cliente es requerido para Crédito Fiscalcustomer.name vacío.
Tipo de contribuyente es requerido para Crédito Fiscalcustomer.type_contributor no enviado.

Consultar y modificar después

  • Consultar estado: GET /status/CCF-2026-0042
  • Anular: POST /invalidate/CCF-2026-0042. Si el CCF tiene más de 3 meses, el API automáticamente genera una Nota de Crédito (05) que lo ajusta — ver Nota de Crédito.
  • Emitir NC sobre este CCF: POST /credit-memo con document_id apuntando al CCF — ver Nota de Crédito.

Ver también