Skip to main content

Python client and strict mapper for the Italian Police Ca.R.G.O.S. API

Project description

cargos-api

PyPI Python Versions License

A small Python library to build and submit rental booking records to the Italian Police Ca.R.G.O.S. API.

Table of Contents


This repository was created to interact with the Ca.R.G.O.S. APIs for a client who needed to automate the submission of rental booking details to the Italian Police.

The official documentation (see docs.pdf) is difficult to follow and sparse on examples. The goal of this project is to provide a clean, documented Python module that makes the integration straightforward and consistent.

This module handles all the location -> id conversions, data formatting and submission to the Ca.R.G.O.S. API.


Install

pip install cargos-api

Quick start

from cargos_api import CargosAPI, CargosRecordMapper, models as m

# Credentials
api = CargosAPI(username="...", password="...", api_key="...48-chars...")

# Build a booking using codes from your catalogs (examples below use placeholder codes)
booking = m.BookingData(
    contract_id="CONTR-001",
    contract_datetime="2025-01-01T10:00:00",   # ISO-like; mapper outputs dd/mm/YYYY HH:MM
    payment_type_code="1",                     # per Ca.R.G.O.S. table
    checkout_datetime="2025-01-01T11:00:00",
    checkout_place=m.Address(location_code=403015146, street="Via X 1"),  # Roma (example)
    checkin_datetime="2025-01-02T11:00:00",
    checkin_place=m.Address(location_code=402020327, street="Via Y 2"),    # Verona (example)
    operator=m.Operator(
        id="SYSTEM",
        agency_id="1",
        agency_name="ACME",
        agency_place_code=403015146,
        agency_address="Via Z 3",
        agency_phone="0000",
    ),
    car=m.Car(
        type_code="A",  # vehicle type code (per table)
        brand="Fiat",
        model="Panda",
        plate="AB123CD",
        color="Bianco",
    ),
    customer=m.Customer(
        surname="Rossi",
        name="Mario",
        birth_date="1990-01-01",
        birth_place_code=401028044,           # Genova (example)
        citizenship_code=100000001,           # Italia (example)
        id_doc_type_code="CI",
        id_doc_number="XYZ12345",
        id_doc_issuing_place_code=401028044,
        driver_licence_number="LIC123456",
        driver_licence_issuing_place_code=401028044,
        contact="0000000000",
    ),
)

# Map to Ca.R.G.O.S. fixed-width record (1505 chars)
record = CargosRecordMapper().build_record(booking)

# Validate or send
api.check_contracts([record])
# api.send_contracts([record])

Formatting the data

This library exposes typed dataclasses in cargos_api.models that you fill with your normalized data and pass to the mapper.

  • BookingData: contract_id, contract_datetime, payment_type_code, checkout_datetime, checkout_place (Address), checkin_datetime, checkin_place (Address), operator (Operator), car (Car), customer (Customer), second_driver (optional)
  • Customer: surname, name, birth_date, birth_place_code, citizenship_code, residence (Address, optional), id_doc_type_code, id_doc_number, id_doc_issuing_place_code, driver_licence_number, driver_licence_issuing_place_code, contact
  • SecondDriver: same as Customer (without residence); if present, all fields are mandatory
  • Car: type_code, brand, model, plate, color (optional), has_gps (optional), has_immobilizer (optional)
  • Address: location_code, street
  • Operator: id, agency_id, agency_name, agency_place_code, agency_address, agency_phone

Ca.R.G.O.S. Tracciato Record Parameters

