Skip to content

About

Official Python SDK by Datalastic. Vessel Tracking Data, Port Information, Vessel Routes, Ship historical data and more.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

3 Commits

Folders and files

Repository files navigation

Datalastic Python SDK

The official Python library for the Datalastic Maritime API. This Python maritime API client covers real-time AIS vessel tracking, port search, sea route calculation, maritime intelligence data, and asynchronous report management.

Installation

pip install datalastic

Requires Python 3.8 or later and the requests library.

Quick start

from datalastic import Client

client = Client("YOUR_API_KEY")

# Real-time position of a single vessel
vessel = client.vessels.get(mmsi="636092297")
print(vessel.name, vessel.lat, vessel.lon, vessel.speed)

# Account usage
stat = client.stat()
print(stat.requests_remaining)

Authentication

Every request includes your API key as the x-api-key HTTP header, set once on the session when you construct the client. You never need to set headers yourself. Pass the key once when constructing the client:

client = Client("YOUR_API_KEY")

# Optional: override the default 30-second timeout
client = Client("YOUR_API_KEY", timeout=10)

Timeouts and retries

Transient failures are retried for you. By default the client retries connection errors, request timeouts, and HTTP 429 up to three times with exponential backoff.

client = Client(
    "YOUR_API_KEY",
    timeout=30,             # per-request timeout, seconds
    max_retries=3,          # 0 disables retrying entirely
    backoff_factor=0.5,     # waits 0.5s, 1s, 2s between attempts
    retry_after_max=60,     # ceiling for any single wait, seconds
    retry_on_status=(429,), # statuses worth repeating
)
Setting Default Notes
timeout 30 Per-request timeout in seconds. Must be a positive number; None is rejected so a request can never hang forever.
max_retries 3 Maximum retries per request. 0 sends exactly one request, as in v0.1.0.
backoff_factor 0.5 Wait before retry n (zero-based) is backoff_factor * 2 ** n.
retry_after_max 60 Ceiling in seconds for every wait, including one derived from a Retry-After header. Nothing waits longer than this.
retry_on_status (429,) Only 408, 429, and 5xx may be listed. Passing 401, 402, 404, or any other client error raises ValueError.

Details worth knowing:

  • Retry-After is honored on 429. Both RFC 7231 forms are supported: delta-seconds (120) and an HTTP-date (Wed, 21 Oct 2026 07:28:00 GMT). A date in the past means "retry now". A missing, malformed, or absurd header falls back to the backoff schedule, and every wait is capped at retry_after_max.
  • Client errors are never retried. 401, 402, 404, and other 4xx statuses describe a problem with the request; repeating it cannot help. They raise immediately.
  • 5xx is not retried by default. The SDK cannot tell a transient upstream blip from a deterministic server-side failure, and retrying every 5xx amplifies load during an incident. If you sit behind a gateway that returns occasional 502/503/504, opt in with retry_on_status=(429, 502, 503, 504).
  • POST is treated as non-idempotent. reports.submit creates a report, so a timeout or dropped connection is not retried: the request may well have reached the server, and repeating it would risk a duplicate report. A retryable status is retried on POST, because the server answered and therefore refused the request rather than performing it.
  • When retries are exhausted the original error surfaces: RateLimitError if the last attempt was a 429, otherwise an APIError carrying the endpoint and the number of attempts made.

Response metadata and pagination

Every method returns the parsed data payload, and every returned object also carries the response envelope on .meta — pagination tokens, credit and usage counters, and the API's success flag.

vessel = client.vessels.get(mmsi="636092297")
print(vessel.name)     # unchanged
print(vessel.meta)     # {'success': True, ...}

Methods that return a collection return a ResultList. That is a real list subclass: iteration, indexing, len(), slicing, and equality with a plain list all work exactly as before. It just adds .meta and .next_token.

