Nota de credito POST

La nota de credito ajusta o anula un comprobante ya emitido (devoluciones, descuentos, anulaciones). La estructura del comprobante es la misma que en Factura; cambia el contenido de info y el cuerpo de ejemplo (comprobante.json).

Ejemplo en el ambiente de pruebas. Los comprobantes no tienen validez fiscal.

POST /v1/contribuyentes/{identificacion}/comprobantes
infoTributaria.codDoc = "04"

Estructura del comprobante#

Clave Tipo Obligatorio Descripcion
origenReferencia string Si Sistema de origen (max. 64)
referenciaExterna string Si Referencia estable de tu sistema (max. 128)
infoTributaria object Si Identidad del documento
info object Si Cabecera de la nota
detalles array Si Lineas
infoAdicional array No Hasta 20 objetos {nombre, valor}

infoTributaria: ruc (13), codDoc (04), estab (3), ptoEmi (3) y secuencial (9) obligatorios. La clave de acceso la asigna la plataforma; no la envies.

Campos de info#

Campo Tipo Obligatorio Regla
fechaEmision string Si dd/MM/yyyy
tipoIdentificacionComprador string Si Catalogos de identificacion
identificacionComprador string Si Documento del comprador
razonSocialComprador string Si Razon social
codDocModificado string Si Tipo del documento de referencia
numDocModificado string Si Formato ddd-ddd-ddddddddd
fechaEmisionDocSustento string Si dd/MM/yyyy
totalDocumentoSustento number No Total del documento de referencia
totalSinImpuestos number Si Base de la nota
totalConImpuestos array Si codigo, codigoPorcentaje, baseImponible, valor
valorModificacion number Si Valor de la modificacion
moneda string Si Codigo de moneda
motivo string Si Motivo de la nota

detalles#

Lineas de la nota de credito. Usa codigoInterno (no codigoPrincipal).

Campo Tipo Obligatorio Descripcion
codigoInterno string Si Codigo del bien o servicio
codigoAdicional string No Codigo adicional
descripcion string Si Descripcion de la linea
unidadMedida string No Unidad de medida
cantidad number Si Cantidad (hasta 6 decimales)
precioUnitario number Si Precio unitario (hasta 6 decimales)
descuento number Si Descuento de la linea (importe, no porcentaje)
precioTotalSinImpuesto number Si cantidad x precioUnitario - descuento
impuestos array Si Impuestos de la linea (ver abajo)
detallesAdicionales array No Hasta 3 objetos {nombre, valor}

detalles[].impuestos#

Campo Tipo Obligatorio Descripcion
codigo string Si Impuesto: 2 IVA, 3 ICE, 5 IRBPNR
codigoPorcentaje string Si Codigo de tarifa (ve Catalogos)
tarifa number Si Porcentaje de la tarifa
baseImponible number Si Base sobre la que se calcula
valor number Si Valor del impuesto

infoAdicional#

Campo Tipo Obligatorio Descripcion
nombre string Si Nombre del campo adicional
valor string Si Valor del campo adicional

Ejemplo de solicitud#

curl -s -X POST "https://staging-api.mynexusapi.com/v1/contribuyentes/0123456789/comprobantes" \
  -H "X-Api-Key: $ECUAFACT_API_KEY" \
  -H "Idempotency-Key: NC-2026-0003" \
  -H "Content-Type: application/json" \
  -d @comprobante.json
using System.Text;

using var http = new HttpClient();
http.DefaultRequestHeaders.Add("X-Api-Key", apiKey);
http.DefaultRequestHeaders.Add("Idempotency-Key", "NC-2026-0003");

string json = await File.ReadAllTextAsync("comprobante.json");
using var contenido = new StringContent(json, Encoding.UTF8, "application/json");
using var respuesta = await http.PostAsync(
    "https://staging-api.mynexusapi.com/v1/contribuyentes/0123456789/comprobantes",
    contenido);

Console.WriteLine($"{(int)respuesta.StatusCode} {await respuesta.Content.ReadAsStringAsync()}");
import json, os, requests

headers = {
    "X-Api-Key": os.environ["ECUAFACT_API_KEY"],
    "Idempotency-Key": "NC-2026-0003",
}
with open("comprobante.json", encoding="utf-8") as archivo:
    cuerpo = json.load(archivo)

r = requests.post(
    "https://staging-api.mynexusapi.com/v1/contribuyentes/0123456789/comprobantes",
    headers=headers, json=cuerpo, timeout=30)
print(r.status_code, r.text)
import { readFile } from 'node:fs/promises';

const cuerpo = await readFile('comprobante.json', 'utf8');
const res = await fetch(
  'https://staging-api.mynexusapi.com/v1/contribuyentes/0123456789/comprobantes',
  {
    method: 'POST',
    headers: {
      'X-Api-Key': process.env.ECUAFACT_API_KEY,
      'Idempotency-Key': 'NC-2026-0003',
      'Content-Type': 'application/json'
    },
    body: cuerpo
  });
console.log(res.status, await res.text());
<?php
$ch = curl_init('https://staging-api.mynexusapi.com/v1/contribuyentes/0123456789/comprobantes');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POST => true,
    CURLOPT_HTTPHEADER => [
        'X-Api-Key: ' . getenv('ECUAFACT_API_KEY'),
        'Idempotency-Key: NC-2026-0003',
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => file_get_contents('comprobante.json'),
]);
$respuesta = curl_exec($ch);
$estado = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
echo $estado . ' ' . $respuesta;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.file.Files;
import java.nio.file.Path;

HttpClient cliente = HttpClient.newHttpClient();
String cuerpo = Files.readString(Path.of("comprobante.json"));