Name Required Description
CONTRATTO_ID Unique contract identifier
CONTRATTO_DATA Contract date (format gg/mm/aaaa hh:mm)
CONTRATTO_TIPOP Payment type (see TABELLA TIPO PAGAMENTI)
CONTRATTO_CHECKOUT_DATA Checkout date (format gg/mm/aaaa hh:mm)
CONTRATTO_CHECKOUT_LUOGO_COD Police location code (TABELLA LUOGHI POLIZIA)
CONTRATTO_CHECKOUT_INDIRIZZO Checkout address (length > 3)
CONTRATTO_CHECKIN_DATA Check-in date (format gg/mm/aaaa hh:mm)
CONTRATTO_CHECKIN_LUOGO_COD Police location code (TABELLA LUOGHI POLIZIA)
CONTRATTO_CHECKIN_INDIRIZZO Check-in address (length > 3)
OPERATORE_ID Operator identifier
AGENZIA_ID Agency identifier (unique)
AGENZIA_NOME Agency name
AGENZIA_LUOGO_COD Police location code (TABELLA LUOGHI POLIZIA)
AGENZIA_INDIRIZZO Agency address (length > 3)
AGENZIA_RECAPITO_TEL Agency phone number (length > 3)
VEICOLO_TIPO Vehicle type (TABELLA TIPO VEICOLO)
VEICOLO_MARCA Vehicle brand
VEICOLO_MODELLO Vehicle model
VEICOLO_TARGA Vehicle plate number (length > 3)
VEICOLO_COLORE Vehicle color
VEICOLO_GPS GPS presence flag
VEICOLO_BLOCCOM Immobilizer presence flag
CONDUCENTE_CONTRAENTE_COGNOME Driver’s surname
CONDUCENTE_CONTRAENTE_NOME Driver’s name
CONDUCENTE_CONTRAENTE_NASCITA_DATA Driver’s date of birth (gg/mm/aaaa)
CONDUCENTE_CONTRAENTE_NASCITA_LUOGO_COD Birthplace (COMUNE ITALIANO or STATO ESTERO)
CONDUCENTE_CONTRAENTE_CITTADINANZA_COD Citizenship code (TABELLA LUOGHI POLIZIA)
CONDUCENTE_CONTRAENTE_RESIDENZA_LUOGO_COD ❌* Residence (COMUNE ITALIANO or STATO ESTERO)
CONDUCENTE_CONTRAENTE_RESIDENZA_INDIRIZZO ❌* Residence address (e.g., “VIA DEL CASTRO PRETORIO 10, ROMA”)
CONDUCENTE_CONTRAENTE_DOCIDE_TIPO_COD Document type (TABELLA DOCUMENTI POLIZIA)
CONDUCENTE_CONTRAENTE_DOCIDE_NUMERO Document number (length > 4)
CONDUCENTE_CONTRAENTE_DOCIDE_LUOGORIL_COD Document issuing place (COMUNE ITALIANO or STATO ESTERO)
CONDUCENTE_CONTRAENTE_PATENTE_NUMERO Driver’s license number (length > 4)
CONDUCENTE_CONTRAENTE_PATENTE_LUOGORIL_COD License issuing place (COMUNE ITALIANO or STATO ESTERO)
CONDUCENTE_CONTRAENTE_RECAPITO Driver’s contact number
CONDUCENTE2_COGNOME ❌** Second driver surname
CONDUCENTE2_NOME ❌** Second driver name
CONDUCENTE2_NASCITA_DATA ❌** Second driver date of birth (gg/mm/aaaa)
CONDUCENTE2_NASCITA_LUOGO_COD ❌** Second driver birthplace (COMUNE ITALIANO or STATO ESTERO)
CONDUCENTE2_CITTADINANZA_COD ❌** Second driver citizenship (TABELLA LUOGHI POLIZIA)
CONDUCENTE2_DOCIDE_TIPO_COD ❌** Second driver document type
CONDUCENTE2_DOCIDE_NUMERO ❌** Second driver document number
CONDUCENTE2_DOCIDE_LUOGORIL_COD ❌** Second driver document issuing place
CONDUCENTE2_PATENTE_NUMERO ❌** Second driver license number (length > 4)
CONDUCENTE2_PATENTE_LUOGORIL_COD ❌** Second driver license issuing place
CONDUCENTE2_RECAPITO ❌** Second driver contact number

Notes

  • * → Both residence fields (LUOGO_COD and INDIRIZZO) must be filled together, otherwise the data is rejected.
  • ** → If a second driver is present, all fields under CONDUCENTE2_ become mandatory.
  • Each block of records must not contain more than 100 contracts (rows).

Required fields

The mapper validates inputs and raises InvalidInput if anything is missing:

  • booking: id, creation_date, from_date, to_date
  • customer: birth_date, firstname, lastname, birth_place, citizenship, and one of (document_id, driver_licence_number) and one of (cellphone, email)
  • car: brand, model, plate, color
  • delivery_place: address_city, address
  • return_place: address_city, address
  • operator: id, agency_id, agency_name, city, address, phone

Optional fields

  • Customer.address is emitted as free-text in the record when provided
  • Address.address_country is currently not mapped to a dedicated field

Lookup tables (locations, documents, payments, vehicles)

  • Packaged CSV catalogs under cargos_api/data/ are used at runtime:
    • luoghi.csv (location/country codes)
    • tipo_documento.csv (document types)
    • tipo_pagamento.csv (payment types)
    • tipo_veicolo.csv (vehicle types)
  • Lookups are case-insensitive; expired locations (rows with DataFineVal) are ignored
  • Use CatalogLoader if you need to resolve human-readable labels to Ca.R.G.O.S. codes in your app:
    from cargos_api.locations_loader import CatalogLoader
    code = CatalogLoader().document_type_code('CI')
    
  • If a required code is not found, the mapper raises a ValueError

Inspecting the record as a mapping

Sometimes you want to verify exactly what each field contains after padding/truncation. You can ask the mapper to return both the fixed-width string and a JSON-like mapping of field names to their exact slices by passing with_map=True:

from cargos_api import CargosRecordMapper, models as m

booking = m.BookingData(
    contract_id="123", contract_datetime="2025-01-05T09:00:00", payment_type_code="1",
    checkout_datetime="2025-01-06T10:00:00", checkout_place=m.Address(location_code=403015146, street="Via A 10"),
    checkin_datetime="2025-01-07T10:00:00", checkin_place=m.Address(location_code=403015146, street="Via B 20"),
    operator=m.Operator(id="SYS", agency_id="AG1", agency_name="ACME", agency_place_code=403015146, agency_address="Via C 30", agency_phone="06..."),
    car=m.Car(type_code="A", brand="VW", model="Golf", plate="ZZ999ZZ"),
    customer=m.Customer(
        surname="Bianchi", name="Anna", birth_date="1985-05-20",
        birth_place_code=403015146, citizenship_code=100000001,
        id_doc_type_code="CI", id_doc_number="X1", id_doc_issuing_place_code=403015146,
        driver_licence_number="L1", driver_licence_issuing_place_code=403015146,
    ),
)
record, mapping = CargosRecordMapper().build_record(booking, with_map=True)
print(len(record))              # 1505
print(mapping["CONTRATTO_ID"])  # 50-char padded slice for the contract ID

API usage notes

  • CargosAPI.get_token() fetches the token using HTTP Basic auth
  • The api_key must be exactly 48 characters: first 32 chars are the AES key and the last 16 chars are the IV used to encrypt the bearer token
  • Use check_contracts(records) to validate records before submission; use send_contracts(records) to submit them

Example: minimal end-to-end flow

from cargos_api import CargosAPI, CargosRecordMapper, models as m

api = CargosAPI(username="ORG", password="PASS", api_key="...48-chars...")
booking = m.BookingData(
    contract_id="123",
    contract_datetime="2025-01-05T09:00:00",
    payment_type_code="1",
    checkout_datetime="2025-01-06T10:00:00",
    checkout_place=m.Address(location_code=403015146, street="Via A 10"),
    checkin_datetime="2025-01-07T10:00:00",
    checkin_place=m.Address(location_code=403015146, street="Via B 20"),
    operator=m.Operator(id="SYS", agency_id="AG1", agency_name="ACME", agency_place_code=403015146, agency_address="Via C 30", agency_phone="06..."),
    car=m.Car(type_code="A", brand="VW", model="Golf", plate="ZZ999ZZ", color="Nero"),
    customer=m.Customer(
        surname="Bianchi", name="Anna", birth_date="1985-05-20",
        birth_place_code=403015146, citizenship_code=100000001,
        id_doc_type_code="CI", id_doc_number="DOC1", id_doc_issuing_place_code=403015146,
        driver_licence_number="LIC1", driver_licence_issuing_place_code=403015146,
        contact="333...",
    ),
)
record = CargosRecordMapper().build_record(booking)
api.check_contracts([record])

Troubleshooting

  • ValueError: location not found → check the spelling of city/country names
  • InvalidInput: missing fields → read the error message for which fields are missing
  • InvalidResponse: HTTP errors → network issues or server response with errore field

Building something with it?

If you nee dhelp implementing this in your project, please reach out.

Author

If you found this project helpful or interesting, consider starring the repo and following me for more security research and tools, or buy me a coffee to keep me up

GitHub Twitter Medium Discord Email Buy Me a Coffee


Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

cargos_api-0.2.4.tar.gz (127.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

cargos_api-0.2.4-py3-none-any.whl (125.3 kB view details)

Uploaded Python 3

File details

Details for the file cargos_api-0.2.4.tar.gz.

File metadata

  • Download URL: cargos_api-0.2.4.tar.gz
  • Upload date:
  • Size: 127.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for cargos_api-0.2.4.tar.gz
Algorithm Hash digest
SHA256 8c8d24ca6869c3c8f7d5c2677e1e765e3d12aa306d89e6f86808f5b1b2a1a1d3
MD5 65afa85529d2f24f0c5797d1b92e4875
BLAKE2b-256 e60afc2c4e732f3f746a122f5c4c7057c68443ed0521a3deec464f2dc4d7c565

See more details on using hashes here.

Provenance

The following attestation bundles were made for cargos_api-0.2.4.tar.gz:

Publisher: ci.yml on glizzykingdreko/cargos-api

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file cargos_api-0.2.4-py3-none-any.whl.

File metadata

  • Download URL: cargos_api-0.2.4-py3-none-any.whl
  • Upload date:
  • Size: 125.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for cargos_api-0.2.4-py3-none-any.whl
Algorithm Hash digest
SHA256 42dc4a95c5beba001f7ffbb32e33e8bb6c5a2e504774bfdaad3461df8d67ec02
MD5 37b0f957969b2e339c56cc1dce7ed338
BLAKE2b-256 118f304e8b53d7c1cd745f985ebb44f0a1dd453fcf6b7b194003ba950d4c7c57

See more details on using hashes here.

Provenance

The following attestation bundles were made for cargos_api-0.2.4-py3-none-any.whl:

Publisher: ci.yml on glizzykingdreko/cargos-api

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page