{
  "openapi": "3.1.0",
  "info": {
    "title": "Vessel Schedules API",
    "version": "1.0.0",
    "description": "Port-to-port sailing schedules: every carrier sailing between two ports for up to 8 weeks ahead,\nwith vessel, voyage, terminals, transshipments and cutoffs.\n\n**Freshness.** Schedules for a port pair are refreshed at most every 12 hours. `metadata.updated_at`\nsays when the data was taken, `metadata.cache_expires` until when it is considered fresh. If the\nschedule source is temporarily unavailable, the last known schedule is returned; such an answer\nhas `cache_expires` in the past.\n\n**Times.** All sailing times and cutoffs are port-local ISO 8601 with the port's UTC offset\n(`2026-10-11T00:00:00+08:00`). Metadata times are UTC.\n\n**Errors.** Always read `success` and `status_code` from the body; do not rely on the HTTP\nstatus alone.\n"
  },
  "servers": [
    {
      "url": "https://api.qubictron.com/vessel-schedules/v1"
    }
  ],
  "security": [
    {
      "apiKey": []
    }
  ],
  "tags": [
    {
      "name": "Vessel Schedules"
    }
  ],
  "paths": {
    "/port-to-port": {
      "get": {
        "tags": [
          "Vessel Schedules"
        ],
        "operationId": "getPortToPortSchedules",
        "summary": "Sailings between two ports",
        "description": "Returns sailings departing from `pol` within the window `[etd, etd + weeks * 7 days]`\n(both days included), sorted by departure time. A sailing belongs to the day it departs in\nits own port's local time. The window cannot extend beyond 8 weeks from today; the window\nactually served is returned in `data.period`.\n",
        "parameters": [
          {
            "name": "pol",
            "in": "query",
            "required": true,
            "description": "Port of loading, UN/LOCODE. Case-insensitive.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z]{2}[A-Za-z0-9]{3}$",
              "example": "CNSHA"
            }
          },
          {
            "name": "pod",
            "in": "query",
            "required": true,
            "description": "Port of discharge, UN/LOCODE. Case-insensitive.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z]{2}[A-Za-z0-9]{3}$",
              "example": "USLGB"
            }
          },
          {
            "name": "etd",
            "in": "query",
            "required": false,
            "description": "First departure day of the window. Default: today (UTC). A date in the past is treated\nas today; a date more than 8 weeks ahead returns `OUT_OF_HORIZON`.\n",
            "schema": {
              "type": "string",
              "format": "date",
              "example": "2026-10-11"
            }
          },
          {
            "name": "weeks",
            "in": "query",
            "required": false,
            "description": "Window length in weeks.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 8,
              "default": 4
            }
          },
          {
            "name": "carrier",
            "in": "query",
            "required": false,
            "description": "Only this carrier, by SCAC. Case-insensitive.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z]{2,4}$",
              "example": "EGLV"
            }
          },
          {
            "name": "direct",
            "in": "query",
            "required": false,
            "description": "`true` — direct sailings only, `false` — sailings with transshipment only. Omit for both.",
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "`SUCCESS`. Also returned when no sailings match (`sailings` is empty) and when the last\nknown schedule is served because the source is unavailable (`cache_expires` in the past).\n",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ScheduleResponse"
                },
                "example": {
                  "success": true,
                  "status_code": "SUCCESS",
                  "metadata": {
                    "updated_at": "2026-10-10T18:55:26Z",
                    "cache_expires": "2026-10-11T06:55:26Z"
                  },
                  "data": {
                    "lane": {
                      "pol": "CNSHA",
                      "pod": "USLGB"
                    },
                    "period": {
                      "from": "2026-10-11",
                      "to": "2026-10-18"
                    },
                    "sailings": [
                      {
                        "carrier": {
                          "scac": "EGLV",
                          "name": "Evergreen"
                        },
                        "service": "CPS",
                        "vessel": {
                          "name": "EVER LAUREL",
                          "imo": "9595474",
                          "mmsi": "566673000"
                        },
                        "voyage": "1241-080E",
                        "pol": {
                          "code": "CNSHA",
                          "name": "SHANGHAI",
                          "terminal": "YANGSHAN PHASE 4 (Shangdong)",
                          "etd": "2026-10-11T00:00:00+08:00",
                          "etd_planned": "2026-10-11T00:00:00+08:00"
                        },
                        "pod": {
                          "code": "USLGB",
                          "name": "LONG BEACH,CA",
                          "terminal": null,
                          "eta": "2026-10-26T00:00:00-07:00",
                          "eta_planned": "2026-10-26T00:00:00-07:00"
                        },
                        "transit_days": 15,
                        "direct": false,
                        "transshipments": [
                          {
                            "port": {
                              "code": "USLAX",
                              "name": "LOS ANGELES,CA"
                            },
                            "terminal": null,
                            "mode": "rail",
                            "service": null,
                            "vessel": {
                              "name": null,
                              "imo": null,
                              "mmsi": null
                            },
                            "voyage": null,
                            "eta": "2026-10-26T00:00:00-07:00",
                            "etd": "2026-10-26T00:00:00-07:00"
                          }
                        ],
                        "cutoffs": {
                          "cy": "2026-10-09T12:00:00+08:00",
                          "si": null,
                          "vgm": "2026-10-09T12:00:00+08:00",
                          "booking": null
                        },
                        "shared_with": [
                          {
                            "scac": "CMDU",
                            "service": "HBB"
                          },
                          {
                            "scac": "COSU",
                            "service": "AAC2"
                          },
                          {
                            "scac": "OOLU",
                            "service": "PCN3"
                          }
                        ]
                      },
                      {
                        "carrier": {
                          "scac": "EGLV",
                          "name": "Evergreen"
                        },
                        "service": "PCC1",
                        "vessel": {
                          "name": "OOCL BERLIN",
                          "imo": "9622605",
                          "mmsi": "477203100"
                        },
                        "voyage": "061E",
                        "pol": {
                          "code": "CNSHA",
                          "name": "SHANGHAI",
                          "terminal": "YANGSHAN PHASE 4 (Shangdong)",
                          "etd": "2026-10-12T00:00:00+08:00",
                          "etd_planned": "2026-10-13T00:00:00+08:00"
                        },
                        "pod": {
                          "code": "USLGB",
                          "name": "LONG BEACH,CA",
                          "terminal": "Long Beach Container Terminal , LLC",
                          "eta": "2026-10-26T00:00:00-07:00",
                          "eta_planned": "2026-10-26T00:00:00-07:00"
                        },
                        "transit_days": 13,
                        "direct": true,
                        "transshipments": [],
                        "cutoffs": {
                          "cy": "2026-10-10T12:00:00+08:00",
                          "si": null,
                          "vgm": "2026-10-10T12:00:00+08:00",
                          "booking": null
                        },
                        "shared_with": [
                          {
                            "scac": "CMDU",
                            "service": "HIXP"
                          },
                          {
                            "scac": "COSU",
                            "service": "AAC4"
                          },
                          {
                            "scac": "OOLU",
                            "service": "PCC1"
                          }
                        ]
                      }
                    ]
                  }
                }
              }
            }
          },
          "400": {
            "description": "`WRONG_PARAMETERS` — a parameter is missing or invalid.\n`OUT_OF_HORIZON` — `etd` is more than 8 weeks ahead.\n",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "success": false,
                  "status_code": "WRONG_PARAMETERS",
                  "metadata": null,
                  "data": null
                }
              }
            }
          },
          "401": {
            "description": "`INVALID_API_KEY` — the API key is missing or unknown. The header name must be lowercase\n`x-api-key`; other spellings are treated as a missing key. Not counted against the limit.\n",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GatewayError"
                },
                "example": {
                  "success": false,
                  "status_code": "INVALID_API_KEY"
                }
              }
            }
          },
          "403": {
            "description": "`API_KEY_ACCESS_DENIED` — the key is valid but has no access to this product, or its\nmonthly request limit is used up; in the latter case `error` is `API_KEY_QUOTA_EXCEEDED`.\nNot counted against the limit.\n",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GatewayError"
                },
                "examples": {
                  "noAccess": {
                    "summary": "Key without access to this product",
                    "value": {
                      "success": false,
                      "status_code": "API_KEY_ACCESS_DENIED",
                      "error": "API_KEY_ACCESS_DENIED"
                    }
                  },
                  "quotaExceeded": {
                    "summary": "Monthly limit used up",
                    "value": {
                      "success": false,
                      "status_code": "API_KEY_ACCESS_DENIED",
                      "error": "API_KEY_QUOTA_EXCEEDED"
                    }
                  }
                }
              }
            }
          },
          "502": {
            "description": "`UPSTREAM_UNAVAILABLE` — the schedule source is unavailable and no schedule for this port\npair has been stored yet. Retry later.\n",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "success": false,
                  "status_code": "UPSTREAM_UNAVAILABLE",
                  "metadata": null,
                  "data": null
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "apiKey": {
        "type": "apiKey",
        "in": "header",
        "name": "x-api-key",
        "description": "Send the header name in lowercase; other spellings are rejected with 401."
      }
    },
    "schemas": {
      "ScheduleResponse": {
        "type": "object",
        "required": [
          "success",
          "status_code",
          "metadata",
          "data"
        ],
        "properties": {
          "success": {
            "type": "boolean",
            "const": true
          },
          "status_code": {
            "type": "string",
            "const": "SUCCESS"
          },
          "metadata": {
            "$ref": "#/components/schemas/Metadata"
          },
          "data": {
            "type": "object",
            "required": [
              "lane",
              "period",
              "sailings"
            ],
            "properties": {
              "lane": {
                "type": "object",
                "required": [
                  "pol",
                  "pod"
                ],
                "properties": {
                  "pol": {
                    "type": "string",
                    "description": "UN/LOCODE, uppercase."
                  },
                  "pod": {
                    "type": "string",
                    "description": "UN/LOCODE, uppercase."
                  }
                }
              },
              "period": {
                "type": "object",
                "description": "The window actually served; both days included.",
                "required": [
                  "from",
                  "to"
                ],
                "properties": {
                  "from": {
                    "type": "string",
                    "format": "date"
                  },
                  "to": {
                    "type": "string",
                    "format": "date"
                  }
                }
              },
              "sailings": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/Sailing"
                }
              }
            }
          }
        }
      },
      "ErrorResponse": {
        "type": "object",
        "required": [
          "success",
          "status_code",
          "metadata",
          "data"
        ],
        "properties": {
          "success": {
            "type": "boolean",
            "const": false
          },
          "status_code": {
            "type": "string",
            "enum": [
              "WRONG_PARAMETERS",
              "OUT_OF_HORIZON",
              "UPSTREAM_UNAVAILABLE"
            ]
          },
          "metadata": {
            "type": "null"
          },
          "data": {
            "type": "null"
          }
        }
      },
      "GatewayError": {
        "type": "object",
        "required": [
          "success",
          "status_code"
        ],
        "properties": {
          "success": {
            "type": "boolean",
            "const": false
          },
          "status_code": {
            "type": "string",
            "enum": [
              "INVALID_API_KEY",
              "API_KEY_ACCESS_DENIED"
            ]
          },
          "error": {
            "type": "string",
            "enum": [
              "API_KEY_ACCESS_DENIED",
              "API_KEY_QUOTA_EXCEEDED"
            ],
            "description": "The reason for a 403."
          }
        }
      },
      "Metadata": {
        "type": "object",
        "required": [
          "updated_at",
          "cache_expires"
        ],
        "properties": {
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the schedule was taken, UTC."
          },
          "cache_expires": {
            "type": "string",
            "format": "date-time",
            "description": "Until when the schedule is considered fresh, UTC. In the past — the last known schedule is served."
          }
        }
      },
      "Sailing": {
        "type": "object",
        "required": [
          "carrier",
          "service",
          "vessel",
          "voyage",
          "pol",
          "pod",
          "transit_days",
          "direct",
          "transshipments",
          "cutoffs",
          "shared_with"
        ],
        "properties": {
          "carrier": {
            "type": "object",
            "required": [
              "scac",
              "name"
            ],
            "properties": {
              "scac": {
                "type": [
                  "string",
                  "null"
                ],
                "example": "EGLV"
              },
              "name": {
                "type": [
                  "string",
                  "null"
                ],
                "example": "Evergreen"
              }
            }
          },
          "service": {
            "type": [
              "string",
              "null"
            ],
            "description": "Carrier's service (loop) code.",
            "example": "CPS"
          },
          "vessel": {
            "$ref": "#/components/schemas/Vessel"
          },
          "voyage": {
            "type": [
              "string",
              "null"
            ],
            "example": "1241-080E"
          },
          "pol": {
            "type": "object",
            "required": [
              "code",
              "name",
              "terminal",
              "etd",
              "etd_planned"
            ],
            "properties": {
              "code": {
                "type": "string",
                "example": "CNSHA"
              },
              "name": {
                "type": [
                  "string",
                  "null"
                ],
                "example": "SHANGHAI"
              },
              "terminal": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "Departure terminal; null when the carrier does not publish it."
              },
              "etd": {
                "type": [
                  "string",
                  "null"
                ],
                "format": "date-time",
                "description": "Current estimated departure, port-local."
              },
              "etd_planned": {
                "type": [
                  "string",
                  "null"
                ],
                "format": "date-time",
                "description": "Originally scheduled departure, port-local."
              }
            }
          },
          "pod": {
            "type": "object",
            "required": [
              "code",
              "name",
              "terminal",
              "eta",
              "eta_planned"
            ],
            "properties": {
              "code": {
                "type": "string",
                "example": "USLGB"
              },
              "name": {
                "type": [
                  "string",
                  "null"
                ],
                "example": "LONG BEACH,CA"
              },
              "terminal": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "Arrival terminal; null when the carrier does not publish it."
              },
              "eta": {
                "type": [
                  "string",
                  "null"
                ],
                "format": "date-time",
                "description": "Current estimated arrival, port-local."
              },
              "eta_planned": {
                "type": [
                  "string",
                  "null"
                ],
                "format": "date-time",
                "description": "Originally scheduled arrival, port-local."
              }
            }
          },
          "transit_days": {
            "type": [
              "integer",
              "null"
            ],
            "example": 15
          },
          "direct": {
            "type": "boolean",
            "description": "false when the sailing has transshipments."
          },
          "transshipments": {
            "type": "array",
            "description": "Intermediate legs in route order; empty for a direct sailing.",
            "items": {
              "$ref": "#/components/schemas/Transshipment"
            }
          },
          "cutoffs": {
            "type": "object",
            "description": "Carrier deadlines at the port of loading, port-local; null when not published.",
            "required": [
              "cy",
              "si",
              "vgm",
              "booking"
            ],
            "properties": {
              "cy": {
                "type": [
                  "string",
                  "null"
                ],
                "format": "date-time",
                "description": "Container yard (gate-in) cutoff."
              },
              "si": {
                "type": [
                  "string",
                  "null"
                ],
                "format": "date-time",
                "description": "Shipping instructions cutoff."
              },
              "vgm": {
                "type": [
                  "string",
                  "null"
                ],
                "format": "date-time",
                "description": "Verified gross mass cutoff."
              },
              "booking": {
                "type": [
                  "string",
                  "null"
                ],
                "format": "date-time",
                "description": "Booking cutoff."
              }
            }
          },
          "shared_with": {
            "type": "array",
            "description": "Other carriers selling space on the same vessel (vessel sharing), with their service codes.",
            "items": {
              "type": "object",
              "required": [
                "scac",
                "service"
              ],
              "properties": {
                "scac": {
                  "type": [
                    "string",
                    "null"
                  ],
                  "example": "COSU"
                },
                "service": {
                  "type": [
                    "string",
                    "null"
                  ],
                  "example": "AAC2"
                }
              }
            }
          }
        }
      },
      "Transshipment": {
        "type": "object",
        "required": [
          "port",
          "terminal",
          "mode",
          "service",
          "vessel",
          "voyage",
          "eta",
          "etd"
        ],
        "properties": {
          "port": {
            "type": "object",
            "required": [
              "code",
              "name"
            ],
            "properties": {
              "code": {
                "type": [
                  "string",
                  "null"
                ],
                "example": "KRPUS"
              },
              "name": {
                "type": [
                  "string",
                  "null"
                ],
                "example": "BUSAN"
              }
            }
          },
          "terminal": {
            "type": [
              "string",
              "null"
            ]
          },
          "mode": {
            "type": [
              "string",
              "null"
            ],
            "description": "Transport mode of the leg in lowercase, e.g. `vessel`, `rail`, `truck`."
          },
          "service": {
            "type": [
              "string",
              "null"
            ]
          },
          "vessel": {
            "$ref": "#/components/schemas/Vessel"
          },
          "voyage": {
            "type": [
              "string",
              "null"
            ]
          },
          "eta": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "Arrival at the transshipment port, port-local."
          },
          "etd": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "Departure from the transshipment port, port-local."
          }
        }
      },
      "Vessel": {
        "type": "object",
        "required": [
          "name",
          "imo",
          "mmsi"
        ],
        "properties": {
          "name": {
            "type": [
              "string",
              "null"
            ],
            "example": "EVER LAUREL"
          },
          "imo": {
            "type": [
              "string",
              "null"
            ],
            "example": "9595474"
          },
          "mmsi": {
            "type": [
              "string",
              "null"
            ],
            "example": "566673000"
          }
        }
      }
    }
  }
}