HttpRequest peticion = HttpRequest.newBuilder()
    .uri(URI.create("https://staging-api.mynexusapi.com/v1/contribuyentes/0123456789/comprobantes"))
    .header("X-Api-Key", System.getenv("ECUAFACT_API_KEY"))
    .header("Idempotency-Key", "NC-2026-0003")
    .header("Content-Type", "application/json")
    .POST(HttpRequest.BodyPublishers.ofString(cuerpo))
    .build();

HttpResponse<String> respuesta = cliente.send(peticion, HttpResponse.BodyHandlers.ofString());
System.out.println(respuesta.statusCode() + " " + respuesta.body());
using Ecuafact.Sdk;

// client: cliente EcuafactClient - ver SDK .NET
EmisionResultado resultado = await client.EmitirAsync(comprobante);
Console.WriteLine($"Operacion {resultado.Admission.IdOperacion} / codigo: {resultado.Admission.Codigo}");
from ecuafact import EcuafactClient

# client: cliente EcuafactClient - ver SDK Python
resultado = client.emitir(comprobante)
print(f"Operacion {resultado.admission.id_operacion} / codigo: {resultado.admission.codigo}")
import { EcuafactClient } from "@ecuafact/sdk";

// client: cliente EcuafactClient - ver SDK Node.js
const resultado = await client.emitir(comprobante);
console.log(`Operacion ${resultado.admission.idOperacion} / codigo: ${resultado.admission.codigo}`);
<?php
use Ecuafact\Sdk\EcuafactClient;

// $client: cliente EcuafactClient - ver SDK PHP
$resultado = $client->emitir($comprobante);
echo 'Operacion ' . $resultado->admission->idOperacion . ' / codigo: ' . $resultado->admission->codigo;
import com.ecuafact.sdk.EcuafactClient;

// client: cliente EcuafactClient - ver SDK Java
EmisionResultado resultado = client.emitir(comprobante);
System.out.println("Operacion " + resultado.admission().idOperacion() + " / codigo: " + resultado.admission().codigo());

Cuerpo de la Nota de credito#

{
  "origenReferencia": "MiERP",
  "referenciaExterna": "NC-2026-0003",
  "infoTributaria": {
    "ruc": "0123456789001",
    "codDoc": "04",
    "estab": "002",
    "ptoEmi": "001",
    "secuencial": "000000032"
  },
  "info": {
    "fechaEmision": "07/09/2026",
    "tipoIdentificacionComprador": "05",
    "identificacionComprador": "0123456789",
    "razonSocialComprador": "CONTRIBUYENTE DE EJEMPLO",
    "codDocModificado": "01",
    "numDocModificado": "002-001-000000123",
    "fechaEmisionDocSustento": "01/09/2026",
    "totalDocumentoSustento": 115,
    "totalSinImpuestos": 20,
    "totalConImpuestos": [
      { "codigo": "2", "codigoPorcentaje": "4", "baseImponible": 20, "valor": 3 }
    ],
    "valorModificacion": 23,
    "moneda": "DOLAR",
    "motivo": "DEVOLUCION PARCIAL"
  },
  "detalles": [
    {
      "codigoInterno": "SERV-001",
      "descripcion": "Devolucion de servicio",
      "cantidad": 1,
      "precioUnitario": 20,
      "descuento": 0,
      "precioTotalSinImpuesto": 20,
      "impuestos": [
        { "codigo": "2", "codigoPorcentaje": "4", "tarifa": 15, "baseImponible": 20, "valor": 3 }
      ]
    }
  ]
}

Reglas especificas#

  • Si informas totalDocumentoSustento, valorModificacion no puede superarlo.
  • Informa tu los datos del documento de referencia; la API no los completa por ti.
  • Debe identificar al receptor (no consumidor final).

Respuesta#

La API responde 202 Accepted con la operacion creada:

{
  "codigo": "200",
  "mensaje": "Operacion exitosa.",
  "idOperacion": "3f1c8c1e-6f2a-4b7e-9c3d-2a1b0c9d8e7f",
  "urlEstado": "https://staging-api.mynexusapi.com/v1/operaciones/3f1c8c1e-6f2a-4b7e-9c3d-2a1b0c9d8e7f",
  "uid": "a1b2c3d4-5e6f-4a7b-8c9d-0e1f2a3b4c5d"
}
Campo Significado
codigo 200 si es una emision nueva; 201 si es un reintento con la misma Idempotency-Key
mensaje Descripcion del resultado
idOperacion Identificador de seguimiento de la emision
urlEstado Ruta para consultar el estado de esta operacion
uid Identificador del documento

El 202 no es la autorizacion del SRI: el comprobante quedo recibido. Consulta urlEstado o espera el webhook.

Estados de este endpoint#

Codigo HTTP Cuando ocurre Que hacer
200 202 Emision aceptada Sigue el estado de la operacion
201 202 Reintento con la misma Idempotency-Key y el mismo contenido Sigue la misma operacion
301 400 Falta Idempotency-Key o hay campos mal formados Corrige la solicitud
302 422 El comprobante no cumple una regla fiscal o de estructura Revisa errores
401 409 Numero o clave ya registrados (duplicado) Consulta la operacion existente
403 409 Misma Idempotency-Key con otro contenido Usa la misma intencion
501 429 Cupo agotado Amplia tu cupo
101 401 API Key invalida Revisa la API Key
103 403 Contribuyente o tipo no habilitado Habilita el contribuyente

El catalogo completo esta en Errores.

Siguientes pasos#

No se pudo completar la operacion. Recargar ✕