{
  "openapi": "3.1.0",
  "info": {
    "title": "West Coast Shipping calculator API",
    "version": "1.0.0",
    "description": "Rates for shipping a vehicle between the USA and overseas. Export quotes run from a US pickup ZIP to a port of arrival: ground to one of our warehouses (California, Florida, New Jersey, Texas), ocean freight, documentation and optional insurance. Import quotes run from an overseas city to a US ZIP, door to door. Prices are the published rates with the caller's own modifiers applied; `published` fields carry the unadjusted figures. Rates are valid 30 days and are quoted to the port unless stated."
  },
  "servers": [
    {
      "url": "https://wcs-import.wcs-export.workers.dev"
    }
  ],
  "components": {
    "securitySchemes": {
      "bearer": {
        "type": "http",
        "scheme": "bearer",
        "description": "wcs_live_... or wcs_test_... key"
      }
    }
  },
  "paths": {
    "/v1/me": {
      "get": {
        "summary": "Who am I",
        "description": "The calling key: name, kind, partner code, modifiers in force, calls today.",
        "security": [
          {
            "bearer": []
          }
        ],
        "responses": {
          "200": {
            "description": "Key details"
          }
        }
      }
    },
    "/v1/ports": {
      "get": {
        "summary": "Departure warehouses",
        "description": "Our US warehouses a car can be trucked to. Use `id` as `port` in /v1/ground and /v1/quote.",
        "security": [
          {
            "bearer": []
          }
        ],
        "responses": {
          "200": {
            "description": "List of warehouses"
          }
        }
      }
    },
    "/v1/destinations": {
      "get": {
        "summary": "Ports of arrival by country",
        "description": "Every country and port we serve, with which departure warehouses and cargo types have a published lane.",
        "security": [
          {
            "bearer": []
          }
        ],
        "responses": {
          "200": {
            "description": "Countries with ports"
          }
        }
      }
    },
    "/v1/resolve": {
      "get": {
        "summary": "Understand a place",
        "description": "Free text (ZIP, city, port or country) to a place with its role: US places give a ZIP and nearest warehouses; overseas places give the nearest served port, alternatives, and whether the country is served.",
        "security": [
          {
            "bearer": []
          }
        ],
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "Munich"
          }
        ],
        "responses": {
          "200": {
            "description": "Resolved place"
          }
        }
      }
    },
    "/v1/ground": {
      "get": {
        "summary": "Ground rate from a ZIP",
        "description": "Pickup cost from a US ZIP to each warehouse (or one, with `port`), open and enclosed, with miles and days. No contact needed.",
        "security": [
          {
            "bearer": []
          }
        ],
        "parameters": [
          {
            "name": "zip",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^\\d{5}$"
            },
            "example": "60601"
          },
          {
            "name": "port",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Warehouse id or name, e.g. 9 or New Jersey"
          },
          {
            "name": "cargo",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "car",
                "ev",
                "motorcycle",
                "pallet",
                "container4"
              ]
            },
            "description": "Export only. Defaults to car; container4 is a 40ft container with 4 cars where the lane offers it"
          },
          {
            "name": "vehicle_class",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "modern",
                "classic",
                "motorcycle"
              ]
            },
            "description": "Import only: sets the US duty rate (classic = 25 years or older, or a race car). Defaults to modern"
          },
          {
            "name": "built_in",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "EU",
                "UK",
                "Japan",
                "Brazil",
                "Other"
              ]
            },
            "description": "Import only: where the vehicle was built, for the US duty rate. Defaults to the origin country's region"
          },
          {
            "name": "vehicle",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Import only: year, make and model, printed on the quote and the email"
          }
        ],
        "responses": {
          "200": {
            "description": "Ground rates",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "warehouses": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "port": {
                            "type": "string"
                          },
                          "miles": {
                            "type": "number"
                          },
                          "days": {
                            "type": "integer"
                          },
                          "open": {
                            "type": "number",
                            "description": "US dollars"
                          },
                          "enclosed": {
                            "type": "number",
                            "description": "US dollars"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/quote": {
      "get": {
        "summary": "Full quote",
        "description": "Export (US ZIP or city to overseas city, port or country) or import (overseas to US), inferred from the two ends. Export: every departure warehouse priced (ground, ocean, documentation days, insurance, total, days), `selected` is the cheapest unless `port` is given, and the nearest served port is chosen for the destination unless `dest_port` names one. Import: ocean and air options door to door.",
        "security": [
          {
            "bearer": []
          }
        ],
        "parameters": [
          {
            "name": "origin",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "60601",
            "description": "US ZIP or city for export; overseas city for import"
          },
          {
            "name": "destination",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "Munich",
            "description": "Overseas city, port or country for export; US ZIP or city for import"
          },
          {
            "name": "origin_country",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "example": "Germany",
            "description": "Import: the country an overseas postcode is in (a bare postcode such as 80331 cannot be placed on its own; 'origin=80331, Germany' also works)"
          },
          {
            "name": "destination_country",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Export: disambiguates a city name that exists in several countries"
          },
          {
            "name": "cargo",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "car",
                "ev",
                "motorcycle",
                "pallet",
                "container4"
              ]
            }
          },
          {
            "name": "value",
            "in": "query",
            "required": false,
            "schema": {
              "type": "number",
              "description": "US dollars"
            },
            "description": "Declared value in USD, up to 10,000,000; 0 or absent declines insurance; negative or non-numeric values are refused"
          },
          {
            "name": "enclosed",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "0",
                "1"
              ]
            }
          },
          {
            "name": "port",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Force a departure warehouse id"
          },
          {
            "name": "dest_port",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Force a port of arrival by name when the country has several"
          }
        ],
        "responses": {
          "200": {
            "description": "Quote. The `lead` object holds what to pass to /v1/lead (direction, calc, origin, destination, dest_country_id or origin_country) so the customer's email carries this breakdown. An engine error comes back as 200 with `error` (unable_to_validate_address, no_road_route, no_lanes...)"
          },
          "400": {
            "description": "Unresolvable place or unsupported route"
          }
        }
      }
    },
    "/v1/lead": {
      "post": {
        "summary": "Log a customer enquiry",
        "description": "POST, form-encoded or JSON body. Stores the contact and quote summary and creates or updates the HubSpot contact with a timeline note. Partner keys stamp their partner code on the contact. Test keys never reach HubSpot.",
        "security": [
          {
            "bearer": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object",
                "required": [
                  "email"
                ],
                "properties": {
                  "email": {
                    "type": "string",
                    "format": "email"
                  },
                  "first": {
                    "type": "string"
                  },
                  "phone": {
                    "type": "string"
                  },
                  "origin": {
                    "type": "string"
                  },
                  "destination": {
                    "type": "string"
                  },
                  "value": {
                    "type": "number",
                    "description": "US dollars"
                  },
                  "summary": {
                    "type": "string",
                    "description": "The rates you showed, in one line"
                  },
                  "direction": {
                    "type": "string",
                    "enum": [
                      "export",
                      "import"
                    ],
                    "description": "From /v1/quote lead.direction; defaults to export"
                  },
                  "calc": {
                    "type": "string",
                    "description": "From /v1/quote lead.calc, verbatim. The quote is re-priced on our side and the customer's instant-quote email then shows the full breakdown; without it the email says the rate will follow personally"
                  },
                  "origin_country": {
                    "type": "string",
                    "description": "Import leads: from /v1/quote lead.origin_country, routes the lead to the right owner"
                  },
                  "dest_country_id": {
                    "type": "integer",
                    "description": "Export leads: from /v1/quote lead.dest_country_id, routes the lead to the right owner"
                  },
                  "event": {
                    "type": "string",
                    "enum": [
                      "submit",
                      "used"
                    ],
                    "description": "submit (default) files the lead and sends the instant-quote email; used only records the lead"
                  },
                  "page_name": {
                    "type": "string"
                  },
                  "last": {
                    "type": "string"
                  },
                  "hutk": {
                    "type": "string",
                    "description": "The visitor's hubspotutk cookie, when the lead comes from a browser; gives the contact its source and UTM attribution in HubSpot"
                  },
                  "page_uri": {
                    "type": "string",
                    "description": "URL of the page the enquiry was made on"
                  }
                }
              }
            },
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "email"
                ],
                "properties": {
                  "email": {
                    "type": "string",
                    "format": "email"
                  },
                  "first": {
                    "type": "string"
                  },
                  "phone": {
                    "type": "string"
                  },
                  "origin": {
                    "type": "string"
                  },
                  "destination": {
                    "type": "string"
                  },
                  "value": {
                    "type": "number",
                    "description": "US dollars"
                  },
                  "summary": {
                    "type": "string",
                    "description": "The rates you showed, in one line"
                  },
                  "direction": {
                    "type": "string",
                    "enum": [
                      "export",
                      "import"
                    ],
                    "description": "From /v1/quote lead.direction; defaults to export"
                  },
                  "calc": {
                    "type": "string",
                    "description": "From /v1/quote lead.calc, verbatim. The quote is re-priced on our side and the customer's instant-quote email then shows the full breakdown; without it the email says the rate will follow personally"
                  },
                  "origin_country": {
                    "type": "string",
                    "description": "Import leads: from /v1/quote lead.origin_country, routes the lead to the right owner"
                  },
                  "dest_country_id": {
                    "type": "integer",
                    "description": "Export leads: from /v1/quote lead.dest_country_id, routes the lead to the right owner"
                  },
                  "event": {
                    "type": "string",
                    "enum": [
                      "submit",
                      "used"
                    ],
                    "description": "submit (default) files the lead and sends the instant-quote email; used only records the lead"
                  },
                  "page_name": {
                    "type": "string"
                  },
                  "last": {
                    "type": "string"
                  },
                  "hutk": {
                    "type": "string",
                    "description": "The visitor's hubspotutk cookie, when the lead comes from a browser; gives the contact its source and UTM attribution in HubSpot"
                  },
                  "page_uri": {
                    "type": "string",
                    "description": "URL of the page the enquiry was made on"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Stored"
          },
          "405": {
            "description": "GET is refused; use POST"
          }
        }
      }
    }
  }
}