Esta notebook fue creada originalmente como un blog post por Raúl E. López Briega en Matemáticas, Analisis de datos y Python. El contenido esta bajo la licencia BSD.
Si quieres algo que nunca tuviste, debes estar dispuesto a hacer algo que nunca hiciste
Conectar aplicaciones a los servicios web de ARCA puede ser un dolor de cabeza. Documentación confusa, autenticación engorrosa y pelear contra estrucuturas de datos inconsistentes entre cada servicio. Como estaba armando un proyecto personal y no encontré ninguna librería que sea efectiva para solucionar estos problemas; decidí escribir una propia.
Si necesitas integrar tu aplicación con los servicios web de ARCA, mí librería te proporcionará las herramientas necesarias para hacerlo de manera eficiente, segura y sin complicaciones. En este artículo, te mostraré qué es Arca Arg, cómo funciona y como puede ayudarte también a tí en tu proyecto.
Arca Arg es un cliente en Python para acceder a los servicios web de ARCA (Administración Federal de Ingresos Públicos de Argentina). Maneja la autenticación y la comunicación con los servicios SOAP de ARCA de forma sencilla y permite cominicarse con todos los servicios web de ARCA](https://www.afip.gob.ar/ws/) utilizando la misma interfase.
Algunas de las ventajas que vas a encontrar al utilizar mi librería son:
Ahora que sabes por qué deberías usar Arca Arg, veamos cómo instalarla y configurarla en tu entorno de desarrollo.
Para instalar la librería, solo necesitas ejecutar el siguiente comando:
pip install arca_arg
¡Así de fácil! Una vez instalada, estás listo para comenzar a utilizarla.
Para empezar a interactuar con los servicios en los entornos de homologación, primero vamos a necesitar obtener el certificado y la clave privada y adherirnos a los servicios que vamos a utilizar desde la página de ARCA, accediendo con nuestra clave fiscal. Pero antes de ir a hacer esto, debemos realizar los siguientes pasos:
openssl genrsa -out [nombre_tu_key].key 2048
Este archivo key es muy importante porque representa la contraseña con la que va a funcionar el certificado así que no debemos guardalo en un lugar seguro y no perderlo.
openssl req -new -key [key_generada_punto1].key -subj "/C=AR/O=[nombre empresa]/CN=[nombre certificado]/serialNumber=CUIT [tu CUIT]" -out [nombre archivo].csr
En donde:
[key_generada_punto1]
es el nombre del archivo key generado en el paso anterior.
[nombre empresa]
es el nombre de la empresa para quien es el certificado. En el ambiente de homologación podemos utilizar un nombre que haga referencia a que es para el ambiente de test.
[nombre certificado]
es el nombre que va a tener nuestro certificado en ARCA. Solo se pueden utilizar letras y números.
[tu CUIT]
es tu CUIT o el de la empresa para quien es el certificado.
[nombre archivo]
es el nombre con que quieres que se guarde el archivo CSR. No es tan importante, ya que una vez que utilicemos este archivo para obetner el certificado en ARCA lo vamos a poder eliminar.
Por ejemplo en mi caso yo utilicé:
openssl req -new -key rauloTest.key -subj "/C=AR/O=rauloTest/CN=rauloTest/serialNumber=CUIT 20293188204" -out rauloTest.csr
Dentro de nuestro escritorio de ARCA debemos ingresar en «WSASS - Autogestión Certificados Homologación»
Dentro de esta aplicación debemos ir a «Nuevo Certificado»
En esta pantalla en 1. Nombre simbólico del DN
ingresamos el nombre con el que generamos el CSR en el punto anterior. En mi ejemplo "rauloTest" (CN=rauloTest).
Y luego en el punto 3. Solicitud de certificado en formato PKCS#10
debemos pegar el contenido del mismo archivo CSR que generamos. Por último, presionamos el botón Crear DN y obtener certificado
En resultado
debajo se nos generara el certificado, este debemos copiar el contenido y guardarlo en nuestra computadora junto con la key para usarlo luego en la librería. Yo por ejemplo lo guardo con el formato archivo.cert
para distinguirlo de otros archivos.
Allí, en 1. Nombre simbólico del DN a autorizar
debemos seleccionar el certificado que queremos autorizar. En 3. CUIT representado
debemos ingresar el CUIT con el cual queremos utilizar el web service. Y en 5. Servicio al que desea acceder
debemos elegir el web service a utilizar. Con todo esto listo debemos presionar en «Crear autorización de acceso»
y nos devolverá el resultado de la autorización.
Desde esta misma aplicación, podemos también acceder a «Autorizaciones»
para verificar que se creó la autorización correctamente
Bien, luego de estos laboriosos pasos, ya podemos comenzar a codear y utilizar la liberería. Veamos como utilizarla con un ejemplo del servicio de factura electrónica(WSFE).
# Instalar librería
!pip install arca_arg
# Importar las variables de configuración
import arca_arg.settings as confg
confg.PRIVATE_KEY_PATH = '/home/raul/arca/HOM/raulotest.key'
confg.CERT_PATH = '/home/raul/arca/HOM/arcaTestCert.pem'
confg.TA_FILES_PATH = '/home/raul/arca/HOM/'
confg.CUIT = '20293188204'
confg.PROD = False
Estás son las principales configuraciones que debemos realizar para que todo funcione correctamente:
CUIT
= "TU_CUIT_AQUI"PROD
= False # True para producciónCERT_PATH
= "carpeta con el certificado de arca"PRIVATE_KEY_PATH
= "Carpeta con el la clave privada"TA_FILES_PATH
="donde se guardaran temporalmente los token de acceso"# Importamos el objeto principal y algunas constantes de ayuda
from arca_arg.webservice import ArcaWebService
from arca_arg.settings import WSDL_FEV1_HOM, WS_LIST
# Nombre de los principales servicios
# si el servicio que quieres utilizar no está aquí no importa
# es solo una ayuda de los nombres de los servicos para iniciar
# el webservide
WS_LIST
['ws_sr_constancia_inscripcion', 'ws_sr_padron_a10', 'ws_sr_padron_a13', 'wsfecred', 'wsfe', 'wsfex', 'wslpg', 'wscpe', 'wsapoc', 'wsagr', 'wsrgiva', 'wsct', 'sire-ws', 'wsremharina', 'wsremazucar', 'wsremcarne']
# Servicio de Factuara Electrónica
arca = ArcaWebService(WSDL_FEV1_HOM, 'wsfe', enable_logging= False)
Para inicar el serviocio utilizamos el objeto ArcaWebService
con la url del WSDL del servicio (que en este caso ya la recuperamos desde las constantes de las configuraciones de la libería); el nombre del servico (que es uno de los nombres de la lista de ayuda); y tenemos un parámetro opcional para habilitar/desabilitar el logging(está habilitado por defecto).
# listamos los request que podemos realizar en el servicio
print(arca.list_methods())
['FECAESolicitar', 'FECompTotXRequest', 'FEDummy', 'FECompUltimoAutorizado', 'FECompConsultar', 'FECAEARegInformativo', 'FECAEASolicitar', 'FECAEASinMovimientoConsultar', 'FECAEASinMovimientoInformar', 'FECAEAConsultar', 'FEParamGetCotizacion', 'FEParamGetTiposTributos', 'FEParamGetTiposMonedas', 'FEParamGetTiposIva', 'FEParamGetTiposOpcional', 'FEParamGetTiposConcepto', 'FEParamGetPtosVenta', 'FEParamGetTiposCbte', 'FEParamGetCondicionIvaReceptor', 'FEParamGetTiposDoc', 'FEParamGetTiposPaises', 'FEParamGetActividades', 'FECAESolicitar', 'FECompTotXRequest', 'FEDummy', 'FECompUltimoAutorizado', 'FECompConsultar', 'FECAEARegInformativo', 'FECAEASolicitar', 'FECAEASinMovimientoConsultar', 'FECAEASinMovimientoInformar', 'FECAEAConsultar', 'FEParamGetCotizacion', 'FEParamGetTiposTributos', 'FEParamGetTiposMonedas', 'FEParamGetTiposIva', 'FEParamGetTiposOpcional', 'FEParamGetTiposConcepto', 'FEParamGetPtosVenta', 'FEParamGetTiposCbte', 'FEParamGetCondicionIvaReceptor', 'FEParamGetTiposDoc', 'FEParamGetTiposPaises', 'FEParamGetActividades']
# Si queremos utilizar FECAESolicitar
# podemos usar la ayuda para revisar sus parámetros.
arca.method_help('FECAESolicitar')
'FECAESolicitar(Auth: ns0:FEAuthRequest, FeCAEReq: ns0:FECAERequest) -> FECAESolicitarResult: ns0:FECAEResponse'
# Vemos que tiene un tipo FEAuthRequest y un tipo FECAERequest
# podemos revisar la definición de estos tipos con el siguiente método
arca.get_type('FEAuthRequest')
{ 'Token': None, 'Sign': None, 'Cuit': None }
arca.get_type('FECAERequest')
{ 'FeCabReq': 'FECAECabRequest', 'FeDetReq': 'ArrayOfFECAEDetRequest' }
arca.get_type('FECAECabRequest')
{ 'CantReg': None, 'PtoVta': None, 'CbteTipo': None }
Esto ya nos da una idea de como es la estructura del request que debemos enviar al servicio. Lo bueno es que también podemos utilizar el método get_type
como armazón para el request asignandolo a una variable.
# Armando los datos para el request
Auth = arca.get_type('FEAuthRequest')
Auth['Token'] = arca.token
Auth['Sign'] = arca.sign
Auth['Cuit'] = arca.cuit
FeCabReq = arca.get_type('FECAECabRequest')
FeCabReq['CantReg'] = 1
FeCabReq['PtoVta'] = 1
FeCabReq['CbteTipo'] = 1
# Esto es opcional también se pueden generar los datos con diccionarios
FECAEDetRequest = {
'Concepto' : 1,
'DocTipo' : 80,
'DocNro': 27293188217,
'CbteDesde': 7,
'CbteHasta': 7,
'CbteFch': "20250124",
'ImpTotal':121,
'ImpTotConc': 0,
'ImpNeto': 100,
'ImpOpEx': 0,
'ImpIVA': 21,
'ImpTrib': 0,
'MonId': "PES",
'MonCotiz':1,
'Iva': {'AlicIva': {'Id': 5, 'BaseImp': 100, 'Importe': 21}}
}
# Terminamos de unir los datos para enviar el request
data = {'Auth': Auth,
'FeCAEReq': { 'FeCabReq': FeCabReq, 'FeDetReq': {'FECAEDetRequest': FECAEDetRequest}}
}
# Enviamos el request y obtenemos la respuesta del servicio
arca.send_request('FECAESolicitar', data)
{ 'FeCabResp': { 'Cuit': 20293188204, 'PtoVta': 1, 'CbteTipo': 1, 'FchProceso': '20250128183526', 'CantReg': 1, 'Resultado': 'A', 'Reproceso': 'N' }, 'FeDetResp': { 'FECAEDetResponse': [ { 'Concepto': 1, 'DocTipo': 80, 'DocNro': 27293188217, 'CbteDesde': 7, 'CbteHasta': 7, 'CbteFch': '20250124', 'Resultado': 'A', 'Observaciones': { 'Obs': [ { 'Code': 10217, 'Msg': 'El credito fiscal discriminado en el presente comprobante solo podra ser computado a efectos del Procedimiento permanente de transicion al Regimen General.' } ] }, 'CAE': '75044220307741', 'CAEFchVto': '20250203' } ] }, 'Events': None, 'Errors': None }
Como podemos ver, es bastante simple y fácil utilizar la libería. Veamos otro ejemplo con otro servicio para demostrar que la interface es exactamente igual.
from arca_arg.settings import WSDL_CONSTANCIA_HOM
arca2 = ArcaWebService(WSDL_CONSTANCIA_HOM, 'ws_sr_constancia_inscripcion', enable_logging=False)
arca2.list_methods()
['getPersona', 'getPersonaList', 'getPersona_v2', 'dummy', 'getPersonaList_v2']
# Request dummy para verificar el estado del servicio
arca2.send_request('dummy', {})
{ 'appserver': 'OK', 'authserver': 'OK', 'dbserver': 'OK' }
# ver que necesitamos para usar getPersona_v2
arca2.method_help('getPersona_v2')
'getPersona_v2(token: xsd:string, sign: xsd:string, cuitRepresentada: xsd:long, idPersona: xsd:long) -> personaReturn: ns0:personaReturn'
# En este caso no hay tipos complejos podemos armar los datos directamente
data = {
'token':arca2.token,
'sign': arca2.sign,
'cuitRepresentada': arca2.cuit,
'idPersona':20224107030
}
arca2.send_request('getPersona_v2', data)
{ 'datosGenerales': { 'apellido': 'FRANCO AGUSTIN', 'caracterizacion': [ { 'descripcionCaracterizacion': 'CUENTA CORRIENTE', 'idCaracterizacion': 82, 'periodo': 20160714 }, { 'descripcionCaracterizacion': 'CATEGORÍA A: MUY BAJO RIESGO', 'idCaracterizacion': 354, 'periodo': 20161025 } ], 'dependencia': None, 'domicilioFiscal': { 'codPostal': '1828', 'datoAdicional': None, 'descripcionProvincia': 'BUENOS AIRES', 'direccion': 'ALEM 5982', 'idProvincia': 1, 'localidad': 'BANFIELD', 'tipoDatoAdicional': None, 'tipoDomicilio': 'FISCAL' }, 'esSucesion': 'NO', 'estadoClave': 'ACTIVO', 'fechaContratoSocial': None, 'fechaFallecimiento': None, 'idPersona': 20224107030, 'mesCierre': 12, 'nombre': 'SEVERINO', 'razonSocial': None, 'tipoClave': 'CUIT', 'tipoPersona': 'FISICA' }, 'datosMonotributo': None, 'datosRegimenGeneral': { 'actividad': [ { 'descripcionActividad': 'ALQUILER DE EFECTOS PERSONALES Y ENSERES DOMÉSTICOS N.C.P.', 'idActividad': 772099, 'nomenclador': 883, 'orden': 1, 'periodo': 201706 } ], 'categoriaAutonomo': None, 'impuesto': [ { 'descripcionImpuesto': 'GANANCIAS PERSONAS FISICAS', 'idImpuesto': 11, 'periodo': 200512 }, { 'descripcionImpuesto': 'IVA', 'idImpuesto': 30, 'periodo': 200705 }, { 'descripcionImpuesto': 'APORTES SEG.SOCIAL AUTONOMOS', 'idImpuesto': 308, 'periodo': 200512 } ], 'regimen': [] }, 'errorConstancia': None, 'errorMonotributo': None, 'errorRegimenGeneral': None, 'metadata': { 'fechaHora': datetime.datetime(2025, 1, 28, 18, 36, 9, 45000, tzinfo=<FixedOffset '-03:00'>), 'servidor': 'setiwsh2' } }
Incluso con una librería bien diseñada, pueden surgir problemas. Aquí te dejo algunos errores comunes y cómo solucionarlos.
Credenciales Incorrectas: Si recibes un error de autenticación, verifica que estás usando la API Key y el Secret correctos.
Endpoints Incorrectos: Asegúrate de que estás llamando al endpoint correcto. Un error tipográfico puede hacer que tu petición falle.
Problemas de Conectividad: Si experimentas fallos intermitentes, revisa tu conexión a internet y asegúrate de que los servidores de Arca están operativos.
Con esto concluye está presentación. Recuerden que también pueden consultar el código en Github
Saludos!
Este post fue escrito por Raúl e. López Briega utilizando Jupyter notebook. Pueden descargar este notebook o ver su version estática en nbviewer.