afiPAPI es HTTP + JSON. Elegí tu entorno y copiá el ejemplo: el flujo es siempre el mismo.
ok; si es false, el detalle está en data.error y data.detail. Tras el login, la API cachea el token y lo renueva sola — no hace falta autenticar en cada operación.Mismo flujo en todos los lenguajes: login → (último) → emitir, y leer el CAE de la respuesta.
# 1) Login (una vez por CUIT)
curl -X POST http://localhost:5014/api/afip/login \
-H "Content-Type: application/json" \
-d '{"cuit":20238233195,"servicio":"wsfe","certificadoPath":"C:\\Certificados\\cert.pfx","certificadoPassword":"clave","produccion":false}'
# 2) Último número (Factura B, punto de venta 1)
curl -X POST http://localhost:5014/api/afip/ultimo \
-H "Content-Type: application/json" \
-d '{"cuit":20238233195,"puntoVenta":1,"tipoComprobante":6,"produccion":false}'
# 3) Emitir
curl -X POST http://localhost:5014/api/afip/emitir \
-H "Content-Type: application/json" \
-d '{"cuit":20238233195,"produccion":false,"puntoVenta":1,"tipoComprobante":6,
"concepto":1,"documentoTipo":99,"documentoNumero":0,
"importeTotal":121,"importeGravado":100,"importeIva":21,
"moneda":"PES","cotizacion":1,"condicionIvaReceptorId":5,"alicuotaIvaId":5}'using System.Net.Http;
using System.Net.Http.Json;
using System.Text.Json;
var http = new HttpClient { BaseAddress = new Uri("http://localhost:5014") };
// 1) Login (una vez por CUIT)
await http.PostAsJsonAsync("/api/afip/login", new {
cuit = 20238233195L, servicio = "wsfe",
certificadoPath = @"C:\Certificados\cert.pfx",
certificadoPassword = "clave", produccion = false
});
// 2) Emitir
var resp = await http.PostAsJsonAsync("/api/afip/emitir", new {
cuit = 20238233195L, produccion = false,
puntoVenta = 1, tipoComprobante = 6, concepto = 1,
documentoTipo = 99, documentoNumero = 0,
importeTotal = 121m, importeGravado = 100m, importeIva = 21m,
moneda = "PES", cotizacion = 1m,
condicionIvaReceptorId = 5, alicuotaIvaId = 5
});
using var doc = JsonDocument.Parse(await resp.Content.ReadAsStringAsync());
var root = doc.RootElement;
if (root.GetProperty("ok").GetBoolean())
Console.WriteLine("CAE: " + root.GetProperty("data").GetProperty("CAE").GetString());import requests
BASE = "http://localhost:5014/api/afip"
# 1) Login (una vez por CUIT)
requests.post(f"{BASE}/login", json={
"cuit": 20238233195, "servicio": "wsfe",
"certificadoPath": r"C:\Certificados\cert.pfx",
"certificadoPassword": "clave", "produccion": False,
})
# 2) Emitir
r = requests.post(f"{BASE}/emitir", json={
"cuit": 20238233195, "produccion": False,
"puntoVenta": 1, "tipoComprobante": 6, "concepto": 1,
"documentoTipo": 99, "documentoNumero": 0,
"importeTotal": 121, "importeGravado": 100, "importeIva": 21,
"moneda": "PES", "cotizacion": 1,
"condicionIvaReceptorId": 5, "alicuotaIvaId": 5,
})
res = r.json()
print("CAE:", res["data"]["CAE"]) if res["ok"] else print("Error:", res["data"]["error"])const BASE = "http://localhost:5014/api/afip";
const post = (path, body) =>
fetch(`${BASE}${path}`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(body),
}).then(r => r.json());
// 1) Login (una vez por CUIT)
await post("/login", {
cuit: 20238233195, servicio: "wsfe",
certificadoPath: "C:\\Certificados\\cert.pfx",
certificadoPassword: "clave", produccion: false,
});
// 2) Emitir
const res = await post("/emitir", {
cuit: 20238233195, produccion: false,
puntoVenta: 1, tipoComprobante: 6, concepto: 1,
documentoTipo: 99, documentoNumero: 0,
importeTotal: 121, importeGravado: 100, importeIva: 21,
moneda: "PES", cotizacion: 1,
condicionIvaReceptorId: 5, alicuotaIvaId: 5,
});
if (res.ok) console.log("CAE:", res.data.CAE);
else console.error("Error:", res.data.error);<?php
$BASE = "http://localhost:5014/api/afip";
function afip(string $path, array $payload): array {
global $BASE;
$ch = curl_init($BASE . $path);
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ["Content-Type: application/json"],
CURLOPT_POSTFIELDS => json_encode($payload),
]);
$res = json_decode(curl_exec($ch), true);
curl_close($ch);
return $res;
}
// 1) Login (una vez por CUIT)
afip("/login", [
"cuit" => 20238233195, "servicio" => "wsfe",
"certificadoPath" => "C:\\Certificados\\cert.pfx",
"certificadoPassword" => "clave", "produccion" => false,
]);
// 2) Emitir
$res = afip("/emitir", [
"cuit" => 20238233195, "produccion" => false,
"puntoVenta" => 1, "tipoComprobante" => 6, "concepto" => 1,
"documentoTipo" => 99, "documentoNumero" => 0,
"importeTotal" => 121, "importeGravado" => 100, "importeIva" => 21,
"moneda" => "PES", "cotizacion" => 1,
"condicionIvaReceptorId" => 5, "alicuotaIvaId" => 5,
]);
echo $res["ok"] ? "CAE: " . $res["data"]["CAE"] : "Error: " . $res["data"]["error"];* Cliente en 3 capas: AfipApi / FacturadorAfip / AfipHelpers
loFact = NEWOBJECT("FacturadorAfip", "FacturadorAfip.prg", "", ;
"http://localhost:5014", 20238233195, .F., ;
"C:\Certificados\cert.pfx", "clave")
loFact.Inicializar() && /login (registra cert + token)
loEmi = loFact.EmitirFactura( ;
1, 6, 1, 99, 0, ; && PV, tipo, concepto, docTipo, docNro
121, 0, 0, 100, 21, ; && total, noGrav, exento, gravado, IVA
"PES", 1, 5, 5, "", "", "") && moneda, cotiz, condIVA, alicIVA, fechas
IF loEmi.Ok
? "CAE:", loEmi.CAE
ENDIFTodos cuelgan de /api/afip. Los POST de tablas toman { cuit, produccion }.