ports = client.ports.find(country_iso="NL")
print(len(ports), ports[0].port_name)   # ordinary list access
print(ports.meta)                       # the envelope

.meta is always a dict — an empty one when a response carries no envelope, so result.meta.get("...") is always safe.

Pagination

vessels.find and vessels.in_radius are paginated. Read .next_token off the result and pass it back as next to fetch the following page. .next_token is None on the last page.

page = client.vessels.find(name="MAERSK", vessel_type="cargo")
vessels = list(page)

while page.next_token:
    page = client.vessels.find(
        name="MAERSK", vessel_type="cargo", next=page.next_token
    )
    vessels.extend(page)

print(len(vessels))

vessels.in_radius returns a single VesselInRadiusResult rather than a list, but exposes the same .next_token:

page = client.vessels.in_radius(port_unlocode="NLRTM", radius=20)
found = list(page.vessels)

while page.next_token:
    page = client.vessels.in_radius(
        port_unlocode="NLRTM", radius=20, next=page.next_token
    )
    found.extend(page.vessels)

Vessels

The Datalastic Python SDK exposes eight vessel methods. At least one of uuid, mmsi, or imo is required for all single-vessel lookups.

vessels.get -- real-time basic tracking

vessel = client.vessels.get(mmsi="636092297")
vessel = client.vessels.get(imo="9320403")
vessel = client.vessels.get(uuid="...")

Returns a Vessel.

vessels.pro -- real-time pro tracking

Adds draught, departure/destination ports, ATD, and ETA fields.

vessel = client.vessels.pro(mmsi="636092297")
print(vessel.current_draught, vessel.dest_port, vessel.eta_UTC)

Returns a VesselPro.

vessels.bulk -- lookup many vessels at once

Pass a list or a comma-separated string for each identifier type. Identifiers are sent as repeated query parameters.

result = client.vessels.bulk(mmsi=["636092297", "538005989"])
result = client.vessels.bulk(imo="9320403,9301491")
print(result.total)
for vessel in result.vessels:
    print(vessel.name)

Returns a VesselBulkResult.

vessels.in_radius -- find vessels near a point, port, or vessel

radius (nautical miles) is required. An anchor is also required: either lat + lon, port_uuid, port_unlocode, uuid, mmsi, or imo. Optional filters include type, type_specific, exclude, nav_status, next, and empty.

# By coordinates
near = client.vessels.in_radius(lat=51.95, lon=4.14, radius=50, type="cargo")

# By port UN/LOCODE
near = client.vessels.in_radius(port_unlocode="NLRTM", radius=20)

# Include vessels with no recent AIS position
near = client.vessels.in_radius(lat=51.95, lon=4.14, radius=50, empty=True)

Returns a VesselInRadiusResult.

vessels.history -- historical track

history = client.vessels.history(mmsi="636092297", days=7)
history = client.vessels.history(
    imo="9320403", from_date="2026-01-01", to_date="2026-02-01"
)
for point in history.positions:
    print(point["lat"], point["lon"])

from_date and to_date are sent to the API as from and to. Returns a VesselHistory.

vessels.info -- vessel specifications

info = client.vessels.info(imo="9320403")
print(info.gross_tonnage, info.deadweight, info.year_built)

Returns a VesselInfo.

vessels.find -- search the vessel database

At least one real search criterion is required. fuzzy and next alone do not qualify. vessel_type is sent to the API as the type parameter. Supports the empty boolean to include vessels with no recent AIS data.

matches = client.vessels.find(name="MAERSK", vessel_type="cargo")
matches = client.vessels.find(
    country_iso="DK",
    gross_tonnage_min=50000,
    year_built_min=2010,
)
# Include vessels not currently transmitting
matches = client.vessels.find(name="NORDIC", empty=True)

Returns a ResultList of VesselInfo (a list that also carries .meta and .next_token).

vessels.estimated -- SAT-E estimated position (add-on)

