{
  "servers": [
    {
      "url": "https://api.es-go.de",
      "description": "Production"
    }
  ],
  "info": {
    "description": "Search free truck capacity on empty runs and post open transport requests on ESGO. ESGO is a broker: prices are non-binding estimates or the standing offers of carriers, and booking happens on es-go.de.",
    "contact": {
      "name": "ESGO",
      "url": "https://es-go.de/developers"
    },
    "title": "ESGO API",
    "version": "v1"
  },
  "paths": {
    "/v1/me": {
      "get": {
        "responses": {
          "401": {
            "description": "Missing, invalid, expired or revoked API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The API key lacks the scope, or the account has no active plan or is disabled.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit or daily quota reached. Retry after the number of seconds in Retry-After.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until the next attempt.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "The ESGO API is switched off.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Me"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/DEFAULT_ERROR"
          }
        },
        "tags": [
          "account"
        ],
        "operationId": "me_retrieve",
        "summary": "Retrieve the current API key",
        "description": "Use this call to check that your key works and how many calls are left today. It needs no scope.",
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/v1/matches/search": {
      "post": {
        "responses": {
          "422": {
            "$ref": "#/components/responses/UNPROCESSABLE_ENTITY"
          },
          "401": {
            "description": "Missing, invalid, expired or revoked API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The API key lacks the scope, or the account has no active plan or is disabled.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit or daily quota reached. Retry after the number of seconds in Retry-After.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until the next attempt.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "The ESGO API is switched off.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MatchSearchResult"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/DEFAULT_ERROR"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MatchSearchRequest"
              }
            }
          }
        },
        "tags": [
          "matches"
        ],
        "operationId": "matches_search",
        "summary": "Search matching capacity",
        "description": "Finds trips whose route, time and free capacity fit your shipment. Prices are non-binding estimates; a fixed price is the standing offer of the carrier. Counts against the daily quota \"matches_search\".",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-esgo-scope": "matches:read"
      }
    },
    "/v1/open-requests": {
      "post": {
        "responses": {
          "422": {
            "$ref": "#/components/responses/UNPROCESSABLE_ENTITY"
          },
          "401": {
            "description": "Missing, invalid, expired or revoked API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The API key lacks the scope, or the account has no active plan or is disabled.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit or daily quota reached. Retry after the number of seconds in Retry-After.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until the next attempt.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "The ESGO API is switched off.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OpenRequest"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/DEFAULT_ERROR"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/OpenRequestCreate"
              }
            }
          }
        },
        "tags": [
          "open_requests"
        ],
        "operationId": "open_requests_create",
        "summary": "Create an open transport request",
        "description": "Posts a transport request that carriers on ESGO see. ESGO matches it against existing trips right away and against every new trip later. Counts against the daily quota \"open_requests_create\". Not retried automatically: a repeated call creates a second request.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-esgo-scope": "open_requests:write"
      }
    },
    "/v1/open-requests/{request_id}/matches": {
      "get": {
        "responses": {
          "401": {
            "description": "Missing, invalid, expired or revoked API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The API key lacks the scope, or the account has no active plan or is disabled.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "No such resource, or it belongs to another account.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit or daily quota reached. Retry after the number of seconds in Retry-After.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until the next attempt.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "The ESGO API is switched off.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MatchList"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/DEFAULT_ERROR"
          }
        },
        "tags": [
          "open_requests"
        ],
        "operationId": "open_requests_list_matches",
        "summary": "List matches of an open request",
        "description": "Trips ESGO has matched to one of your open requests, best first. Reading them does not mark them as seen in the dashboard.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-esgo-scope": "open_requests:read"
      },
      "parameters": [
        {
          "in": "path",
          "name": "request_id",
          "description": "ID of one of your open requests, as returned by open_requests_create.",
          "required": true,
          "schema": {
            "type": "string",
            "minLength": 1
          }
        }
      ]
    }
  },
  "tags": [
    {
      "name": "account",
      "description": "The API key in use and its remaining daily quotas."
    },
    {
      "name": "matches",
      "description": "Search free truck capacity on trips that carriers offer on ESGO."
    },
    {
      "name": "open_requests",
      "description": "Post open transport requests and read the trips ESGO matches to them."
    }
  ],
  "openapi": "3.0.3",
  "components": {
    "schemas": {
      "ErrorBody": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "authentication_error",
              "permission_error",
              "invalid_request_error",
              "rate_limit_error",
              "api_error"
            ],
            "description": "Error category."
          },
          "code": {
            "type": "string",
            "description": "Machine-readable error code.",
            "example": "invalid_parameter"
          },
          "message": {
            "type": "string",
            "description": "Human-readable explanation."
          },
          "param": {
            "type": "string",
            "description": "Request field the error refers to, if any.",
            "example": "weight_kg",
            "nullable": true
          }
        },
        "required": [
          "code",
          "message",
          "type"
        ],
        "additionalProperties": false
      },
      "Error": {
        "type": "object",
        "properties": {
          "error": {
            "$ref": "#/components/schemas/ErrorBody"
          }
        },
        "required": [
          "error"
        ],
        "additionalProperties": false
      },
      "ApiKeyInfo": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string",
            "description": "Label given by ESGO.",
            "example": "TMS production"
          },
          "prefix": {
            "type": "string",
            "description": "Visible start of the key.",
            "example": "esgo_live_Ab3dE9"
          },
          "scopes": {
            "type": "array",
            "description": "Granted scopes.",
            "example": [
              "matches:read"
            ],
            "items": {
              "type": "string"
            }
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "expires_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          }
        },
        "required": [
          "created_at",
          "id",
          "name",
          "prefix",
          "scopes"
        ],
        "additionalProperties": false
      },
      "Quota": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "Operation the quota applies to.",
            "example": "matches_search"
          },
          "limit": {
            "type": "integer",
            "description": "Calls per rolling 24 hours.",
            "example": 200
          },
          "remaining": {
            "type": "integer",
            "description": "Calls left in the current window.",
            "example": 198
          }
        },
        "required": [
          "limit",
          "name",
          "remaining"
        ],
        "additionalProperties": false
      },
      "Me": {
        "type": "object",
        "properties": {
          "object": {
            "type": "string",
            "enum": [
              "me"
            ]
          },
          "key": {
            "$ref": "#/components/schemas/ApiKeyInfo"
          },
          "account_role": {
            "type": "string",
            "description": "Role of the ESGO account the key belongs to.",
            "example": "buyer"
          },
          "quotas": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Quota"
            }
          }
        },
        "required": [
          "account_role",
          "key",
          "object",
          "quotas"
        ],
        "additionalProperties": false
      },
      "MatchSearchRequest": {
        "type": "object",
        "properties": {
          "origin": {
            "type": "string",
            "minLength": 2,
            "maxLength": 255,
            "description": "Origin, ideally postcode and city.",
            "example": "47057 Duisburg"
          },
          "destination": {
            "type": "string",
            "minLength": 2,
            "maxLength": 255,
            "description": "Destination, ideally postcode and city.",
            "example": "80331 M\u00fcnchen"
          },
          "weight_kg": {
            "type": "number",
            "minimum": 0.0,
            "maximum": 40000.0,
            "description": "Cargo weight in kilograms.",
            "example": 12000
          },
          "loading_meters": {
            "type": "number",
            "default": null,
            "minimum": 0.0,
            "maximum": 13.6,
            "description": "Loading meters needed (max 13.6).",
            "example": 4.8,
            "nullable": true
          },
          "loading_requirement": {
            "type": "string",
            "default": "any",
            "enum": [
              "any",
              "heck",
              "seite",
              "oben"
            ],
            "description": "How the cargo has to be loaded. \"any\" never filters; \"seite\" (side) and \"oben\" (top) exclude box bodies; \"heck\" means rear loading.",
            "example": "any"
          },
          "service_ids": {
            "type": "array",
            "default": [],
            "maxItems": 20,
            "description": "Required additional services (ESGO service IDs).",
            "example": [],
            "items": {
              "type": "integer",
              "minimum": 1
            }
          }
        },
        "required": [
          "destination",
          "origin",
          "weight_kg"
        ],
        "additionalProperties": false
      },
      "DepartureWindow": {
        "type": "object",
        "properties": {
          "start": {
            "type": "string",
            "format": "date-time",
            "description": "Earliest departure, local time Europe/Berlin."
          },
          "end": {
            "type": "string",
            "format": "date-time",
            "description": "Latest departure, local time Europe/Berlin."
          }
        },
        "required": [
          "end",
          "start"
        ],
        "additionalProperties": false
      },
      "Match": {
        "type": "object",
        "properties": {
          "object": {
            "type": "string",
            "enum": [
              "match"
            ]
          },
          "route_id": {
            "type": "string",
            "description": "ID of the offered trip."
          },
          "origin_area": {
            "type": "string",
            "description": "Origin of the trip, city level.",
            "example": "47057 Duisburg"
          },
          "destination_area": {
            "type": "string",
            "description": "Destination of the trip, city level.",
            "example": "80331 M\u00fcnchen"
          },
          "departure_window": {
            "$ref": "#/components/schemas/DepartureWindow"
          },
          "match_score": {
            "type": "number",
            "description": "How well the trip fits, 0 to 100.",
            "example": 87.5
          },
          "detour_km": {
            "type": "number",
            "description": "Extra kilometers for the carrier.",
            "example": 14.2,
            "nullable": true
          },
          "free_capacity_ldm": {
            "type": "number",
            "description": "Free loading meters on this trip before your load.",
            "example": 6.2
          },
          "free_capacity_kg": {
            "type": "number",
            "description": "Free payload in kilograms before your load.",
            "example": 9000
          },
          "price_estimate_eur": {
            "type": "number",
            "description": "Non-binding price estimate in EUR. Not an offer; null where no estimate exists.",
            "example": 640,
            "nullable": true
          },
          "instant_bookable": {
            "type": "boolean",
            "description": "The carrier offers a fixed price for this trip."
          },
          "instant_price_eur": {
            "type": "number",
            "description": "The carrier's standing fixed-price offer in EUR, if any.",
            "example": 690,
            "nullable": true
          },
          "co2_saved_kg_estimate": {
            "type": "number",
            "description": "Rough estimate of CO2 saved in kilograms; null where no estimate exists.",
            "example": 1420.3,
            "nullable": true
          },
          "booking_url": {
            "type": "string",
            "description": "Opens the booking flow on es-go.de. Booking happens there, not through the API."
          }
        },
        "required": [
          "booking_url",
          "departure_window",
          "destination_area",
          "free_capacity_kg",
          "free_capacity_ldm",
          "instant_bookable",
          "match_score",
          "object",
          "origin_area",
          "route_id"
        ],
        "additionalProperties": false
      },
      "MatchSearchResult": {
        "type": "object",
        "properties": {
          "object": {
            "type": "string",
            "enum": [
              "match_search"
            ]
          },
          "distance_km": {
            "type": "number",
            "description": "Road distance of your route.",
            "example": 612.4
          },
          "match_count": {
            "type": "integer",
            "description": "Number of matching trips found (data may be shorter).",
            "example": 3
          },
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Match"
            }
          }
        },
        "required": [
          "data",
          "distance_km",
          "match_count",
          "object"
        ],
        "additionalProperties": false
      },
      "TimeWindow": {
        "type": "object",
        "properties": {
          "start": {
            "type": "string",
            "format": "date-time",
            "description": "Start, ISO 8601. Without offset the time is local time Europe/Berlin.",
            "example": "2026-10-20T08:00:00"
          },
          "end": {
            "type": "string",
            "format": "date-time",
            "description": "End, ISO 8601. Must be after start and in the future.",
            "example": "2026-10-20T16:00:00"
          }
        },
        "required": [
          "end",
          "start"
        ],
        "additionalProperties": false
      },
      "OpenRequestCreate": {
        "type": "object",
        "properties": {
          "origin": {
            "type": "string",
            "minLength": 2,
            "maxLength": 255,
            "description": "Origin, ideally postcode and city.",
            "example": "47057 Duisburg"
          },
          "destination": {
            "type": "string",
            "minLength": 2,
            "maxLength": 255,
            "description": "Destination, ideally postcode and city.",
            "example": "80331 M\u00fcnchen"
          },
          "weight_kg": {
            "type": "number",
            "minimum": 0.0,
            "maximum": 40000.0,
            "description": "Cargo weight in kilograms.",
            "example": 12000
          },
          "loading_meters": {
            "type": "number",
            "minimum": 0.0,
            "maximum": 13.6,
            "description": "Loading meters needed (max 13.6).",
            "example": 4.8
          },
          "cargo_type": {
            "type": "string",
            "minLength": 1,
            "maxLength": 100,
            "description": "Kind of cargo.",
            "example": "Paletten"
          },
          "cargo_description": {
            "type": "string",
            "default": "",
            "maxLength": 2000,
            "description": "Free text for the carrier.",
            "example": "12 EUR pallets, stackable"
          },
          "loading_requirement": {
            "type": "string",
            "default": "any",
            "enum": [
              "any",
              "heck",
              "seite",
              "oben"
            ],
            "description": "How the cargo has to be loaded. \"any\" never filters; \"seite\" (side) and \"oben\" (top) exclude box bodies; \"heck\" means rear loading.",
            "example": "any"
          },
          "target_price_eur": {
            "type": "number",
            "default": null,
            "minimum": 0.0,
            "maximum": 1000000.0,
            "description": "Optional target price in EUR shown to carriers as orientation.",
            "example": 650,
            "nullable": true
          },
          "time_windows": {
            "type": "array",
            "minItems": 1,
            "maxItems": 10,
            "description": "Pickup time windows; at least one.",
            "items": {
              "$ref": "#/components/schemas/TimeWindow"
            }
          },
          "service_ids": {
            "type": "array",
            "default": [],
            "maxItems": 20,
            "description": "Required additional services (ESGO service IDs).",
            "example": [],
            "items": {
              "type": "integer",
              "minimum": 1
            }
          }
        },
        "required": [
          "cargo_type",
          "destination",
          "loading_meters",
          "origin",
          "time_windows",
          "weight_kg"
        ],
        "additionalProperties": false
      },
      "OpenRequest": {
        "type": "object",
        "properties": {
          "object": {
            "type": "string",
            "enum": [
              "open_request"
            ]
          },
          "id": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "description": "Status of the request.",
            "example": "active"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "expires_at": {
            "type": "string",
            "format": "date-time",
            "description": "End of the latest time window."
          },
          "matches_found": {
            "type": "integer",
            "description": "Matching trips found right away.",
            "example": 2
          },
          "dashboard_url": {
            "type": "string",
            "description": "The request in the ESGO dashboard."
          }
        },
        "required": [
          "created_at",
          "dashboard_url",
          "expires_at",
          "id",
          "matches_found",
          "object",
          "status"
        ],
        "additionalProperties": false
      },
      "MatchList": {
        "type": "object",
        "properties": {
          "object": {
            "type": "string",
            "enum": [
              "list"
            ]
          },
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Match"
            }
          }
        },
        "required": [
          "data",
          "object"
        ],
        "additionalProperties": false
      }
    },
    "responses": {
      "DEFAULT_ERROR": {
        "description": "Default error response",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "UNPROCESSABLE_ENTITY": {
        "description": "Unprocessable Entity",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      }
    },
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "API key issued by ESGO, sent as \"Authorization: Bearer esgo_live_...\"."
      }
    }
  }
}