Integration

WAYBILL API

Container shipping data — sailing schedules, ocean carriers, fleet and services — straight into your system. Plain HTTP requests, JSON responses, one key in a header.

REST · JSON HTTPS gzip No SDK
0sailings in schedule
0ocean carriers
0vessels in fleet
0services

Why it matters

What the integration gives you

No more manual exports and copy-paste: data arrives in your system in a shape that is ready to process.

Schedules inside your system

Sailings with vessel, voyage number, ports of loading and discharge, departure and arrival dates, transit time and arrival terminal. Filters by carrier, vessel, ports and date range.

Ocean carrier directory

Legal entity, country of registration, trade areas, directions, agents in Russia with contacts and terminals. A ready source for your counterparty records.

Fleet and capacity

Vessels with IMO number, type, TEU capacity, deadweight, year built, age and flag. Useful for assessing a carrier capacity on a given trade.

Services and routings

Service identifiers, port rotations, countries of origin and destination. Lets you build automatic routing options for a required direction.

Always current, hands-free

We keep the data up to date, you receive it with every request. Each response carries the date of the last update, so you can sync only what has actually changed.

Predictable access

A personal key, a daily request limit and per-section permissions. The remaining quota is shown in every response, so nothing gets cut off without warning.

Typical use cases

Freight forwarders

Nearest departures for a route right inside your CRM, without searching carrier websites by hand.

Cargo owners

Planned shipping dates in your ERP: the schedule is pulled in automatically and stays current.

Analysts

Fleet and service data in your BI tool to assess capacity and trade dynamics.

Developers

A ready reference of carriers, ports and terminals for your internal services.

Getting started

Three steps to connect

From request to first response usually takes one business day.

01

Send a request

Write to service@way-bill.ru with your company name, the data sections you need and an estimated number of daily requests. For companies we prepare a contract and an invoice.

02

Receive your key

We issue a personal key in the form wb_live_… and agree on a daily limit and validity period. The key is shared once — store it like a password.

03

Make the first request

Verify access on /v1/meta, then move on to the data you need. Code samples in four languages are below.

Trial access. Before signing a contract we issue a test key with a limit of 100 requests per day for two weeks — enough to review the data structures and build the integration.

Quick start

Your first request

The key goes in the X-API-Key header. Nothing else is required.

curl -H "X-API-Key: YOUR_KEY" \
     -H "Accept-Encoding: gzip" \
     "https://api.way-billapi.ru/v1/schedule?line=FESCO&limit=5"
import requests

BASE = "https://api.way-billapi.ru/v1"
HEADERS = {"X-API-Key": "YOUR_KEY"}

r = requests.get(f"{BASE}/schedule",
                 headers=HEADERS,
                 params={"line": "FESCO", "limit": 5},
                 timeout=20)
r.raise_for_status()
payload = r.json()

for row in payload["data"]:
    print(row["vessel"], row["voyage"], row["portFrom"], "→", row["portTo"], row["etd"])

print("requests left:",
      payload["meta"]["quota"]["limit"] - payload["meta"]["quota"]["used"])
const BASE = "https://api.way-billapi.ru/v1";

async function schedule(params) {
  const url = new URL(BASE + "/schedule");
  Object.entries(params).forEach(([k, v]) => url.searchParams.set(k, v));

  const res = await fetch(url, { headers: { "X-API-Key": "YOUR_KEY" } });
  if (!res.ok) {
    const err = await res.json();
    throw new Error(err.error.code + ": " + err.error.message);
  }
  return res.json();
}

schedule({ line: "FESCO", limit: 5 }).then(p => console.table(p.data));
<?php
$base = "https://api.way-billapi.ru/v1";
$url  = $base . "/schedule?" . http_build_query(["line" => "FESCO", "limit" => 5]);

$ch = curl_init($url);
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_ENCODING       => "gzip",
    CURLOPT_HTTPHEADER     => ["X-API-Key: YOUR_KEY"],
    CURLOPT_TIMEOUT        => 20,
]);
$body = curl_exec($ch);
curl_close($ch);

$payload = json_decode($body, true);
foreach ($payload["data"] as $row) {
    echo $row["vessel"], " ", $row["voyage"], " ", $row["etd"], PHP_EOL;
}

Reference

Documentation

API version v1. Every section is available over HTTPS and via GET only.

Base URL

https://api.way-billapi.ru/v1

A full request URL is the base URL plus the section name, for example https://api.way-billapi.ru/v1/lines. Plain HTTP requests are redirected to HTTPS automatically.

Authentication

The key is passed in a header:

X-API-Key: wb_live_a7f3c9d2e1b48605

Authorization: Bearer <key> is supported as well — convenient if your HTTP client is built around that scheme. A request without a key returns 401; an unknown or revoked key returns 403.

Never put the key in front-end code, mobile apps or public repositories: it grants access on your behalf and consumes your quota. Call the API from your own server.

Response format

A successful response always has the same shape: payload in data, service information in meta.

{
  "data": [ … ],
  "meta": {
    "total": 1284,
    "limit": 100,
    "offset": 0,
    "updated": "2026-08-23",
    "quota": { "limit": 5000, "used": 132 }
  }
}

