curl --request GET \
--url https://api.worldmonitor.app/api/trade/v1/get-trade-flows \
--header 'X-WorldMonitor-Key: <api-key>'import requests
url = "https://api.worldmonitor.app/api/trade/v1/get-trade-flows"
headers = {"X-WorldMonitor-Key": "<api-key>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {'X-WorldMonitor-Key': '<api-key>'}};
fetch('https://api.worldmonitor.app/api/trade/v1/get-trade-flows', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.worldmonitor.app/api/trade/v1/get-trade-flows",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"X-WorldMonitor-Key: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.worldmonitor.app/api/trade/v1/get-trade-flows"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("X-WorldMonitor-Key", "<api-key>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://api.worldmonitor.app/api/trade/v1/get-trade-flows")
.header("X-WorldMonitor-Key", "<api-key>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.worldmonitor.app/api/trade/v1/get-trade-flows")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["X-WorldMonitor-Key"] = '<api-key>'
response = http.request(request)
puts response.read_body{
"coverageEndYear": 1,
"coverageStartYear": 1,
"fetchedAt": "2026-01-15T12:00:00Z",
"flows": [
{
"exportValueUsd": 1.5,
"importValueUsd": 1.5,
"partnerCountry": "000",
"productSector": "Total merchandise",
"reportingCountry": "840"
}
],
"upstreamUnavailable": false
}{
"violations": [
{
"field": "<string>",
"description": "<string>"
}
]
}{
"error": "<string>"
}{
"error": "<string>",
"code": "subscription_lapsed",
"requiredTier": 123,
"currentTier": 123,
"planKey": "<string>"
}{
"message": "<string>"
}{
"error": "<string>",
"code": "renewal_verification_pending",
"requiredTier": 123
}{
"message": "<string>"
}GetTradeFlows
Get bilateral merchandise trade flows.
curl --request GET \
--url https://api.worldmonitor.app/api/trade/v1/get-trade-flows \
--header 'X-WorldMonitor-Key: <api-key>'import requests
url = "https://api.worldmonitor.app/api/trade/v1/get-trade-flows"
headers = {"X-WorldMonitor-Key": "<api-key>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {'X-WorldMonitor-Key': '<api-key>'}};
fetch('https://api.worldmonitor.app/api/trade/v1/get-trade-flows', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.worldmonitor.app/api/trade/v1/get-trade-flows",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"X-WorldMonitor-Key: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.worldmonitor.app/api/trade/v1/get-trade-flows"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("X-WorldMonitor-Key", "<api-key>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://api.worldmonitor.app/api/trade/v1/get-trade-flows")
.header("X-WorldMonitor-Key", "<api-key>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.worldmonitor.app/api/trade/v1/get-trade-flows")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["X-WorldMonitor-Key"] = '<api-key>'
response = http.request(request)
puts response.read_body{
"coverageEndYear": 1,
"coverageStartYear": 1,
"fetchedAt": "2026-01-15T12:00:00Z",
"flows": [
{
"exportValueUsd": 1.5,
"importValueUsd": 1.5,
"partnerCountry": "000",
"productSector": "Total merchandise",
"reportingCountry": "840"
}
],
"upstreamUnavailable": false
}{
"violations": [
{
"field": "<string>",
"description": "<string>"
}
]
}{
"error": "<string>"
}{
"error": "<string>",
"code": "subscription_lapsed",
"requiredTier": 123,
"currentTier": 123,
"planKey": "<string>"
}{
"message": "<string>"
}{
"error": "<string>",
"code": "renewal_verification_pending",
"requiredTier": 123
}{
"message": "<string>"
}Authorizations
User-issued WorldMonitor API key.
Query Parameters
WTO member code of reporting country, as a 3-digit UN M49 code (for example "840" = United States). Empty selects the "840" default.
^([0-9]{3})?$WTO member code of partner country, as a 3-digit UN M49 code. Empty selects "000" = World, which is the only partner currently covered: the WTO indicators behind these flows (ITS_MTV_AX, ITS_MTV_AM) publish a World total and answer 204 for every named partner. Any other code is accepted by validation and answered with unavailable_reason TRADE_FLOW_UNAVAILABLE_REASON_NOT_COVERED, so coverage can widen without a contract change.
^([0-9]{3})?$Number of years to look back from the newest seeded year, inclusive of both endpoints (years = 10 returns 11 calendar years). 0 selects the default of 10; the maximum is 30, which is the full seeded window.
Optional JMESPath expression applied server-side to project or reduce the JSON response before it is returned (mirrors the MCP jmespath argument). Invalid expressions, expressions larger than 1024 UTF-8 bytes, or projections that exceed the 256 KB output cap return HTTP 400 with a {_jmespath_error, original_keys} envelope. Grammar and worked examples: https://www.worldmonitor.app/docs/mcp-jmespath.
Response
Successful response
Response containing trade flow records.
Show child attributes
Show child attributes
ISO 8601 timestamp when data was fetched from WTO.
True when flows could not be served because of a fault — a seeded pair whose cache entry is gone, or a cache read that failed. False when flows are served AND when the request names a combination that is simply not part of seeded coverage, which is a contract answer rather than an outage.
TradeFlowUnavailableReason says why no rows were returned. The distinction that matters is NOT_COVERED — a contract answer, nothing is broken and a retry cannot help — against every other member, which names a fault.
TRADE_FLOW_UNAVAILABLE_REASON_UNSPECIFIED, TRADE_FLOW_UNAVAILABLE_REASON_INVALID_REQUEST, TRADE_FLOW_UNAVAILABLE_REASON_NOT_COVERED, TRADE_FLOW_UNAVAILABLE_REASON_SEED_MISSING, TRADE_FLOW_UNAVAILABLE_REASON_COVERAGE_UNKNOWN, TRADE_FLOW_UNAVAILABLE_REASON_CACHE_UNAVAILABLE First and last calendar year covered by flows. Both are 0 when no flows
are returned. This is the effective window after slicing to years, which
may be narrower than the requested lookback when the seed starts later.
Was this page helpful?
