From e0b1da21493c9dc24382eb513b0b928704e53a97 Mon Sep 17 00:00:00 2001 From: zemion Date: Wed, 20 May 2026 16:47:05 +0200 Subject: [PATCH] initial draft commit --- .gitignore | 3 + LICENSE => LICENSE.md | 0 README.md | 66 ++++++++ providers.xml | 97 ++++++++++++ providers/calco2lato/calco2lato.xml | 77 +++++++++ providers/google_tim/google_tim.xml | 50 ++++++ scheme.json | 232 ++++++++++++++++++++++++++++ 7 files changed, 525 insertions(+) rename LICENSE => LICENSE.md (100%) create mode 100644 providers.xml create mode 100644 providers/calco2lato/calco2lato.xml create mode 100644 providers/google_tim/google_tim.xml create mode 100644 scheme.json diff --git a/.gitignore b/.gitignore index 8c2b884..bc08a77 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,6 @@ # Built Visual Studio Code Extensions *.vsix +iso*.csv +domains_operations.txt +merge_providers.py \ No newline at end of file diff --git a/LICENSE b/LICENSE.md similarity index 100% rename from LICENSE rename to LICENSE.md diff --git a/README.md b/README.md index b0ba64e..a2708a8 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,68 @@ # emission-api-lib +`emission-api-lib` is the authoritative draft specification for provider-neutral emission calculation connectors. + +The project defines a shared domain model, provider configuration format, provider capability vocabulary and validation artifacts for integrating multiple emission calculation providers through a stable connector layer. + +## Status + +Draft specification. + +The specification is not stable yet. Breaking changes are expected until the first stable version is released. + +## Purpose + +Direct integrations between specialist applications and individual emission calculation APIs create long-term dependencies on provider-specific request formats, response formats and feature assumptions. + +`emission-api-lib` defines a provider-neutral integration boundary. Applications should be able to express an emission calculation request in a stable domain format, while provider-specific mappings, capabilities and limitations are handled by connector implementations. + +## Repository role + +This repository is authoritative. + +Language-specific repositories implement this specification, but do not define it. + +- `emission-api-lib-java` is the Java reference implementation. +- `emission-api-lib-python` is the Python implementation. +- `emission-api-lib-php` is the PHP implementation. + +All implementation repositories should link back to this repository. + +## Provider scope + +The specification is designed for multiple providers from the beginning. + +A provider is described through XML configuration and machine-readable capability metadata. Implementations may use this information to validate requests, select providers, explain unsupported features and normalize responses. + +## Specification artifacts + +This repository may contain: + +- `schema.json` for the shared domain model +- XSD files for provider XML validation +- provider XML examples +- normalized request and response examples +- provider capability definitions +- compatibility notes for language-specific implementations + +## Initial domain + +The first target domain is flight emission calculation. + +The specification is expected to support provider capability discovery instead of assuming that every provider supports the same request structure, response structure or calculation options. + +## Design principles + +- Provider neutrality +- Multiple providers from the beginning +- Stable domain-level request and response concepts +- Explicit provider capabilities +- Configuration over hardcoded provider logic +- Replayability and auditability where supported +- Language implementations that follow the shared specification + +## License + +The general specification repository is licensed under the GNU Affero General Public License, Version 3 or later. + +Individual implementation repositories may use a different license if this improves integration and adoption. Each implementation repository must state its license clearly. \ No newline at end of file diff --git a/providers.xml b/providers.xml new file mode 100644 index 0000000..f4d2aeb --- /dev/null +++ b/providers.xml @@ -0,0 +1,97 @@ + + + + calco2la.to + https://api.calco2la.to + +
Authorization
+ Bearer ${API_KEY} +
+ + + + + { + "legs": [ + #for leg in request.legs + { + "origin": "${leg.origin_iata}", + "destination": "${leg.destination_iata}", + "departure_time": "${leg.departure_time}" + }#sep, + #end + ], + "cabin_class": "${request.cabin_class}", + "passengers": ${request.passengers}, + "include_non_co2": ${request.include_non_co2} + } + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + Google Travel Impact Model + https://travelimpactmodel.googleapis.com/v1 + +
X-Goog-Api-Key
+ ${API_KEY} +
+ + + + + { + "flightSegments": [ + #for leg in request.legs + { + "departureAirport": { "code": "${leg.origin_iata}" }, + "arrivalAirport": { "code": "${leg.destination_iata}" } + }#sep, + #end + ], + "cabinClass": "${request.cabin_class}", + "passengerCount": ${request.passengers} + } + + + + + + + + + + + +
+
\ No newline at end of file diff --git a/providers/calco2lato/calco2lato.xml b/providers/calco2lato/calco2lato.xml new file mode 100644 index 0000000..8bef19e --- /dev/null +++ b/providers/calco2lato/calco2lato.xml @@ -0,0 +1,77 @@ + + + + calco2la.to + https://api.calco2la.to + + +
Authorization
+ Bearer ${API_KEY} +
+ + + + + + + + + + { + "legs": [ + #for leg in request.legs + { + "origin": "${leg.origin_iata}", + "destination": "${leg.destination_iata}", + "departure_time": "${leg.departure_time}" + }#sep, + #end + ], + "cabin_class": "${request.cabin_class}", + "passengers": ${request.passengers}, + "include_non_co2": ${request.include_non_co2} + } + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
diff --git a/providers/google_tim/google_tim.xml b/providers/google_tim/google_tim.xml new file mode 100644 index 0000000..af79387 --- /dev/null +++ b/providers/google_tim/google_tim.xml @@ -0,0 +1,50 @@ + + + + + Google Travel Impact Model + https://travelimpactmodel.googleapis.com/v1 + + +
X-Goog-Api-Key
+ ${API_KEY} +
+ + + + + + + + { + "flightSegments": [ + #for leg in request.legs + { + "departureAirport": { "code": "${leg.origin_iata}" }, + "arrivalAirport": { "code": "${leg.destination_iata}" } + }#sep, + #end + ], + "cabinClass": "${request.cabin_class}", + "passengerCount": ${request.passengers} + } + + + + + + + + + + + + + +
+
diff --git a/scheme.json b/scheme.json new file mode 100644 index 0000000..3d8e342 --- /dev/null +++ b/scheme.json @@ -0,0 +1,232 @@ +{ + "FlightLeg": { + "origin_iata": "string", + "destination_iata": "string", + "departure_time": "optional ISO-8601 datetime", + "marketing_carrier": "optional string", + "operating_carrier": "optional string", + "flight_number": "optional string" + }, + "FlightRequest": { + "legs": ["FlightLeg"], + "cabin_class": "economy | premium_economy | business | first | unknown", + "passengers": "integer >= 1", + "roundtrip": "boolean", + "include_non_co2": "boolean", + "currency": "optional ISO 4217 code" + }, + "EmissionEstimate": { + "co2_kg": "number or null", + "co2e_kg": "number or null", + "non_co2_multiplier": "number or null", + "breakdown": { + "ch4_kg": "number or null", + "n2o_kg": "number or null" + }, + "methodology": { + "method_name": "string or null", + "method_version": "string or null", + "dataset_version": "string or null", + "vendor": "string or null", + "standard": "string or null", + "documentation_url": "string or null" + }, + "vendor_raw": "opaque vendor-specific JSON/XML" + }, + "AirportSearchRequest": { + "query": "string", + "limit": "optional integer", + "country_filter": "optional ISO 3166 code", + "languages": ["optional ISO 639 code"] + }, + "AirportInfo": { + "iata_code": "string", + "icao_code": "string", + "name": "string", + "localized_name": ["LocalizedString"], + "country": "ISO 3166 code", + "continent": "string", + "latitude": "double", + "longitude": "double" + }, + "LocalizedString": { + "lang": "ISO 639 code", + "name": "string" + } +} + +{ + "FlightCalculationRequest": { + "api_key": "optional string", + "provider": "optional string", + "operation": "optional string", + "departure_date": "optional ISO-8601 date", + "rfi": "optional number", + "price_per_ton": "optional number", + "currency": "optional ISO 4217 code", + "roundtrip": "optional boolean", + "passengers": "optional integer >= 1", + "cabin_class": "economy | premium_economy | business | first | unknown", + "calculation_method": "optional string", + "reference": "optional string", + "legs": ["FlightLeg"], + "iata_path": ["string"], + "currencies": ["optional ISO 4217 code"], + "vendor_options": "object" + }, + "FlightLeg": { + "id": "optional string", + "index": "optional integer", + "origin_iata": "optional string", + "destination_iata": "optional string", + "origin": "optional LocationRef", + "destination": "optional LocationRef", + "departure_date": "optional ISO-8601 date", + "departure_time": "optional ISO-8601 datetime", + "flight_number": "optional string", + "marketing_carrier": "optional string", + "operating_carrier": "optional string", + "airline": "optional string", + "aircraft_type": "optional string", + "passenger_count": "optional integer", + "flight_count": "optional integer", + "travel_class": "optional string", + "charter": "optional boolean", + "via": ["optional string"], + "distance_km": "optional number", + "vendor_options": "object" + }, + "EmissionCalculationResult": { + "provider": "string", + "domain": "string", + "operation": "string", + "status": "string", + "total": "EmissionAmount", + "per_passenger": "EmissionAmount", + "distance": "DistanceAmount", + "per_passenger_distance": "DistanceAmount", + "fuel": "FuelAmount", + "offset": "MoneyAmount", + "per_passenger_price": "MoneyAmount", + "quote": "QuoteInfo", + "methodology": "MethodologyMeta", + "passenger_count": "integer or null", + "travel_class": "string or null", + "description": "string or null", + "segments": ["SegmentEmissionResult"], + "prices": ["MoneyAmount"], + "errors": ["ProviderError"], + "metadata": "opaque object or array", + "input_echo": "opaque object", + "vendor_raw": "opaque object" + }, + "SegmentEmissionResult": { + "id": "string or null", + "index": "integer or null", + "type": "string or null", + "status": "string or null", + "origin": "LocationRef", + "destination": "LocationRef", + "flight_number": "string or null", + "flight_date": "ISO-8601 date or null", + "airline": "string or null", + "aircraft_type": "string or null", + "passenger_count": "integer or null", + "flight_count": "integer or null", + "travel_class": "string or null", + "charter": "boolean or null", + "emissions": "EmissionAmount", + "class_emissions": "CabinClassEmissionSet", + "distance": "DistanceAmount", + "fuel": "FuelAmount", + "offset": "MoneyAmount", + "cruise_altitude": "number or null", + "distance_in_critical_altitudes": "number or null", + "source": "string or null", + "errors": ["ProviderError"], + "vendor_raw": "opaque object" + }, + "EmissionAmount": { + "co2_kg": "number or null", + "co2e_kg": "number or null", + "co2e_tonnes": "number or null", + "wtw_kg": "number or null", + "ttw_kg": "number or null", + "wtt_kg": "number or null", + "non_co2_multiplier": "number or null", + "unit": "kg | tonnes | grams | null", + "per": "request | passenger | segment | null" + }, + "CabinClassEmissionSet": { + "economy_kg": "number or null", + "premium_economy_kg": "number or null", + "business_kg": "number or null", + "first_kg": "number or null" + }, + "DistanceAmount": { + "value": "number or null", + "unit": "km | miles | null", + "miles": "number or null" + }, + "FuelAmount": { + "liters": "number or null", + "kg": "number or null" + }, + "MoneyAmount": { + "amount": "number or null", + "amount_minor": "integer or null", + "currency": "ISO 4217 code or null", + "url": "string or null", + "locale": "string or null" + }, + "QuoteInfo": { + "id": "string or null", + "expires_at": "ISO-8601 datetime or null" + }, + "MethodologyMeta": { + "method_name": "string or null", + "method_version": "string or null", + "dataset_version": "string or null", + "vendor": "string or null", + "standard": "string or null", + "documentation_url": "string or null", + "non_co2_treatment": "none | included | partial | unknown" + }, + "ProviderError": { + "code": "string or null", + "message": "string", + "field": "string or null", + "vendor_raw": "opaque object" + }, + "LocationRef": { + "iata": "string or null", + "icao": "string or null", + "name": "string or null", + "city": "string or null", + "country": "ISO 3166 code or null", + "continent": "string or null", + "lat": "number or null", + "lon": "number or null", + "coord": "string or null" + }, + "AirportSearchRequest": { + "query": "string", + "limit": "optional integer", + "country_filter": "optional ISO 3166 code", + "languages": ["optional ISO 639 code"] + }, + "AirportInfo": { + "iata_code": "string", + "icao_code": "string", + "name": "string", + "localized_name": ["LocalizedString"], + "country": "ISO 3166 code", + "continent": "string", + "latitude": "double", + "longitude": "double" + }, + "LocalizedString": { + "lang": "ISO 639 code", + "name": "string" + } +} \ No newline at end of file