Uses the extended base URL. Returns the latest satellite-estimated position when terrestrial AIS is unavailable.

est = client.vessels.estimated(mmsi="636092297")
print(est.estimated_position)

Returns a VesselEstimated.

Ports

ports.find -- search ports

At least one parameter is required. lat and lon must be provided together.

ports = client.ports.find(name="ROTTERDAM")
ports = client.ports.find(country_iso="NL")
ports = client.ports.find(lat=51.95, lon=4.14, radius=30)
ports = client.ports.find(unlocode="NLRTM")
ports = client.ports.find(port_type="sea")

Returns a ResultList of Port.

ports.get -- retrieve a single port with terminal detail

port = client.ports.get(unlocode="NLRTM")
print(port.port_name, len(port.terminals))

port = client.ports.get(name="ROTTERDAM")

Returns a PortDetail.

Sea routes (add-on)

routes.calculate

Calculates the sea route between an origin and a destination. Each endpoint can be specified as a coordinate pair, a port UUID, or a port UN/LOCODE.

# By coordinates
route = client.routes.calculate(
    lat_from=51.95, lon_from=4.14,
    lat_to=40.65, lon_to=-74.05,
)

# By UN/LOCODE
route = client.routes.calculate(
    port_unlocode_from="NLRTM",
    port_unlocode_to="USNYC",
)

print(route.from_point)
print(route.to_point)
print(route.route["total_dist"])

Returns a SeaRoute.

Maritime intelligence (add-ons)

All intel methods call the maritime_reports base URL and return a ResultList of typed records.

intel.dry_dock

Dry dock schedule records. Filter by imo, name, dry_dock_from, or dry_dock_to.

records = client.intel.dry_dock(imo="9320403")
for r in records:
    print(r.vessel_name, r.dry_dock_date, r.country_name)

Returns a ResultList of DryDockRecord.

intel.casualties

Vessel casualty records. Filter by imo, name, from_date, or to_date.

records = client.intel.casualties(
    imo="9320403", from_date="2025-01-01", to_date="2026-01-01"
)

Returns a ResultList of CasualtyRecord.

intel.inspections

Port state control inspection records. Filter by imo, name, from_date, or to_date.

records = client.intel.inspections(imo="9320403")
for r in records:
    print(r.inspection_date, r.inspection_authority, r.detention)

Returns a ResultList of InspectionRecord.

intel.spd

Sale, purchase, and demolition records. Filter by imo, name, from_date, or to_date.

records = client.intel.spd(imo="9320403")
for r in records:
    print(r.sales_report_date, r.buyer, r.sales_price_usd_mio)

Returns a ResultList of SPDRecord.

intel.ownership

Beneficial ownership and management records. Filter by imo, name, beneficial_owner, operator, technical_manager, commercial_manager, or updated_from.

records = client.intel.ownership(beneficial_owner="MAERSK")
for r in records:
    print(r.vessel_name, r.beneficial_owner_country, r.technical_manager)

Returns a ResultList of OwnershipRecord.

intel.class_society

Classification society records. Filter by imo, name, fuzzy, beneficial_owner, beneficial_owner_imo, technical_manager, technical_manager_imo, or updated_from.

records = client.intel.class_society(imo="9320403")
for r in records:
    print(r.class1_code, r.special_survey_date)

Returns a ResultList of ClassSocietyRecord.

intel.engine

Engine and propulsion records. Filter by imo, name, fuzzy, or updated_from.

records = client.intel.engine(imo="9320403")
for r in records:
    print(r.engine_designation, r.engine_builder, r.mco, r.mco_unit)

Returns a ResultList of EngineRecord.

intel.companies

Maritime company records. Filter by company_imo, name, or updated_from.

records = client.intel.companies(company_imo="0123456")
for r in records:
    print(r.short_name, r.company_type, r.country_code)

Returns a ResultList of CompanyRecord.

Reports

Reports are asynchronous. Submit a request, then poll by ID until the status is "done".