total is how many records matched the filters in total, updated is the date the data was last refreshed on our side, quota is your daily limit and current usage.

Pagination: limit (100 by default, 1000 maximum) and offset. Keep fetching pages while offset + limit is less than total.

Limits

The daily limit belongs to the key and resets at midnight UTC. Current usage is shown in meta.quota of every response, so no separate call is needed.

Once the limit is reached you get 429 with code daily_limit. If the limit is consistently too low, write to us and we will raise it.

Endpoints

GET /v1/meta Update dates and data volumes

A lightweight call to verify access and monitor data freshness. No parameters.

{
  "data": {
    "schedule": { "updated": "2026-08-23", "voyages": 1284 },
    "lines":    { "updated": "2026-08-17", "total": 131, "active": 70 },
    "vessels":  248,
    "services": 125
  }
}
GET /v1/schedule Sailing schedule
ParameterTypeDescription
linestringCarrier name, exact match
vesselstringVessel name
voyagestringVoyage number
portFromstringPort of loading, substring match
portTostringPort of discharge, substring match
terminalstringArrival terminal
etdFromdateDeparture on or after, format YYYY-MM-DD
etdTodateDeparture on or before
limit, offsetnumberPagination
GET /v1/schedule?portTo=Novorossiysk&etdFrom=2026-09-01&limit=2

{
  "data": [
    {
      "line": "AKKON LINES", "vessel": "LIDER PERIHAN", "voyage": "2536W",
      "portFrom": "Gebze", "etd": "2026-09-02",
      "portTo": "Novorossiysk", "terminal": "NUTEP",
      "eta": "2026-09-06", "transit": "4"
    }
  ],
  "meta": { "total": 314, "limit": 2, "offset": 0, "updated": "2026-08-23" }
}
GET /v1/lines Ocean carrier directory
ParameterTypeDescription
qstringSearch by name and legal entity
basinstringTrade area. Values come in Russian: Балтийский (Baltic), Азово-Черноморский (Azov–Black Sea), Дальневосточный (Far East), Каспийский (Caspian), Арктический (Arctic)
active1 or 0Active carriers only, or discontinued only
limit, offsetnumberPagination

The list returns short records: name, slug, legal entity, country, trade areas, status and fleet statistics.

GET /v1/lines/{slug} Full carrier record

The slug comes from the slug field in the carrier list, for example /v1/lines/fesco. Returns description, address, directions, agents with contacts, services and the full vessel list. If the carrier is not found — 404.

GET /v1/vessels Fleet
ParameterTypeDescription
linestringFleet of a single carrier
imostringA specific vessel by IMO number
limit, offsetnumberPagination
{
  "data": [
    { "line": "FESCO", "name": "FESCO SOFIA", "imo": "9237503",
      "type": "Container Ship", "teu": 2702, "dwt": 33745,
      "built": "2002", "age": 24, "flag": "Russia" }
  ]
}
GET /v1/services Services and routings
ParameterTypeDescription
linestringServices of a single carrier
countryFromstringCountry of origin
podstringPort of discharge
limit, offsetnumberPagination
GET /v1/positions Vessel positions · on request

Live vessel coordinates, speed and course. This section is provided on a case-by-case basis: the data comes from an external AIS provider and redistribution is governed by their terms. When access is off, the section returns 503 with an explanation.

Errors

Errors use the same envelope as data, but with an error key:

{ "error": { "code": "daily_limit", "message": "Daily request limit reached." } }
HTTP codecodeWhat happened
401no_keyThe key header was not sent
403bad_keyKey is unknown or revoked
403key_expiredKey has expired
403scope_deniedKey has no access to this section
404not_foundUnknown path or carrier not found
405method_not_allowedA method other than GET was used
429daily_limitDaily limit reached
503positions_disabledPositions section is not enabled
500internalInternal error, retry later

Best practices

  • Enable gzip. The Accept-Encoding: gzip header cuts response size by roughly 84 percent.
  • Cache. Schedules change once a day, reference data less often. Compare meta.updated and avoid pulling the same payload in a loop.
  • Use larger pages. A request with limit=1000 saves calls when you process the whole set anyway.
  • Handle 429. When the limit is reached, wait until the next day instead of retrying in a loop.
  • Set a timeout. Fifteen to twenty seconds is enough; on failure retry once.

Questions

Frequently asked

Sailing schedules — daily. Carrier, fleet and service directories — as carriers publish changes, usually several times a month. The exact date of the last update for each set comes in meta.updated.

No. These are plain HTTP requests with a single header, callable from any language and even from the browser console. Samples for four languages are above.

Yes. Every key has its own list of permitted sections. A key may open the schedule only — calls to the rest return 403 scope_denied.

Requests return 429 until the next UTC day begins. Access is not blocked and needs no restoring — wait for the counter to reset or ask us to raise the limit.

Write to us — we revoke the old key and issue a new one within a business day. Revocation takes effect immediately.

Within v1 we never remove or rename existing fields. New fields may appear — write your parser so that it ignores unknown ones.

Get API access

Tell us about your use case — we will suggest the right sections and limit, and issue a test key.

Made on
Tilda