United Kingdom ๐ฌ๐ง CAA Registry โ
| Name | uk-caa-registry |
| Country | United Kingdom |
| Registration prefix | G- |
| Data source | https://ginfoapi.caa.co.uk (G-INFO REST API) |
| Format | JSON API (search + details endpoints; no bulk download) |
| Run frequency | Weekly (Monday, 06:10 UTC) |
| Depends on Mictronics for ICAO hex | No โ the G-INFO details payload includes the aircraft's ICAO 24-bit address directly (AircraftDetails.ICAO24BitAircraftAddress.Hex). |
How it works โ
G-INFO has no bulk-export endpoint, so this runner enumerates the entire register itself: it POSTs /api/aircraft/search once for every 2-letter suffix combination from AA to ZZ (676 calls total, via itertools.product), then, for each result with RegistrationStatus == "R", immediately calls GET /api/aircraft/details/{id} and writes the record โ there is no intermediate accumulation. Search calls are not rate-limited; details calls sleep for request_interval_seconds between requests to be polite to the API. Any call that returns HTTP 403 is queued and retried once at a fixed 500ms interval after the main enumeration pass finishes. Lookup tables decode the API's free-text AircraftClass into canonical aircraft.type/aircraft.category values and full English country names into ISO 3166-1 alpha-2 codes, falling back to the raw source value for anything unmapped. Every written record explicitly sets military: false โ this register is exclusively civil, and the explicit value ensures a stale military: true flag (from Mictronics or a prior record on a reused hex) is corrected on re-registration.
Whenever a record has an aircraft.type_designator, aircraft:type:{type_designator} is looked up in Redis (populated by the mictronics runner) and, if found, its manufacturer_model and description_code (ICAO Doc 8643 description code, e.g. L2J) are set directly on this record โ unconditionally, regardless of whether Mictronics also has values for the same hex. This runner's own type_designator is sourced directly from the CAA and is authoritative; merge_aircraft.lua's "registry wins over mictronics" precedence rule guarantees these values take priority at read time either way. The lookup is not a hard dependency โ a missing reference table entry, or the table not existing yet, leaves the record exactly as it would have been without this step.
Notable operational characteristic: because it makes 676 prefix search calls plus a details fetch per registered aircraft, a full run takes several hours. It is deliberately scheduled as the last runner of the day by the ofelia service's labels in docker-compose.core.yaml (0 10 6 * * 1, after ourairports at 0 10 5 * * 1) to avoid overlapping with other Monday jobs.
Columns โ
Fields below are grouped by the payload they come from: the POST /api/aircraft/search response (list of match summaries) and the GET /api/aircraft/details/{id} response (full nested record). Field names are otherwise unique except where noted as a duplicate.
Search response (POST /api/aircraft/search) โ
| Source field | Imported | Notes |
|---|---|---|
AircraftID | โ | Used to fetch the details payload; not stored |
RegistrationStatus | โ | Filters which AircraftIDs get a details fetch ("R" only); not stored |
Mark | โ | Duplicate of RegistrationDetails.Mark, which is read from the details payload instead |
SerialNo | โ | Duplicate of AircraftDetails.SerialNumber, which is read from the details payload instead |
MilitarySerialNo | โ | Present in source; never read (no equivalent field exists in the details payload) |
AircraftType | โ | Duplicate of AircraftDetails.Type, which is read from the details payload instead |
Details response (GET /api/aircraft/details/{id}) โ
| Source field | Imported | Notes |
|---|---|---|
RegistrationDetails.Mark | โ | โ registration (prefixed with G-) |
RegistrationDetails.Status | โ | Filtered to "Registered" only; not stored |
RegistrationDetails.PreviousID | โ | Present in source; not read by this runner |
RegistrationDetails.CurrentRegistrationDate | โ | Present in source; not read by this runner |
RegistrationDetails.DeRegistrationDate | โ | Present in source; not read by this runner |
RegistrationDetails.Reason | โ | Present in source; not read by this runner |
RegistrationDetails.To | โ | Present in source; not read by this runner |
AircraftDetails.Manufacturer | โ | โ aircraft.manufacturer |
AircraftDetails.Type | โ | โ aircraft.model |
AircraftDetails.SerialNumber | โ | โ aircraft.serial_number |
AircraftDetails.ICAO24BitAircraftAddress.Hex | โ | โ icao_hex; records without a 6-character hex are discarded |
AircraftDetails.ICAO24BitAircraftAddress.Binary | โ | Present in source; not read by this runner |
AircraftDetails.ICAO24BitAircraftAddress.Octal | โ | Present in source; not read by this runner |
AircraftDetails.PopularName | โ | Present in source; not read by this runner |
AircraftDetails.ICAOAircraftTypeDesignator | โ | โ aircraft.type_designator; also used to look up aircraft:type:{type_designator} in Redis, setting aircraft.manufacturer_model and aircraft.description_code when found |
AircraftDetails.AircraftClass | โ | โ aircraft.type / aircraft.category (decoded) |
AircraftDetails.BuildCategory | โ | Present in source; not read by this runner |
AircraftDetails.EasaCategory | โ | Present in source; not read by this runner |
AircraftDetails.Engines[0].TotalNumberOfEngines | โ | โ aircraft.powerplant.count |
AircraftDetails.Engines[0].Name | โ | โ aircraft.powerplant.model; only the first engine entry is used |
AircraftDetails.Engines[0].NumberOfEngines | โ | Distinct field from TotalNumberOfEngines (which is used); present in source, not read |
AircraftDetails.Engines[0].IsPropeller | โ | Present in source; not read by this runner |
AircraftDetails.Mtow | โ | Present in source; not read by this runner |
AircraftDetails.TotalAirframeHours | โ | Present in source; not read by this runner |
AircraftDetails.YearBuild | โ | โ aircraft.manufactured_date |
AircraftDetails.MaintenanceProgramme | โ | Present in source; not read by this runner |
AircraftDetails.Expiry | โ | Present in source; not read by this runner |
AircraftDetails.OwnershipStatus | โ | Present in source; not read by this runner |
AircraftDetails.MaximumPassengers | โ | โ aircraft.seats (MaximumPassengers + 1) |
AircraftDetails.MaximumTakeOffMass | โ | Present in source; not read by this runner (numeric duplicate of Mtow) |
AircraftDetails.CofaDetails.CofaCategory | โ | Present in source; not read by this runner |
AircraftDetails.CofaDetails.CofaValidityExpiryLabel | โ | Present in source; not read by this runner |
AircraftDetails.CofaDetails.CofaValidityExpiry | โ | Present in source; not read by this runner |
AircraftDetails.CofaDetails.CofaValidityReference | โ | Present in source; not read by this runner |
AircraftDetails.CofaDetails.CofaOperatingLimitations | โ | Present in source; not read by this runner |
AircraftDetails.CofaDetails.ShowOperatingLimitations | โ | Present in source; not read by this runner |
AircraftDetails.IsPotentialChangeOfOwnership | โ | Present in source; not read by this runner |
AircraftDetails.EmergencyBallisticDeviceFitted | โ | Present in source; not read by this runner |
MortgageDetails[].EntryDateAndTime | โ | Present in source; not read by this runner |
MortgageDetails[].EntryType | โ | Present in source; not read by this runner |
MortgageDetails[].ReferenceType | โ | Present in source; not read by this runner |
RegisteredAircraftOwners[0].RegisteredOwner | โ | โ registrant.names[0]; only the first owner is used |
RegisteredAircraftOwners[0].AddressIndicatorID | โ | Present in source; not read by this runner |
RegisteredAircraftOwners[0].AddressIndicator | โ | Present in source; not read by this runner |
RegisteredAircraftOwners[0].TradingAs | โ | Present in source; not read by this runner |
RegisteredAircraftOwners[0].TrusteeOf | โ | Present in source; not read by this runner |
RegisteredAircraftOwners[0].Address1 / Address2 | โ | โ registrant.street |
RegisteredAircraftOwners[0].Town | โ | โ registrant.city |
RegisteredAircraftOwners[0].County | โ | โ registrant.administrative_area |
RegisteredAircraftOwners[0].PostCode | โ | โ registrant.postal_code |
RegisteredAircraftOwners[0].Country | โ | โ registrant.country (decoded to ISO 3166-1 alpha-2 where known) |
AircraftOperatedByAocHolder.showSection | โ | Present in source; not read by this runner |
AircraftOperatedByAocHolder.OperatorName | โ | Present in source; not read by this runner (operator enrichment for G-registered aircraft is not sourced from here) |
AircraftOperatedByAocHolder.OperatorTrandingAs | โ | Present in source (sic โ typo in the live API); not read by this runner |
InsuranceSummaryDetails.EvidenceVerifiedDate | โ | Present in source; not read by this runner |
InsuranceSummaryDetails.NoFlyDate | โ | Present in source; not read by this runner |
InsuranceSummaryDetails.AircraftMarkStatusID | โ | Present in source; not read by this runner |
InsuranceSummaryDetails.AircraftID | โ | Present in source; not read by this runner (duplicate of the search result's AircraftID) |
InsuranceSummaryDetails.Mark | โ | Present in source; not read by this runner (duplicate of RegistrationDetails.Mark) |
NoiseSummaryDetails.NoiseCertificateIssueDate | โ | Present in source; not read by this runner |
NoiseSummaryDetails.NoiseCertificateNumber | โ | Present in source; not read by this runner |
NoiseSummaryDetails.NoiseChapter | โ | Present in source; not read by this runner |
RegistrationMarkExemption.IssueDate | โ | Present in source; not read by this runner |
RegistrationMarkExemption.Origin | โ | Present in source; not read by this runner |
RegistrationMarkExemption.CodeCarried | โ | Present in source; not read by this runner |
RegistrationMarkExemption.SerialCarried | โ | Present in source; not read by this runner |
OpenRegistrationCases[].CaseName | โ | Present in source; not read by this runner |
OpenRegistrationCases[].OpenDate | โ | Present in source; not read by this runner |
OpenRegistrationCases[].ReviewDate | โ | Present in source; not read by this runner |
OpenRegistrationCases[].PotentialChangeOfOwnership | โ | Present in source; not read by this runner |
OpenApplicationsAndApprovalsCases[].CaseName | โ | Present in source; not read by this runner |
OpenApplicationsAndApprovalsCases[].OpenDate | โ | Present in source; not read by this runner |
OpenApplicationsAndApprovalsCases[].ReviewDate | โ | Present in source; not read by this runner |
OpenApplicationsAndApprovalsCases[].PotentialChangeOfOwnership | โ | Present in source; not read by this runner |
ExtractDate | โ | Present in source; not read by this runner |
See specs/data-dictionary.yaml (uk-caa-registry entry) for full column semantics and cross-source schema notes.
Example Output โ
Read back the merged record for a given ICAO hex (combines this runner's data with Mictronics and any other sources that have written to the same key):
docker run --rm --network host redis:latest redis-cli EVAL "$(cat ./shared/lua/merge_aircraft.lua)" 0 401A48 | python3 -m json.tool --sort-keys --no-ensure-ascii{
"aircraft": {
"category": "Land",
"manufactured_date": "1910-01-01T00:00:00Z",
"manufacturer": "DEPERDUSSIN CIE",
"manufacturer_model": "DEPERDUSSIN CIE DEPERDUSSIN MONOPLANE",
"model": "DEPERDUSSIN MONOPLANE",
"powerplant": {
"count": 1,
"model": "ANZANI Y TYPE"
},
"seats": 1,
"serial_number": "43",
"type": "Airplane",
"type_designator": "ULAC"
},
"data_sources": [
"uk-caa-registry"
],
"icao_hex": "401A48",
"military": false,
"registrant": {
"city": "BIGGLESWADE",
"country": "GB",
"names": [
"RICHARD SHUTTLEWORTH TRUSTEES"
],
"postal_code": "SG18 9ER",
"street": [
"OLD WARDEN AERODROME",
"OLD WARDEN"
]
},
"registration": "G-AANH"
}docker run --rm --network host redis:latest redis-cli EVAL "$(cat ./shared/lua/merge_aircraft.lua)" 0 407F19 | python3 -m json.tool --sort-keys --no-ensure-ascii{
"aircraft": {
"category": "Land",
"description_code": "L2J",
"manufactured_date": "2023-01-01T00:00:00Z",
"manufacturer": "AIRBUS SAS",
"manufacturer_model": "AIRBUS A-350-1000",
"model": "AIRBUS A350-1041",
"powerplant": {
"count": 2,
"model": "ROLLS-ROYCE Trent XWB-97"
},
"seats": 336,
"serial_number": "605",
"type": "Airplane",
"type_designator": "A35K"
},
"data_sources": [
"mictronics",
"uk-caa-registry"
],
"icao_hex": "407F19",
"military": false,
"registrant": {
"city": "CRAWLEY",
"country": "GB",
"names": [
"VIRGIN ATLANTIC AIRWAYS LTD"
],
"postal_code": "RH10 9DF",
"street": [
"THE VHQ",
"FLEMING WAY"
]
},
"registration": "G-VBOB"
}Configuration โ
See Data Runners for the full list of environment variables every runner reads. This runner writes aircraft:registry:{icao_hex} with a fixed 14-day TTL (ENRICHMENT_TTL_SECONDS in shared/timing.py).
MQTT โ
Published once, at the end of a run, to SkyFollower/runner/uk-caa-registry/statistic/{name} (all retained):
| Topic suffix | Value | Format |
|---|---|---|
records_imported | e.g. 271 | Integer as string |
last_run_at | e.g. 2026-07-07T14:32:01.123456+00:00 | ISO 8601 UTC |
last_run_status | Success or Failure | String |
Home Assistant autodiscovery configs are also published (retained) to homeassistant/sensor/SkyFollower_runner_uk_caa_registry_{name}/config for each of the three stats above.