reports.submit

Pass extra report parameters as keyword arguments.

report = client.reports.submit(
    "inradius_history",
    port_uuid="...",
    days=30,
)
print(report.report_id, report.status)

Valid report types:

Type Description
inradius_history Historical positions within a radius
vessel_list Filtered vessel list
port_list Filtered port list
request_usage Account request usage
dry_dock_dates Dry dock schedule export
casualty Casualty data export
inspections PSC inspection data export
sales_purchase_demolitions SPD transactions export
ownership Ownership data export
class_society Classification society export
engine Engine data export
companies Company data export

Returns a Report.

reports.get

Poll the status of a single report.

report = client.reports.get(report.report_id)
if report.status == "done":
    print(report.result_url)

Returns a Report.

reports.list_all

List every report associated with the API key.

for r in client.reports.list_all():
    print(r.report_id, r.report_type, r.status)

Returns a ResultList of Report.

Error handling

All exceptions inherit from DatalasticError.

from datalastic import (
    Client,
    DatalasticError,
    AuthenticationError,
    InsufficientCreditsError,
    NotFoundError,
    RateLimitError,
    APIError,
)

client = Client("YOUR_API_KEY")

try:
    vessel = client.vessels.get(mmsi="636092297")
except AuthenticationError:
    print("Invalid or expired API key")
except InsufficientCreditsError:
    print("Account credits exhausted")
except NotFoundError:
    print("Vessel not found")
except RateLimitError:
    print("Rate limit exceeded")
except APIError as exc:
    print("API error", exc.status_code, exc)
except DatalasticError:
    print("Other SDK error")
Exception HTTP status When raised
AuthenticationError 401 Invalid or expired API key
InsufficientCreditsError 402 No credits remaining
NotFoundError 404 Resource does not exist
RateLimitError 429 More than 600 requests per minute
APIError other / timeout Any other error; carries status_code
DatalasticError -- Base class for all of the above

Input validation errors (ValueError) are raised before any HTTP request is made, so they are never wrapped in a DatalasticError. Invalid client configuration -- a negative max_retries, a non-numeric backoff_factor, a non-retryable entry in retry_on_status -- is also rejected with ValueError at construction, before the client can be used.

Logical failures on HTTP 200

The API can answer with HTTP 200 and still report a failure in the envelope. When meta.success is explicitly false the SDK raises APIError rather than handing back an empty model, and includes meta.message and the endpoint in the error text:

# {"meta": {"success": false, "message": "Vessel not in coverage"}}
try:
    vessel = client.vessels.get(mmsi="636092297")
except APIError as exc:
    print(exc)   # [200] API reported failure (GET .../vessel): Vessel not in coverage

Responses with no meta at all, or a meta without a success key, are treated as successful -- endpoints vary, and only an explicit falsy success is an error.

Every model exposes the raw API payload as .raw for fields not surfaced as named attributes, and the response envelope as .meta.

Model reference

Every model listed below carries two fields in addition to the named ones: raw, the untouched API payload, and meta, the response envelope (plus the derived next_token property). ResultList -- returned by every collection endpoint -- is a list subclass carrying the same meta and next_token.

Vessel

Field Type Notes
uuid str Datalastic vessel UUID
name str Vessel name
mmsi str MMSI identifier
imo str IMO number
eni str ENI number (inland waterways)
country_iso str Flag state ISO code
type str Vessel type
type_specific str Specific vessel type
lat float Last known latitude
lon float Last known longitude
speed float Speed over ground (knots)
course float Course over ground (degrees)
navigation_status str AIS navigational status
heading float True heading (degrees)
destination str AIS-reported destination
last_position_epoch int Unix timestamp of last AIS fix
last_position_UTC str UTC datetime of last AIS fix
eta_epoch int ETA as Unix timestamp
eta_UTC str ETA as UTC datetime string
raw dict Full API response payload

