Python client and strict mapper for the Italian Police Ca.R.G.O.S. API
Project description
cargos-api
A small Python library to build and submit rental booking records to the Italian Police Ca.R.G.O.S. API.
Table of Contents
- cargos-api
- Table of Contents
- Install
- Quick start
- Formatting the data
- API usage notes
- Inspecting the record as a mapping
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,contactSecondDriver: same asCustomer(withoutresidence); if present, all fields are mandatoryCar:type_code,brand,model,plate,color(optional),has_gps(optional),has_immobilizer(optional)Address:location_code,streetOperator: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 underCONDUCENTE2_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.addressis emitted as free-text in the record when providedAddress.address_countryis 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
CatalogLoaderif 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_keymust 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; usesend_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 namesInvalidInput: missing fields → read the error message for which fields are missingInvalidResponse: HTTP errors → network issues or server response witherrorefield
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
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
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8c8d24ca6869c3c8f7d5c2677e1e765e3d12aa306d89e6f86808f5b1b2a1a1d3
|
|
| MD5 |
65afa85529d2f24f0c5797d1b92e4875
|
|
| BLAKE2b-256 |
e60afc2c4e732f3f746a122f5c4c7057c68443ed0521a3deec464f2dc4d7c565
|
Provenance
The following attestation bundles were made for cargos_api-0.2.4.tar.gz:
Publisher:
ci.yml on glizzykingdreko/cargos-api
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
cargos_api-0.2.4.tar.gz -
Subject digest:
8c8d24ca6869c3c8f7d5c2677e1e765e3d12aa306d89e6f86808f5b1b2a1a1d3 - Sigstore transparency entry: 589087521
- Sigstore integration time:
-
Permalink:
glizzykingdreko/cargos-api@9fd22bc13da4e9eae5506d0c301e4ee2b834d777 -
Branch / Tag:
refs/tags/v0.2.4 - Owner: https://github.com/glizzykingdreko
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
ci.yml@9fd22bc13da4e9eae5506d0c301e4ee2b834d777 -
Trigger Event:
push
-
Statement type:
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
42dc4a95c5beba001f7ffbb32e33e8bb6c5a2e504774bfdaad3461df8d67ec02
|
|
| MD5 |
37b0f957969b2e339c56cc1dce7ed338
|
|
| BLAKE2b-256 |
118f304e8b53d7c1cd745f985ebb44f0a1dd453fcf6b7b194003ba950d4c7c57
|
Provenance
The following attestation bundles were made for cargos_api-0.2.4-py3-none-any.whl:
Publisher:
ci.yml on glizzykingdreko/cargos-api
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
cargos_api-0.2.4-py3-none-any.whl -
Subject digest:
42dc4a95c5beba001f7ffbb32e33e8bb6c5a2e504774bfdaad3461df8d67ec02 - Sigstore transparency entry: 589087526
- Sigstore integration time:
-
Permalink:
glizzykingdreko/cargos-api@9fd22bc13da4e9eae5506d0c301e4ee2b834d777 -
Branch / Tag:
refs/tags/v0.2.4 - Owner: https://github.com/glizzykingdreko
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
ci.yml@9fd22bc13da4e9eae5506d0c301e4ee2b834d777 -
Trigger Event:
push
-
Statement type: