Crear factura electrónica de ARCA en Delphi
Con pocas líneas de código

Si es tu primera vez conectándote con la facturación electrónica de ARCA, te recomiendo leer esta guía básica sobre su funcionamiento general.

Conectar tu sistema con la facturación electrónica de ARCA
Guía paso a paso
El primer paso para crear una factura electrónica de ARCA en Delphi es obtener el Código de Autorización Electrónico o CAE.
Esto lo vamos a hacer utilizando Afip SDK que nos permite conectarnos a los web services de ARCA sin complicarnos con el uso de SOAP y la autenticación.
Obtener la autorización
Lo primero que tenemos hacer es obtener el “Token authorization”, que seria la autorización en ARCA.
Para usar los web services de ARCA, se requiere un certificado digital, con Afip SDK puedes integrarte en modo desarrollo usando el CUIT 20409378472
sin necesidad de obtener un certificado, para poder integrarte lo más rápido posible.
Te dejo este enlace por si luego quieres usar tu propio certificado para desarrollo.
Debemos ejecutar una solicitud POST al endpoint
https://app.afipsdk.com/api/v1/afip/auth
A continuación, se muestra el código Delphi equivalente:
uses
System.SysUtils, System.Classes, System.Net.HttpClient, System.Net.URLClient, System.JSON;
procedure ObtenerAutorizacion;
var
Client: THTTPClient;
AuthURL: string;
AuthData: TJSONObject;
Response: IHTTPResponse;
Token, Sign: string;
AuthResponse: TJSONObject;
begin
Client := THTTPClient.Create;
try
AuthURL := 'https://app.afipsdk.com/api/v1/afip/auth';
AuthData := TJSONObject.Create;
try
AuthData.AddPair('environment', 'dev');
AuthData.AddPair('tax_id', '20409378472'); // CUIT a utilizar
AuthData.AddPair('wsid', 'wsfe');
Response := Client.Post(AuthURL,
TStringStream.Create(AuthData.ToString, TEncoding.UTF8), nil,
[TNetHeader.Create('Content-Type', 'application/json')]);
if Response.StatusCode <> 200 then
begin
WriteLn(Format('Error en la autorización: %d', [Response.StatusCode]));
Exit;
end;
AuthResponse := TJSONObject.ParseJSONValue(Response.ContentAsString(TEncoding.UTF8)) as TJSONObject;
try
Token := AuthResponse.GetValue<string>('token');
Sign := AuthResponse.GetValue<string>('sign');
WriteLn('Token: ' + Token);
WriteLn('Sign: ' + Sign);
finally
AuthResponse.Free;
end;
finally
AuthData.Free;
end;
finally
Client.Free;
end;
end;
Ahora tenemos token y sign que nos dio ARCA para usar el web service. No es necesario que lo guardemos, Afip SDK se encarga de esto por nosotros, debemos solicitarlo antes de cada llamada a los métodos del web service.
Crear la factura
Vamos a crear una Factura B por un importe de $121. En nuestro código, añadimos la siguiente lógica:
Debemos ejecutar una solicitud POST al endpoint
https://app.afipsdk.com/api/v1/afip/requests
uses
System.SysUtils, System.Classes, System.Net.HttpClient, System.Net.URLClient, System.JSON;
procedure CrearFactura(const Token, Sign: string);
var
Client: THTTPClient;
InvoiceURL: string;
InvoiceData, ParamsData, AuthData, FeCabReq, FeDetReq, FECAEDetRequest, FeCAEReq: TJSONObject;
IvaArray: TJSONArray;
IvaItem: TJSONObject;
Response: IHTTPResponse;
InvoiceResponse: TJSONObject;
begin
Client := THTTPClient.Create;
try
InvoiceURL := 'https://app.afipsdk.com/api/v1/afip/requests';
// Construir el objeto JSON para la factura
InvoiceData := TJSONObject.Create;
try
InvoiceData.AddPair('environment', 'dev');
InvoiceData.AddPair('method', 'FECAESolicitar');
InvoiceData.AddPair('wsid', 'wsfe');
// Construir el objeto Params
ParamsData := TJSONObject.Create;
try
// Objeto Auth
AuthData := TJSONObject.Create;
AuthData.AddPair('Token', Token);
AuthData.AddPair('Sign', Sign);
AuthData.AddPair('Cuit', '20409378472'); // CUIT utilizado
ParamsData.AddPair('Auth', AuthData);
// Objeto FeCAEReq
FeCAEReq := TJSONObject.Create;
try
// FeCabReq
FeCabReq := TJSONObject.Create;
FeCabReq.AddPair('CantReg', TJSONNumber.Create(1));
FeCabReq.AddPair('PtoVta', TJSONNumber.Create(1));
FeCabReq.AddPair('CbteTipo', TJSONNumber.Create(6));
FeCAEReq.AddPair('FeCabReq', FeCabReq);
// FeDetReq
FeDetReq := TJSONObject.Create;
try
FECAEDetRequest := TJSONObject.Create;
FECAEDetRequest.AddPair('Concepto', TJSONNumber.Create(1));
FECAEDetRequest.AddPair('DocTipo', TJSONNumber.Create(99)); // 99: Consumidor final
FECAEDetRequest.AddPair('DocNro', TJSONNumber.Create(0));
FECAEDetRequest.AddPair('CbteDesde', TJSONNumber.Create(1));
FECAEDetRequest.AddPair('CbteHasta', TJSONNumber.Create(1));
FECAEDetRequest.AddPair('CbteFch', FormatDateTime('yyyymmdd', Now));
FECAEDetRequest.AddPair('ImpTotal', TJSONNumber.Create(121));
FECAEDetRequest.AddPair('ImpTotConc', TJSONNumber.Create(0));
FECAEDetRequest.AddPair('ImpNeto', TJSONNumber.Create(100));
FECAEDetRequest.AddPair('ImpOpEx', TJSONNumber.Create(0));
FECAEDetRequest.AddPair('ImpIVA', TJSONNumber.Create(21));
FECAEDetRequest.AddPair('ImpTrib', TJSONNumber.Create(0));
FECAEDetRequest.AddPair('MonId', 'PES');
FECAEDetRequest.AddPair('MonCotiz', TJSONNumber.Create(1));
// Array de IVA: un elemento con Id = 5, BaseImp = 100 e Importe = 21
IvaArray := TJSONArray.Create;
IvaItem := TJSONObject.Create;
IvaItem.AddPair('Id', TJSONNumber.Create(5));
IvaItem.AddPair('BaseImp', TJSONNumber.Create(100));
IvaItem.AddPair('Importe', TJSONNumber.Create(21));
IvaArray.AddElement(IvaItem);
FECAEDetRequest.AddPair('Iva', IvaArray);
FeDetReq.AddPair('FECAEDetRequest', FECAEDetRequest);
FeCAEReq.AddPair('FeDetReq', FeDetReq);
except
FeDetReq.Free;
raise;
end;
ParamsData.AddPair('FeCAEReq', FeCAEReq);
InvoiceData.AddPair('@params', ParamsData);
// Enviar la solicitud POST para crear la factura
Response := Client.Post(InvoiceURL,
TStringStream.Create(InvoiceData.ToString, TEncoding.UTF8), nil,
[TNetHeader.Create('Content-Type', 'application/json')]);
if Response.StatusCode <> 200 then
begin
WriteLn(Format('Error al crear la factura: %d', [Response.StatusCode]));
Exit;
end;
InvoiceResponse := TJSONObject.ParseJSONValue(Response.ContentAsString(TEncoding.UTF8)) as TJSONObject;
try
WriteLn('Invoice: ' + InvoiceResponse.ToString);
finally
InvoiceResponse.Free;
end;
except
ParamsData.Free;
raise;
end;
finally
InvoiceData.Free;
end;
finally
Client.Free;
end;
end;
end;
En invoice tenemos el CAE y vencimiento correspondientes a la factura que acabamos de crear.
{
...
"CAE": "12345678987654",
"CAEFchVto": "20240327"
...
}
Problemas comunes
Si estás teniendo el error (10016) El número o fecha del comprobante no se corresponde con el próximo a autorizar te recomiendo leer este artículo.

Error (10016) El numero o fecha del comprobante no se corresponde con el proximo a autorizar
Pasos para resolver este error
Si estás teniendo el error (10242) El campo Condición IVA receptor es obligatorio. Consultar método FEParamGetCondicionIvaReceptor te recomiendo leer este artículo.

Error (10242) El campo Condicion IVA receptor es obligatorio
Pasos para resolver este error
Con la autorización creada ya podemos proceder a crear el PDF para presentarle a nuestro cliente. Puedes usar como base esta factura o ticket de ejemplo.
Luego, lo único que nos queda es pasar a modo producción, para más información de cómo hacerlo pueden dirigirse a la documentación de la librería https://docs.afipsdk.com/
Ante cualquier duda o pregunta al respecto, pueden resolverla rápidamente dentro de la Comunidad Afip SDK. Además, puedes unirte para estar al tanto de las novedades y problemas técnicos al usar los servicios de ARCA.