VesselPro

All Vessel fields plus:

Field Type Notes
current_draught float Current draught (metres)
dest_port str Destination port name
dest_port_unlocode str Destination port UN/LOCODE
dep_port str Last departure port name
dep_port_unlocode str Last departure port UN/LOCODE
atd_epoch int Actual time of departure as Unix timestamp
atd_UTC str Actual time of departure as UTC string

VesselEstimated

All VesselPro fields plus:

Field Notes
estimated_position SAT-E estimated position data

VesselBulkResult

Field Notes
total Count of matching vessels
vessels list[Vessel]
raw Full API response payload

VesselInRadiusResult

Field Notes
point The anchor point used for the search
total Count of vessels found
vessels list[Vessel] (each vessel's .raw includes distance)
raw Full API response payload

VesselHistory

uuid, name, mmsi, imo, eni, country_iso, type, type_specific, positions (list of position dicts), raw

VesselInfo

uuid, name, name_ais, mmsi, imo, eni, country_iso, country_name, callsign, type, type_specific, gross_tonnage, deadweight, teu, liquid_gas, length, breadth, draught_avg, draught_max, speed_avg, speed_max, year_built, is_navaid, home_port, raw

Port

uuid, port_name, country_iso, country_name, unlocode, port_type, lat, lon, area_lvl1, area_lvl2, raw

PortDetail

All Port fields plus terminals (list).

SeaRoute

Field Notes
from_point Origin point data from the API
route Route details dict (includes total_dist)
to_point Destination point data from the API
raw Full API response payload

ApiStat

user_id, key_status, requests_made, requests_remaining, raw

Report

report_id, report_type, status, result_url, created_at, updated_at, params, raw

DryDockRecord

id, imo, vessel_name, special_survey_date, dry_dock_date, iopp_issue_date, iopp_exp_date, technical_manager, country_code, country_name, website, email, phone, address, linkedin, modified_at, raw

CasualtyRecord

id, imo, vessel_name, casualty_date, casualty_type, casualty_details, modified_at, raw

InspectionRecord

id, imo, vessel_name, vessel_type_code, flag_code, inspection_date, inspection_authority, inspection_port, inspection_type, detention, ship_deficiencies, deficiency_description, technical_ism_manager, country_code, website, email, phone, address, company_imo, modified_at, raw

SPDRecord

id, sales_report_date, imo, vessel_name, flag_name, vessel_type_code, built_year, dwt_design, gt, ldt, seller, buyer, sales_price_usd_mio, sales_price_usd_per_ldt, destination, sales_type, dry_dock_date, special_survey_date, sales_note, previous_sales_record, modified_at, raw

OwnershipRecord

id, imo, vessel_name, beneficial_owner, beneficial_owner_country, operator, operator_country, flag_name, vessel_type_code, built_year, buyer, dwt_design, class1_code, technical_manager, technical_manager_country, commercial_manager, commercial_manager_country, modified_at, raw

ClassSocietyRecord

imo, vessel_name, vessel_type_code, flag_name, built_year, dwt_design, special_survey_date, dry_dock_date, class1_code, beneficial_owner_imo, beneficial_owner, technical_manager_imo, technical_manager, draft_design, nt, gt, loa, lbp, depth, beam_moduled, engine_builder, engine_designer, propulsion_type_code, modified_at, raw

EngineRecord

imo, vessel_name, vessel_type_code, propulsion_type_code, mco, mco_unit, mco_rpm, trading_category_code, built_year, gt, engine_designation, engine_builder, engine_designer, modified_at, raw

CompanyRecord

id, short_name, long_name, company_type, country_code, company_imo, website, company_status, email, phone, address, linkedin, parent_company_imo, parent_company_name, modified_at, raw

License

MIT. See LICENSE.

About

Official Python SDK by Datalastic. Vessel Tracking Data, Port Information, Vessel Routes, Ship historical data and more.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages