# Singapore Bunker Demand & Tanker Flow Divergence (`zinin/singapore-bunker-tanker-divergence`) Actor

Compare official monthly Singapore bunker demand, tanker arrivals, fuel mix, and vessel calls in one evidence report. Add optional bounded BYOK tanker pressure, with publication lag, freshness, confidence, null reasons, provenance, gaps, and human review.

- **URL**: https://apify.com/zinin/singapore-bunker-tanker-divergence.md
- **Developed by:** [Tim Zinin](https://apify.com/zinin) (community)
- **Categories:** MCP servers, Automation, Travel
- **Stats:** 1 total users, 0 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.0425 / delivered singapore divergence report

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Singapore Bunker Demand & Tanker Flow Divergence

![Singapore Bunker and Tanker Divergence: official evidence, direction, confidence, and review](https://raw.githubusercontent.com/TimmyZinin/apify-actor-assets/8192b1d6e7092f54d1c5e401786e5c0be091e318/commercial115/singapore-bunker-tanker-divergence/readme-hero.webp)

![Singapore Bunker and Tanker Divergence: two bounded signals to one reviewable report](https://raw.githubusercontent.com/TimmyZinin/apify-actor-assets/8192b1d6e7092f54d1c5e401786e5c0be091e318/commercial115/singapore-bunker-tanker-divergence/readme-workflow.webp)

### What this Actor does

This Actor measures whether Singapore's official monthly bunker demand and tanker arrivals are moving together or apart. It combines four Singapore Government data.gov.sg resources covering tanker arrivals and gross tonnage, total bunker sales, bunker sales by fuel type, and vessel calls.

The official data is monthly and may lag publication. The report exposes `latestMonth` and `lagMonths`; it does not describe official data as real-time. Optional `open_plus_byok` mode adds aggregate live tanker pressure from two bounded Datalastic provider requests: `/stat` plus a fixed 10 NM Singapore zone, accepting up to 500 rows. It does not sell or return raw AIS data.

### Key features

- Aggregate tanker arrivals, gross tonnage, bunker demand, low-carbon share, and vessel calls.
- Exact 3-month and 12-month baselines only when the required prior months are consecutive and category-complete.
- Explicit null reasons for unavailable baselines, month-over-month values, and year-over-year values.
- Same-watch locking before any buyer-funded Datalastic request.
- One confirmed `result-found` delivery at most, with state saved while the lock is still owned and confirmed billing never rewritten as unknown.
- Aggregate-only output with no MMSI, IMO, vessel names, coordinates, routes, provider keys, or identity salt.

### Input

`schemaVersion` is required; `requestId`, `watchId`, and `sourceMode` default to `auto`, `singapore-bunker-main`, and `open` respectively. `sourceMode` is:

- `demo`: synthetic fixture, one Dataset row after the `$0.005` actor-start charge, and no `$0.05` `result-found` event;
- `open`: four official Singapore datasets without a provider key;
- `open_plus_byok`: requires a syntactically valid buyer-owned Datalastic key before any official source, lock, provider call, pricing check, or delivery; then uses the official datasets plus `/stat` and one fixed Singapore-zone request.

`baselineMonths` defaults to 12. `maxRows` defaults to 240 and is bounded to 240–500. Each official resource uses one page; four first attempts are expected, while retries share one Actor-wide budget of 12 actual HTTP attempts. Older history is marked `partialReason: older_history_truncated` and is accepted only after exact required-field, numeric, cardinality, uniqueness, and latest-plus-baseline validation. The observed monthly cardinalities are 8 arrival categories, 1 bunker-total row, 16 bunker-breakdown categories, and 5 vessel-call categories. Vessel-call validation uses the published call count; the source's nullable gross-tonnage column is not requested or used by this product. `maxProviderRequests` is fixed at 2 for BYOK. `maxTotalChargeUsd` defaults to `$0.055`.

### How to run

Use the Actor input editor or an Apify Task with `requestId: "auto"`. An open-mode input is:

```json
{
  "schemaVersion": "1.0",
  "requestId": "auto",
  "watchId": "singapore-bunker-main",
  "sourceMode": "open",
  "baselineMonths": 12,
  "maxRows": 240,
  "maxProviderRequests": 2,
  "maxTotalChargeUsd": 0.055
}
```

For `open_plus_byok`, add a buyer-owned `datalasticApiKey`. Omit the field for `demo` and `open`; an explicit `null` is invalid in every mode. The key is secret input and is used in memory to derive the live identity salt; neither value is output or persisted. If a request or watch identifier contains the current key, the run fails before source, lock, billing, or state effects and only a domain-separated opaque identifier may appear in the terminal envelope.

### Output

Every useful run delivers one aggregate report. `official.coverage` states whether the requested consecutive baseline and monthly-lag policy are satisfied and records the expected monthly category cardinalities. A representative terminal envelope is:

```json
{
  "schemaVersion": "1.0",
  "actor": "singapore-bunker-tanker-divergence",
  "requestId": "run-id",
  "status": "complete",
  "resultFound": true,
  "billedResultCount": 1,
  "baselineAdvanced": true,
  "report": {
    "status": "complete",
    "official": {
      "latestMonth": "2026-05",
      "lagMonths": 1,
      "complete": true,
      "coverage": {
        "complete": true,
        "reason": null,
        "requiredPriorMonths": 12,
        "consecutivePriorMonths": 12
      }
    }
  },
  "errors": []
}
```

Replay safety is fail-closed. A persisted request intent is treated as untrusted data and must match the closed Actor/schema/request/watch/report/state contract; malformed, poisoned, `PREPARED`, or `AMBIGUOUS` replays return `request_replay_blocked` with no report and do not call Datalastic, charge, or write state. An `UNCHARGED` replay returns the same budget refusal with zero billing and no effects. A clean confirmed replay does not charge again and may only save a state validated against the current input contract.

Persisted report sources, licenses, attribution URLs, limitations, signal names, and absence reasons are canonical enum codes. `reportId` is recomputed from the complete unsigned report, including the exact `previousStateDigest`, and replay runs through the same semantic validator as newly generated reports. A complete report is `bootstrap` only with an empty predecessor and `complete` only with a valid predecessor digest; partial reports remain `partial`. Every `sources[].retrievedAt` timestamp must be no later than `observedAt`; no positive clock skew is accepted, and complete live freshness is checked by exact timestamp arithmetic. Every nullable decision value has an exact paired reason: null requires a reason and a present value requires a null reason. The closed ledger stores the exact predecessor state and digest plus a null-only delivery receipt field, binds source mode and state-contract/final-state digests, and rejects provider prose, raw identities, and credentials before OUTPUT, Dataset, KVS, or logs. A definitive second-gate budget refusal is persisted as `UNCHARGED` and replays as the same zero-billing result; only uncertain delivery remains `AMBIGUOUS`. Confirmed reconciliation authenticates the recorded predecessor-to-next-state transition before accepting an identical or monotonic successor, then remains monotonic under the watch lock with prefix lineage before 365 observations and ring-buffer overlap lineage at the cap, so an older replay cannot overwrite a newer baseline.

If any source lacks the required complete consecutive months, has a malformed/duplicate/negative row, exhausts the shared attempt budget, returns an unclassified partial response, or is more than three calendar months behind the run month, no useful paid report is delivered. `baseline12Month` and `yearOverYearPercent` remain `null` with explicit reasons. State is saved after exact paid-delivery confirmation while the same-watch lock is still held, then the lock is released. A state-write failure reports `resultFound: true`, `billedResultCount: 1`, and `baselineAdvanced: false`. Release uncertainty after a proven save reports `resultFound: true`, `billedResultCount: 1`, and `baselineAdvanced: true`; it never erases known billing or state proof.

### Pricing

The exact base PPE contract is `$0.005` for `apify-actor-start` and `$0.05` for one delivered `result-found` report, for `$0.055` total before buyer-owned provider costs. Allowed discount tiers are 0%, 5%, 10%, 15%, 18%, and 20%. There is no priced default Dataset-item event. Demo mode still incurs the actor-start charge but has no `$0.05` result fee.

### Data quality

Completeness requires the latest common category-complete month plus `baselineMonths` prior consecutive complete months across every promised series. The latest official month may lag the run month by at most three calendar months; month three is eligible and is not labelled stale, while month four and beyond are partial, emit `DATA_STALE`, and fail closed without a result event. A partial edge month, a missing middle month, or truncated multi-category response is excluded rather than silently aggregated. Live pressure requires an exact complete response for the fixed 10 NM Singapore zone, at least one safe tanker snapshot, and at least 95% fresh coverage. Structurally valid snapshots older than 3600 seconds are excluded and reflected in provider/accepted counts; malformed, future, empty, or lower-coverage responses fail closed.

Singapore Government attribution: [Singapore Open Data Licence](https://data.gov.sg/open-data-licence). Datalastic data is used only for derived aggregates under provider terms.

### Limitations

- Official records are monthly and may be published with a delay.
- The Actor is not for navigation and does not claim official berth, queue, booking-slot, or real-time vessel status.
- The fixed 12-request official ceiling can still be insufficient if source cardinality increases; that run fails closed.
- Live pressure is not a route, identity, sanctions, ownership, or tactical signal.
- Source outages, incomplete coverage, budget caps, state failures, lock failures, and uncertain billing fail closed.

### What the Actor gives you

The product answers a bounded question: **are official Singapore bunker-demand measures and tanker-flow measures moving together, or is there a reviewable divergence?** It creates one aggregate evidence report with the current official period, prior-period comparisons, baseline availability, optional live pressure, quality limitations, and deterministic signals.

It is useful for commercial analysts, bunker-market teams, maritime research, capacity review, and evidence collection when the decision owner needs a compact record rather than raw source tables. The report can help a reviewer decide whether to investigate timing, product mix, inventory behavior, vessel-call composition, or publication lag.

It does not prove causality. A divergence can be caused by window alignment, reporting definitions, fuel mix, vessel class, cargo timing, storage behavior, source revisions, or incomplete live coverage. The Actor does not choose between those explanations and does not trade, route, book, notify, or write to another system.

### Official evidence included

Open mode reads four fixed Singapore Government resources through bounded, schema-checked requests. The public report carries the publisher, exact Dataset identifier, retrieval timestamp, licence code, and attribution URL.

| Evidence family | Report use | Completeness rule |
| --- | --- | --- |
| Vessel arrivals | Tanker arrivals and gross tonnage by month. | Exact expected categories, unique rows, numeric nonnegative measures, consecutive months. |
| Total bunker sales | Current demand, month-over-month and year-over-year comparison. | Exactly one eligible total per month, required offset months present. |
| Bunker sales by fuel type | Product composition and low-carbon share. | Exact expected fuel categories with no duplicate or malformed records. |
| Vessel calls | Wider port-activity context. | Published call-count field only; nullable source gross tonnage is intentionally not used. |

The official source is monthly. `latestMonth` is the latest category-complete month common to every required series. `lagMonths` is calendar lag from the run month. A lag of three remains eligible; four or more is partial and cannot create a paid useful report. This is a publication-lag rule, not a claim about the age of every underlying commercial activity.

The Actor requests only the columns used in its contract. It does not fill missing months, interpolate absent categories, replace null values with zero, or silently accept a partial edge month. Those choices are deliberate: a missing middle month can change a trend conclusion even when the latest value looks valid.

### Optional live pressure

`open_plus_byok` adds a second evidence family: aggregate safe tanker snapshots inside one fixed 10 NM Singapore zone. It performs one provider-account check and one bounded zone request. The provider key remains buyer-controlled, and the output excludes vessel identities, coordinates, routes, names, source prose, and the key.

Live pressure is eligible only when:

- the provider response is explicitly complete and contains no error or partial marker;
- at least one safe tanker snapshot is accepted;
- every accepted identity and position needed internally is structurally valid;
- source timestamps are not in the future and no accepted snapshot is older than one hour;
- fresh timestamp coverage is at least 95%; and
- provider and accepted counts reconcile with the stated coverage.

Older but structurally valid rows are excluded and counted in the coverage evidence. Malformed, future, empty, or below-threshold coverage fails closed. A live count is a bounded observed pressure measure; it is not a complete port queue, berth schedule, route, or official vessel-call count.

### How to read the report

Read the report in this order:

1. `status` tells you whether the report is `bootstrap`, `complete`, or `partial`.
2. `dataQuality` states confidence, source completeness, official publication month, lag, and partial state.
3. `official.coverage` shows whether all consecutive months and category cardinalities were present.
4. `official` metrics give the current values and exact baseline comparisons.
5. `live` shows optional bounded tanker pressure and its independent freshness/coverage evidence.
6. `signals` lists thresholds that were actually crossed.
7. `limitations`, reason fields, and `sources` state what is missing and where the evidence came from.

#### Null is evidence, not zero

Every nullable decision metric has a paired reason. A 12-month baseline may be null because twelve consecutive complete prior months do not exist. A live ratio may be null because live mode was not requested, the source was incomplete, or too few safe observations were available. Downstream code should preserve both the null and its reason; coercing null to zero creates a conclusion the source did not support.

#### Signals are review triggers

Signals use fixed thresholds. Bunker-demand changes are emitted at plus or minus five percent. A tanker-arrival surge requires a current-to-three-month-baseline ratio of at least 1.2. A low-carbon-share increase requires at least one percentage point. Boundary tests intentionally exclude 0.99 percentage points.

A signal is not a forecast, recommendation, or proof of cause. It means a deterministic threshold over complete accepted inputs was met. No signal means the threshold was not met, not that the market is normal.

### Evidence-to-action workflow

Use the Actor as one step in a reviewed process:

1. Define the watch and the commercial question before seeing the result.
2. Confirm official coverage and publication lag.
3. Separate monthly official movement from optional short-lived tanker pressure.
4. Inspect product mix and source definitions before comparing magnitudes.
5. Review every null reason and partial limitation.
6. Record plausible explanations as hypotheses, not facts.
7. Decide whether to investigate, annotate, monitor, or close the review.
8. Store the `reportId`, observation month, source list, build/run identifiers, and reviewer outcome.

Examples of sensible next actions include checking whether a changed fuel mix explains a total, waiting for a revised month, comparing with a separate price series, or asking an authorized provider for greater coverage. Examples of unsafe actions include automatically trading, changing voyage instructions, identifying a vessel, or claiming a causal supply disruption from one divergence report.

### Delivery, billing, and replay truth

The Dataset is the report channel; `OUTPUT` is the authoritative run and settlement channel. A useful non-demo report is delivered with one linked `result-found` event. Demo uses an ordinary unpriced Dataset write and still incurs the automatic start event.

| Outcome | Dataset | Result event | State | Retry guidance |
| --- | --- | --- | --- | --- |
| Demo | One synthetic report | Zero | Not advanced | A fresh run is a fresh start purchase. |
| Confirmed useful report | One aggregate report | Exactly one | Advanced after confirmed delivery | Do not rerun to “confirm” billing. |
| Definitive budget refusal | No useful paid report | Confirmed zero | Not advanced | Same request replays the refusal without new effects. |
| Source or quality refusal | Diagnostic OUTPUT only | Not attempted | Not advanced | Correct the evidence problem before a new request. |
| Ambiguous delivery | May already contain a row | Unknown | Not advanced | Never retry blindly; reconcile the existing run. |
| State save failure | Paid report remains confirmed | Exactly one | Persistence unknown/not advanced | Investigate state; do not buy the same evidence again. |
| Lock release uncertainty | Preserves proven row and billing | Preserves known count | Preserves proven save | Investigate lock ownership before scheduling again. |

The request-intent ledger provides replay control for the same derived request. It does not make an unrelated new run free. Each new Actor run still incurs the automatic start event, and a genuinely new useful observation can emit a new paid result.

### API, Tasks, schedules, and MCP

For a one-off open-data report:

```bash
curl -X POST \
  "https://api.apify.com/v2/acts/zinin~singapore-bunker-tanker-divergence/runs?token=$APIFY_TOKEN" \
  -H "content-type: application/json" \
  -d '{
    "schemaVersion":"1.0",
    "requestId":"auto",
    "watchId":"singapore-bunker-main",
    "sourceMode":"open",
    "baselineMonths":12,
    "maxRows":240,
    "maxProviderRequests":2,
    "maxTotalChargeUsd":0.055
  }'
```

For a schedule, create a Task with a stable `watchId`. Use `requestId: "auto"` unless you are deliberately reconciling one known request. Do not overlap runs for the same watch. A same-watch lock protects the baseline, but avoiding overlap also keeps schedules, reviews, and billing easier to reason about.

An MCP or automation client should wait for the platform terminal status, then read `OUTPUT`, the Dataset, and charged-event counts. Accept a useful result only when the output/report schemas pass, the Dataset report matches `OUTPUT.report`, the report digest is valid, the quality contract is complete, and the platform shows the expected start plus exactly one result event.

The Actor never calls a CRM, sends an alert, changes a booking, or executes a trade. Those actions require a separate reviewed automation with its own authorization and failure handling.

### Rights, attribution, privacy, and retention

Singapore Government records are used under the Singapore Open Data Licence and retain source attribution in the report. Follow the linked licence for attribution, permitted use, disclaimers, and change indication. The Actor transforms source tables into aggregate comparisons; it does not represent the output as an official Singapore Government conclusion.

Datalastic mode is BYOK. You are responsible for a provider plan and permissions that cover collection, transformation, retention, and downstream use. Public output is aggregate-only, but salted or hashed source identities remain pseudonymous technical data rather than a universal guarantee of legal anonymity.

Use a documented business purpose, restrict access, and set retention for Actor Datasets, KVS records, Tasks, exports, and downstream copies. Do not submit secrets in identifiers or URLs. Do not combine the report with other data to identify vessels, owners, crews, cargo, sanctions status, military activity, or individual behavior.

### Production checklist

Before enabling a recurring watch:

- run `demo` to verify your integration without a result event;
- run `open` to verify official-source access and attribution;
- use `open_plus_byok` only after provider-rights and key handling are approved;
- keep a stable, non-secret `watchId` and an explicit owner for the review;
- ensure the charge cap covers the current tier's start plus one result;
- preserve nulls and reason fields in downstream storage;
- alert on partial, ambiguous, state-write, and lock-release states without automatic retry;
- retain run/build/report identifiers and platform event counts for reconciliation;
- define storage retention and deletion before scheduling.

### Troubleshooting

| Symptom | Meaning | Response |
| --- | --- | --- |
| `older_history_truncated` | Rows outside the bounded useful history were present. | Verify the required current and consecutive baseline months remain complete. |
| `DATA_STALE` | Official lag exceeds three months or another quality gate failed. | Inspect `latestMonth`, `lagMonths`, coverage, and source errors. |
| Null 12-month metric | The exact offset or consecutive category-complete history is absent. | Preserve the reason; do not substitute zero or a shorter baseline. |
| Live pressure unavailable | BYOK was not requested or live coverage failed. | Inspect provider/accepted counts, timestamps, and coverage reason. |
| `watch_busy` | Another run owns the same watch. | Wait for it to settle; do not start a retry race. |
| `request_replay_blocked` | Stored intent/state is prepared, ambiguous, poisoned, or incompatible. | Reconcile the original run and storage before creating new work. |
| Budget refusal | Cap cannot cover current tier settlement. | Review the price tier and cap; the result unit remains uncharged. |

### Acceptance criteria

A production consumer should classify a run as accepted only when the exact build is known, the platform run succeeded, `OUTPUT` is present and schema-valid, the Dataset contains the expected one aggregate report, the Dataset row and `OUTPUT.report` are identical, `reportId` recomputes, official coverage is complete, lag is within policy, required live coverage is complete when requested, no partial condition is present, and platform event counts reconcile to one start and one new result unit. A demo is accepted under a different rule: one synthetic Dataset row, zero result units, and no state advance.

### FAQ

#### Why is a 12-month baseline null?

At least 12 prior consecutive category-complete months are required. The reason field identifies missing or truncated coverage.

#### Is demo completely free?

No. Demo has no `$0.05` `result-found` fee, but the `$0.005` actor-start charge still applies at the base tier.

#### Does a busy watch spend Datalastic calls?

No. The same-watch lock is acquired before `/stat` or the Singapore-zone request.

### Related Actors

| Actor | Workflow reason |
|---|---|
| [Strait of Hormuz Tanker Flow Recovery](https://apify.com/zinin/strait-of-hormuz-tanker-flow-recovery) | Compare Singapore bunker demand with aggregate tanker-flow recovery through Hormuz. |
| [Panama Canal Queue Transit Imbalance](https://apify.com/zinin/panama-canal-queue-transit-imbalance) | Compare Singapore demand pressure with aggregate canal-side transit imbalance. |
| [Live Price Oracle](https://apify.com/zinin/live-price-oracle) | Add current market-price context to a bunker-demand change. |
| [Counterparty Risk Rollup](https://apify.com/zinin/counterparty-risk-rollup) | Apply a separate buyer-owned risk review to downstream counterparties. |

Built by [zinin](https://apify.com/zinin).

# Actor input Schema

## `schemaVersion` (type: `string`):

Contract version for this Actor input.

## `requestId` (type: `string`):

Use auto for a Task-safe run identity.

## `watchId` (type: `string`):

Stable identity for the Singapore baseline.

## `sourceMode` (type: `string`):

Demo is synthetic; open uses data.gov.sg; open\_plus\_byok adds two bounded Datalastic provider requests: /stat plus Singapore. Prefill is demo because it is the only mode that reliably pushes a Dataset row on a console "Start" click without buyer configuration; open depends on a live data.gov.sg fetch clearing full-coverage gates and open\_plus\_byok additionally requires a paid key, so open remains the default for API buyers who already have working access.

## `datalasticApiKey` (type: `string`):

Only valid with sourceMode=open\_plus\_byok; runtime validation requires a printable 8-256 character secret, rejects it in demo/open, and never returns it.

## `baselineMonths` (type: `integer`):

Historical window used for 3-month and 12-month comparisons.

## `maxRows` (type: `integer`):

One bounded page per official source; 240 covers the observed 13-month window and up to 500 is allowed.

## `maxProviderRequests` (type: `integer`):

Exactly two requests are permitted for BYOK: /stat plus the Singapore zone.

## `maxTotalChargeUsd` (type: `number`):

Buyer cap checked before the paid result event.

## Actor input object example

```json
{
  "schemaVersion": "1.0",
  "requestId": "auto",
  "watchId": "singapore-bunker-main",
  "sourceMode": "demo",
  "baselineMonths": 12,
  "maxRows": 240,
  "maxProviderRequests": 2,
  "maxTotalChargeUsd": 0.055
}
```

# Actor output Schema

## `OUTPUT` (type: `string`):

API link to the authoritative terminal envelope.

## `REPORTS` (type: `string`):

API link to confirmed aggregate reports.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "schemaVersion": "1.0",
    "requestId": "auto",
    "watchId": "singapore-bunker-main",
    "sourceMode": "demo",
    "baselineMonths": 12,
    "maxRows": 240,
    "maxProviderRequests": 2,
    "maxTotalChargeUsd": 0.055
};

// Run the Actor and wait for it to finish
const run = await client.actor("zinin/singapore-bunker-tanker-divergence").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "schemaVersion": "1.0",
    "requestId": "auto",
    "watchId": "singapore-bunker-main",
    "sourceMode": "demo",
    "baselineMonths": 12,
    "maxRows": 240,
    "maxProviderRequests": 2,
    "maxTotalChargeUsd": 0.055,
}

# Run the Actor and wait for it to finish
run = client.actor("zinin/singapore-bunker-tanker-divergence").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "schemaVersion": "1.0",
  "requestId": "auto",
  "watchId": "singapore-bunker-main",
  "sourceMode": "demo",
  "baselineMonths": 12,
  "maxRows": 240,
  "maxProviderRequests": 2,
  "maxTotalChargeUsd": 0.055
}' |
apify call zinin/singapore-bunker-tanker-divergence --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,zinin/singapore-bunker-tanker-divergence"
        }
    }
}

```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/28muZB8TDsfMjgakV/builds/5krNuzaQwnFJpdKri/openapi.json
