{
  "name": "Aerovolt EBC API",
  "base_url": "https://app.aerovolt.co.uk",
  "authentication": {
    "description": "External endpoints require a client key and client secret. Client keys are stored in SQL and tied to the creating user. Client secrets are shown once and then stored as a hash.",
    "methods": [
      {
        "type": "basic",
        "header": "Authorization",
        "format": "Basic base64(CLIENT_KEY:CLIENT_SECRET)"
      },
      {
        "type": "headers",
        "headers": {
          "X-Carbon-Key": "CLIENT_KEY",
          "X-Carbon-Secret": "CLIENT_SECRET"
        }
      }
    ]
  },
  "endpoints": {
    "create_certificate": {
      "method": "POST",
      "path": "/api/external/certificates/create",
      "content_type": "application/json",
      "idempotency": [
        "external_reference",
        "idempotency_key",
        "certificate_number"
      ],
      "required_record_values": {
        "public_status": "Use public for Public Registry records. Use private to hide from the Public Registry and partial public search; private records can only be opened by full certificate number.",
        "co2_used_t": "Total CO2 used on the flight, in tonnes. Optional when enough aircraft and route data is supplied for the API to calculate it.",
        "ebc_allocated_t": "Amount allocated or purchased as EBC, in tonnes. Optional for carbon-report-only records.",
        "value_purchased": "Monetary value of the EBC purchase in the submitted currency. Optional for carbon-report-only records.",
        "currency": "3-letter ISO currency for value_purchased. Defaults to USD.",
        "supplier_commission_percent": "Supplier commission percentage to record against the EBC value.",
        "supplier_commission_amount": "Supplier commission amount when supplied as a fixed value instead of a percent.",
        "supplier_commission_currency": "3-letter ISO currency for supplier_commission_amount. Defaults to the submitted EBC value currency.",
        "record_reference": "Supplier, booking, invoice, or external record reference to store against the certificate.",
        "payment_status": "Payment state for the certificate record. Defaults to unpaid.",
        "upsert": "When true, repeated submissions update the existing record instead of creating a duplicate."
      },
      "co2_calculation": {
        "description": "If co2_used_t is omitted, the API calculates CO2 from aircraft and flight data.",
        "aircraft_resolution": [
          "exact manufacturer + model + optional variant from the aircraft glossary"
        ],
        "aircraft_aliases": {
          "make": "manufacturer",
          "aircraft_make": "manufacturer",
          "aircraft_manufacturer": "manufacturer",
          "manufacturer_name": "manufacturer",
          "make_name": "manufacturer",
          "type": "model",
          "aircraft_type": "model",
          "aircraft_model": "model",
          "model_name": "model",
          "aircraft_variant": "variant",
          "variant_name": "variant"
        },
        "certificate_link": "Matched aircraft are stored on certificates.aircraft_id, linked to app.aircraft_models.id, and used for PDF aircraft details and CO2 calculations.",
        "per_leg_aircraft": "Set aircraft at the top level for a default aircraft. Add aircraft to any flights, legs, or sectors item to override the default aircraft for that leg.",
        "calculation": "Route distance is calculated from airport coordinates, then CO2 is estimated using aircraft fuel burn or electric CO2-per-hour data.",
        "response_field": "totals.co2_source is payload when CO2 was supplied, or aircraft_database when calculated.",
        "carbon_report_only": "If no EBC allocation and no positive EBC value is supplied, the API creates the server record with CO2/flight details, ebc_purchased_t: 0, total_price: 0, and carbon_report_only: true.",
        "strict_matching": "Use exact manufacturer/model/variant values from the API Documentation aircraft glossary. Values are sourced from the app.aircraft_models table. Uppercase/lowercase variants are accepted, but misspelled aircraft names are rejected with suggested database matches.",
        "recommended_payload": {
          "aircraft": {
            "manufacturer": "Gulfstream Aerospace",
            "model": "G650",
            "variant": "G650"
          }
        },
        "distance_fields": {
          "total": [
            "totals.point_to_point_distance_nm",
            "totals.distance_nm"
          ],
          "per_leg": [
            "legs[].point_to_point_distance_nm",
            "legs[].distance_nm"
          ],
          "description": "Point-to-point distance is returned in nautical miles and is calculated from airport coordinates even when co2_used_t is supplied by the API user."
        }
      },
      "payment_statuses": [
        "unpaid",
        "pending",
        "paid",
        "cancelled",
        "void",
        "refunded"
      ],
      "supplier_commission_aliases": {
        "percent": [
          "supplier_commission_percent",
          "supplier_commission_percentage",
          "commission_percent",
          "commission_percentage"
        ],
        "amount": [
          "supplier_commission",
          "supplier_commission_amount",
          "supplier_commission_value",
          "commission_amount"
        ],
        "currency": [
          "supplier_commission_currency",
          "commission_currency",
          "supplier_commission_value_currency"
        ]
      },
      "currency_aliases": [
        "currency",
        "value_currency",
        "total_price_currency",
        "value_purchased_currency",
        "ebc_value_currency",
        "certificate_value_currency"
      ],
      "airport_codes": {
        "accepted": [
          "ICAO",
          "IATA"
        ],
        "description": "Flight legs can use ICAO or IATA airport codes. IATA codes are resolved to the stored ICAO airport record before mission legs are saved.",
        "departure_aliases": [
          "departure_icao",
          "departure_iata",
          "from_icao",
          "from_iata",
          "from",
          "origin_icao",
          "origin_iata",
          "origin",
          "departure.icao",
          "departure.iata",
          "departure.code"
        ],
        "arrival_aliases": [
          "arrival_icao",
          "arrival_iata",
          "to_icao",
          "to_iata",
          "to",
          "destination_icao",
          "destination_iata",
          "destination",
          "arrival.icao",
          "arrival.iata",
          "arrival.code"
        ]
      },
      "aa_flights": {
        "description": "A-A flights are supported when departure and arrival are the same airport. A-A flights require flight time because route distance cannot provide duration.",
        "accepted_duration_fields": [
          "duration_hours",
          "flight_time_hours",
          "block_time_hours",
          "duration_minutes",
          "flight_time_minutes",
          "block_time_minutes"
        ],
        "ab_flights": "A-B flights can calculate flight time from aircraft cruise speed and airport distance when arrival time is omitted."
      }
    },
    "quote": {
      "method": "POST",
      "path": "/api/external/quote",
      "content_type": "application/json",
      "description": "Returns a quote without creating mission or certificate records. Calculates CO2 when omitted, uses the company EBC cost per tonne, and applies the API user's supplied commission rate or amount.",
      "example_request": {
        "external_reference": "QUOTE-10428",
        "aircraft": {
          "manufacturer": "Gulfstream Aerospace",
          "model": "G650"
        },
        "flights": [
          {
            "departure": {
              "iata": "LHR"
            },
            "arrival": {
              "iata": "NCE"
            },
            "departure_time": "2026-06-03 08:00:00"
          }
        ],
        "ebc_allocated_t": 1.0,
        "supplier_commission_percent": 10.0
      }
    },
    "update_certificate": {
      "methods": [
        "PUT",
        "PATCH"
      ],
      "path": "/api/external/certificates/{certificate_number}",
      "content_type": "application/json",
      "description": "Updates an existing certificate record. Supports customer fields, public/status fields, CO2/EBC amounts, value_purchased, currency, and linked API mission totals when flight legs are supplied.",
      "example_request": {
        "customer_reference": "BOOKING-10428-UPDATED",
        "co2_used_t": 12.8,
        "ebc_allocated_t": 10.5,
        "value_purchased": 2520.0,
        "currency": "GBP",
        "public_status": "public"
      }
    },
    "delete_certificate": {
      "method": "DELETE",
      "path": "/api/external/certificates/{certificate_number}",
      "description": "Deletes the certificate for the authenticated API client company. The linked API-created mission is also deleted when it is not linked to any other certificate.",
      "example_response": {
        "ok": true,
        "deleted": true,
        "certificate": {
          "deleted": true,
          "certificate_id": 123,
          "certificate_number": "AV-EBC-20260603-1A2B3C4D",
          "deleted_mission_ids": [
            456
          ]
        }
      }
    },
    "calculate": {
      "method": "POST",
      "path": "/api/external/calculate",
      "content_type": "application/json",
      "description": "Returns the estimate without creating mission or certificate records."
    },
    "lookup_certificate": {
      "method": "GET",
      "path": "/api/external/certificates/{certificate_number}"
    },
    "search_certificates": {
      "method": "GET",
      "path": "/api/external/certificates/search?q={query}"
    },
    "public_certificate_page": {
      "method": "GET",
      "path": "/certificates/{certificate_number}",
      "description": "Browser-ready certificate page. Public records appear in the registry. Private records only resolve when the full certificate number is entered and show aircraft registration as PRIVATE."
    },
    "pdf_certificate": {
      "method": "GET",
      "path": "/certificates/{certificate_number}.pdf",
      "description": "Browser-ready PDF certificate. Private records only resolve by full certificate number and show aircraft registration as PRIVATE."
    }
  },
  "private_record_mode": {
    "payload": {
      "public_status": "private"
    },
    "rules": [
      "Excluded from Public Registry list",
      "Excluded from partial public search suggestions",
      "Can only be opened by entering the full certificate number",
      "Aircraft registration displays as PRIVATE on the certificate page and PDF"
    ]
  },
  "sandbox": {
    "location": "App settings > API Credentials > API Sandbox",
    "description": "Create or reset credentials, paste the one-time secret into the sandbox, choose Quote, Calculate CO2, or Create Certificate, and run a live JSON payload.",
    "endpoints": [
      "/api/external/quote",
      "/api/external/calculate",
      "/api/external/certificates/create"
    ]
  },
  "database_mapping": {
    "co2_used_t": [
      "certificates.total_co2_used_t",
      "missions.total_co2_t"
    ],
    "ebc_allocated_t": [
      "certificates.ebc_allocated_t",
      "certificates.total_co2_t",
      "missions.offset_co2_t"
    ],
    "value_purchased": [
      "certificates.total_price converted to USD"
    ],
    "submitted_currency_audit": [
      "certificates.submitted_total_price",
      "certificates.submitted_currency",
      "certificates.fx_rate_to_usd",
      "certificates.fx_rate_source",
      "certificates.fx_converted_at"
    ],
    "supplier_commission": [
      "certificates.supplier_commission_percent",
      "certificates.supplier_commission_amount",
      "certificates.supplier_commission_currency",
      "certificates.submitted_supplier_commission_amount",
      "certificates.submitted_supplier_commission_currency"
    ],
    "record_reference": [
      "certificates.customer_reference"
    ],
    "payment_status": [
      "certificates.invoice_status"
    ],
    "credentials": {
      "client_key": "api_clients.client_key",
      "client_secret": "api_clients.client_secret_hash",
      "user_owner": "api_clients.created_by_user_id"
    }
  },
  "duplicate_prevention": {
    "create_endpoint": "/api/external/certificates/create",
    "matching_fields": [
      "external_reference",
      "idempotency_key",
      "certificate_number",
      "record_reference",
      "record_id",
      "reference",
      "booking_reference",
      "customer_reference"
    ],
    "default_repeat_behavior": "Returns 200 OK with already_exists: true and does not create another record.",
    "upsert_flags": [
      "upsert",
      "update_existing"
    ],
    "upsert_behavior": "When an upsert flag is true, the matching certificate is updated instead of duplicated.",
    "example_upsert_request": {
      "external_reference": "BOOKING-10428",
      "aircraft": {
        "manufacturer": "Gulfstream Aerospace",
        "model": "G650",
        "variant": "G650"
      },
      "co2_used_t": 12.8,
      "ebc_allocated_t": 10.5,
      "value_purchased": 2520.0,
      "currency": "GBP",
      "upsert": true
    }
  },
  "example_request": {
    "external_reference": "BOOKING-10428",
    "record_reference": "SUPPLIER-INV-7781",
    "customer_reference": "BOOKING-10428",
    "mission_number": "API-10428",
    "reference_number": "OPS-10428",
    "public_status": "public",
    "co2_used_t": 12.42,
    "ebc_allocated_t": 10.0,
    "value_purchased": 2400.0,
    "currency": "GBP",
    "supplier_commission_percent": 12.5,
    "payment_status": "unpaid",
    "upsert": true,
    "aircraft": {
      "manufacturer": "Gulfstream Aerospace",
      "model": "G650",
      "variant": "G650"
    },
    "flights": [
      {
        "flight_number": "AV001",
        "departure": {
          "iata": "LHR"
        },
        "arrival": {
          "iata": "NCE"
        },
        "departure_time": "2026-06-03 08:00:00",
        "arrival_time": "2026-06-03 10:05:00"
      },
      {
        "flight_number": "AV002",
        "departure": {
          "iata": "NCE"
        },
        "arrival": {
          "iata": "LCY"
        },
        "departure_time": "2026-06-04 09:00:00",
        "arrival_time": "2026-06-04 10:45:00",
        "aircraft": {
          "manufacturer": "Cessna",
          "model": "Citation CJ4"
        }
      }
    ]
  },
  "example_response_totals": {
    "point_to_point_distance_nm": 558.6,
    "distance_nm": 558.6,
    "total_price": 3048.0,
    "total_price_currency": "USD",
    "submitted_total_price": 2400.0,
    "submitted_currency": "GBP",
    "fx_rate_to_usd": 1.27,
    "fx_rate_source": "frankfurter",
    "co2_source": "aircraft_database",
    "carbon_report_only": false,
    "ebc_value_status": "submitted_or_calculated",
    "supplier_commission_percent": 12.5,
    "supplier_commission_amount": 381.0,
    "supplier_commission_currency": "USD",
    "submitted_supplier_commission_amount": 381.0,
    "submitted_supplier_commission_currency": "USD"
  },
  "certificate_urls": {
    "certificate_url": "https://app.aerovolt.co.uk/certificates/{certificate_number}",
    "pdf_url": "https://app.aerovolt.co.uk/certificates/{certificate_number}.pdf",
    "api_url": "https://app.aerovolt.co.uk/api/external/certificates/{certificate_number}"
  }
}
