Liquidacion de compra POST

La liquidacion de compra se emite cuando el emisor adquiere bienes o servicios a un proveedor. 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 = "03"

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 liquidacion
detalles array Si Lineas
infoAdicional array No Hasta 20 objetos {nombre, valor}

infoTributaria: ruc (13), codDoc (03), 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
tipoIdentificacionProveedor string Si Catalogos: identificacion
identificacionProveedor string Si Documento del proveedor
razonSocialProveedor string Si Razon social o nombres
dirEstablecimiento string No Direccion del establecimiento
direccionProveedor string No Direccion del proveedor
totalSinImpuestos number Si Suma de bases
totalDescuento number Si Suma de descuentos de linea
totalConImpuestos array Si codigo, codigoPorcentaje, baseImponible, valor
importeTotal number Si Total a pagar
moneda string Si Codigo de moneda
pagos array Si formaPago y total obligatorios

detalles#

Lineas de la liquidacion.

Campo Tipo Obligatorio Descripcion
codigoPrincipal string Si Codigo del bien o servicio
codigoAuxiliar string No Codigo auxiliar del emisor
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

pagos#

Campo Tipo Obligatorio Descripcion
formaPago string Si Codigo de forma de pago
total number Si Monto con esta forma de pago
plazo number No Plazo
unidadTiempo string Condicional Obligatorio si plazo > 0

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: LIQ-2026-0007" \
  -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", "LIQ-2026-0007");

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": "LIQ-2026-0007",
}
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': 'LIQ-2026-0007',
      '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: LIQ-2026-0007',
        '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", "LIQ-2026-0007")
    .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 Liquidacion de compra#

{
  "origenReferencia": "MiERP",
  "referenciaExterna": "LIQ-2026-0007",
  "infoTributaria": {
    "ruc": "0123456789001",
    "codDoc": "03",
    "estab": "002",
    "ptoEmi": "001",
    "secuencial": "000000045"
  },
  "info": {
    "fechaEmision": "07/09/2026",
    "tipoIdentificacionProveedor": "05",
    "identificacionProveedor": "0987654321",
    "razonSocialProveedor": "PROVEEDOR DE EJEMPLO",
    "totalSinImpuestos": 200,
    "totalDescuento": 0,
    "totalConImpuestos": [
      { "codigo": "2", "codigoPorcentaje": "0", "baseImponible": 200, "valor": 0 }
    ],
    "importeTotal": 200,
    "moneda": "DOLAR",
    "pagos": [
      { "formaPago": "01", "total": 200 }
    ]
  },
  "detalles": [
    {
      "codigoPrincipal": "MP-001",
      "descripcion": "Materia prima",
      "cantidad": 2,
      "precioUnitario": 100,
      "descuento": 0,
      "precioTotalSinImpuesto": 200,
      "impuestos": [
        { "codigo": "2", "codigoPorcentaje": "0", "tarifa": 0, "baseImponible": 200, "valor": 0 }
      ]
    }
  ]
}

Notas#

  • El emisor es quien liquida; el proveedor es la contraparte.
  • No recibe consumidor final como proveedor.
  • No referencia un documento modificado.

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 ✕