company_search_company
EXPERIMENTAL â Search company registries for a company with its officers and shareholders.
Find company registrations across worldwide registries, including
directors, officers, and beneficial owners (PSC/shareholders).
Every entity found is automatically screened against sanctions lists.
You MUST specify at least one jurisdiction. "ALL" is not supported.
Available jurisdictions: AM, AT, AU, BR, CA, CH, CZ, DE, DK, EE, FI,
FR, IE, IL, IS, LT, LV, NL, NO, PL, SG, UK, XX. Call
company_registries() for the live list â this one can go stale.
XX is GLEIF LEI, a GLOBAL registry rather than a country. Reach for it
whenever the company sits outside the national registries above â a
supplier in Hong Kong, mainland China, the US or the UAE. Hits carry an
LEI, a registered address and a search.gleif.org URL the user can open.
A jurisdiction NOT on that list is dropped silently by the backend: you
get total_results 0 with status "completed" and no error. That means the
company was never searched for â it is NOT evidence that it is
unregistered or fake, and saying so to someone checking a counterparty
before wiring money is the most damaging thing this tool can do. Check
`jurisdictions_not_searched` and `coverage_warning` in the response
before you report an empty result.
Args:
name: Company name to search for.
jurisdictions: Country codes to search (required, e.g. ["UK"]).
"ALL" is not supported â specify individual countries.
include_sanctions_check: Auto-screen results against sanctions DB (default: true).
include_officers: Include directors and officers (default: true).
include_shareholders: Include PSC/beneficial owners (default: true).
include_only_active: Filter to active companies only (default: false).
api_key: Your Ohmyfin API key (prod-...). Can also be passed
via KEY header or Authorization: Bearer header.
Examples:
company_search_company("Equinor", jurisdictions=["NO"])
company_search_company("Acme Corp", jurisdictions=["UK", "DE"], include_only_active=True)
Input schema
{'type': 'object', 'required': ['name', 'jurisdictions'], 'properties': {'name': {'type': 'string'}, 'api_key': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'jurisdictions': {'type': 'array', 'items': {'type': 'string'}}, 'include_officers': {'type': 'boolean', 'default': True}, 'include_only_active': {'type': 'boolean', 'default': False}, 'include_shareholders': {'type': 'boolean', 'default': True}, 'include_sanctions_check': {'type': 'boolean', 'default': True}}, 'additionalProperties': False}
Output schema
{'type': 'object', 'additionalProperties': True}
company_search_person
EXPERIMENTAL â Search company registries for a person's directorships, officer roles, and shareholdings.
Searches worldwide company registries to find where a person holds
director, officer, or shareholder positions. Every person and company
found is automatically screened against sanctions lists.
You MUST specify at least one jurisdiction. "ALL" is not supported.
Available jurisdictions: AM, AT, AU, BR, CA, CH, CZ, DE, DK, EE, FI,
FR, IE, IL, IS, LT, LV, NL, NO, PL, SG, UK, XX. Call
company_registries() for the live list â this one can go stale.
XX is GLEIF LEI, a GLOBAL registry rather than a country. Use it for
anyone connected to a company outside the national registries above.
A jurisdiction NOT on that list is dropped silently by the backend: you
get total_results 0 with status "completed" and no error. That means the
person was never searched for â it is NOT evidence they hold no roles.
Check `jurisdictions_not_searched` and `coverage_warning` in the response
before you report an empty result to the user.
Args:
name: Person name to search for.
jurisdictions: Country codes to search (required, e.g. ["UK", "NO"]).
"ALL" is not supported â specify individual countries.
include_sanctions_check: Auto-screen results against sanctions DB (default: true).
include_inactive_roles: Include resigned/ceased roles (default: true).
api_key: Your Ohmyfin API key (prod-...). Can also be passed
via KEY header or Authorization: Bearer header.
Examples:
company_search_person("John Smith", jurisdictions=["UK", "NO"])
company_search_person("Jane Doe", jurisdictions=["DE"])
Input schema
{'type': 'object', 'required': ['name', 'jurisdictions'], 'properties': {'name': {'type': 'string'}, 'api_key': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'jurisdictions': {'type': 'array', 'items': {'type': 'string'}}, 'include_inactive_roles': {'type': 'boolean', 'default': True}, 'include_sanctions_check': {'type': 'boolean', 'default': True}}, 'additionalProperties': False}
Output schema
{'type': 'object', 'additionalProperties': True}
export_controls_screen
Screen goods for export-control restrictions to a destination country.
Combines the goods classification with the destination's restriction status
and returns whether a license is required, the risk level, applicable
license policies (e.g. presumption of denial), control reasons (NS, MT, NP,
CB, AT), and proliferation/dual-use flags. Identify the goods by ANY of:
ECCN, HS code, or a free-text description (English or Russian).
IMPORTANT â jurisdiction nexus: each jurisdiction's controls only bind a
payment/shipment when there is a nexus to that jurisdiction (US EAR binds
US persons, USD-clearing, and US-origin items; EU/UK/JP bind their persons,
currencies, and origin). Use jurisdiction="ALL" for a comprehensive
multi-jurisdiction view, or pick the one matching the actual touchpoints.
IMPORTANT, prefer eccn or hs_code: goods_description is a fallback: the
classifier matches it lexically, so a vague description still returns one
specific HS code and it is usually the wrong one ("industrial machinery"
returns bakery and pasta machinery). When you pass a description only, the
result carries classification_basis and classification_confidence_note;
read them, never quote the inferred code back to the user as their HS code
or ECCN, and ask for the code on their invoice or export declaration. The
destination findings (embargo, transshipment risk, screening duties) are
NOT affected by that doubt, so report them normally.
Args:
destination_country: ISO 3166-1 alpha-2 destination code (e.g. "RU", "CN").
eccn: Optional Export Control Classification Number (e.g. "3A001").
hs_code: Optional Harmonized System code, 4-8 digits (e.g. "854231").
goods_description: Optional free-text goods description (EN or RU).
jurisdiction: "US" (default), "EU", "UK", "JP", "ITAR", or "ALL".
Provide at least one of eccn / hs_code / goods_description.
Examples:
export_controls_screen("RU", eccn="3A001") # electronics â Russia
export_controls_screen("CN", eccn="3A090") # advanced computing â China
export_controls_screen("IR", goods_description="industrial valves")
export_controls_screen("RU", goods_description="drone", jurisdiction="ALL")
export_controls_screen("DE", hs_code="854231") # â Germany (allied)
Use case: 'Can we ship integrated circuits to Russia?'
Input schema
{'type': 'object', 'required': ['destination_country'], 'properties': {'eccn': {'type': 'string', 'default': ''}, 'hs_code': {'type': 'string', 'default': ''}, 'jurisdiction': {'type': 'string', 'default': 'US'}, 'goods_description': {'type': 'string', 'default': ''}, 'destination_country': {'type': 'string'}}, 'additionalProperties': False}
Output schema
{'type': 'object', 'additionalProperties': True}
sanctions_screen
Screen a name against global sanctions and watchlists.
FREE TIER: 3 screens per day without an API key.
PAID: Unlimited screens with an API key.
Checks the name against 300+ sanctions, designation and watchlists
worldwide, including US OFAC (SDN and non-SDN), EU, UK OFSI, Canada,
Switzerland, Australia, New Zealand, Japan, Israel and national lists.
Returns matching entities with similarity scores. The response says how
many lists were actually searched (lists_searched); report THAT, and do not
present a fixed per-jurisdiction table of "clear" rows, which asserts a
per-list result the screen does not return and understates the coverage.
For a company or an individual the screen covers every list, including
adverse media, PEP and debarment registers. For a BANK or other financial
institution it returns sanctions DESIGNATIONS only: a warning-list entry
naming a bank is usually a clone-firm alert about fraudsters impersonating
it, and the feed carries nothing that tells the two apart.
When the name resolves in our bank directory, each designation is also
cross-referenced against that institution's record (country, entity type,
and the name or ALIAS that earned the fuzzy score) and contradicted rows are
removed. ALWAYS read the `verification` block, which is on every response:
`applied: false` means nothing was cross-referenced and the rows are raw
feed output â either the name is not in our bank directory, or the subject
is a company or individual, which has no directory record to check against.
Never report an `applied: false` result as verified, and never report an
empty one as verified-clear. Screening a bank by BIC, or calling
swift_lookup, gets a verified answer.
A row surviving that cross-reference is NOT the same as a row the
cross-reference supported. Each verified row carries `adjudication`:
`corroborated` means the check backed it and it is a designation against
this institution; `not_corroborated` means it survived the false-positive
floor but nothing tied it to this institution â typically
`country_conflict: true`, the designated entity being domiciled elsewhere.
`is_false_positive: false` is only that floor test and is never a finding;
read `adjudication` instead. When NOTHING is corroborated the response
carries `verification_gate.applied: true` and `recommended_action` has been
lowered from BLOCK to REVIEW: report a possible match needing identity
confirmation, do not reinstate BLOCK from the row-level `action` fields,
and do not report the institution as clear either â every row is still in
`matches` and the open question is which legal entity the counterparty is.
`verification_gate` is on every bank response whose verdict asserts a
finding (BLOCK, REVIEW, MONITOR or INFORM), and it asks one question: does
that verdict survive the evidence this payload actually publishes. A
REVIEW, MONITOR or INFORM over an EMPTY `matches` list is not a weaker
BLOCK. This screen publishes designations only for a financial institution,
so the rows that carried such a verdict are the non-designation ones
(warning lists, adverse media, PEP, debarment) it withholds â counted in
`non_designation_rows_withheld` and never listed. Those responses come back
`recommended_action: CLEAR` with `verification_gate.applied: true`, meaning
no DESIGNATION matched. Say exactly that, and keep the scope with it: it is
never a clean bill across every list. The gate stands down, and the verdict
stays, when our own verification removed a designation as a false positive
(`designations_filtered_as_false_positives`), when the directory record is
not clean, or when the row that set the verdict was off-page.
On an unverified response every row also carries `query_match`, listing
which of the screened words appear in that row's own name or aliases and
which do not. Nothing is removed on account of it. Weigh it against the
score: a row sharing one word out of four with the query is usually a
different entity, and its action is that entity's action, not a verdict on
the party screened. Absence is not proof â non-Latin aliases contribute no
words, and a transliterated designation of the right party can show words
missing â but where every query word is present, take the row at face value.
The response also carries `coverage_gate`, set by the screening engine: how
much of the name you screened actually appears on the rows that are
blocking. When `applied` is true the payload-level `recommended_action` was
lowered from BLOCK to REVIEW, because no blocking row carries more than
half of the distinctive words you screened. Report a possible match that
needs identity confirmation, NOT a designation, and do not reinstate BLOCK
from the row-level `action` fields. Nothing was removed: every row the feed
returned is still in `matches`, with its own score and action intact. When
`applied` is false the verdict stands and `reason` says why. A `reason` of
`identifier_query` means the name screened was a registration or tax
number that matched a designation's own identifier: that is a match on
identity, not on wording, so report the BLOCK as it stands.
Args:
name: The person or entity name to screen.
api_key: Your Ohmyfin API key (prod-...). Can also be passed
via KEY header or Authorization: Bearer header.
Optional â free tier allows 3 screens/day without a key.
threshold: Minimum match score 0-100 (default 85).
subject_type: What is being screened: "bank" for a financial
institution, "party" for a company or individual, or "auto"
(default). A name the bank directory resolves is treated as a
financial institution whatever you pass here.
Examples:
sanctions_screen("Acme Trading Ltd")
sanctions_screen("John Smith", threshold=90)
sanctions_screen("First Abu Dhabi Bank", subject_type="bank")
sanctions_screen("Acme Trading Ltd", api_key="prod-abc123...")
Input schema
{'type': 'object', 'required': ['name'], 'properties': {'name': {'type': 'string'}, 'api_key': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'threshold': {'type': 'integer', 'default': 85}, 'subject_type': {'type': 'string', 'default': 'auto'}}, 'additionalProperties': False}
Output schema
{'type': 'object', 'additionalProperties': True}
settlement_eta
BETA. Estimate when a SWIFT payment will arrive: a corpus-grounded
arrival window with an honest tail, computed from real completed payments
we have tracked, projected onto the currency's banking calendar.
This estimator is in BETA and still calibrating. Say so when you present a
number: call it an estimate or a typical window, never a commitment, and
never let a user plan an irreversible decision (a cutoff, a contractual
settlement date) on it without that caveat. The payload carries beta=true
while this holds.
Two modes:
- Forward (default): "when will it land" â returns P50/P90/P95 arrival
dates, sample size, confidence, competing non-arrival risk, delay-risk
factors, and (where validated) the most likely correspondent route.
- Reverse: pass arrive_by_date (YYYY-MM-DD) â returns the latest send
date such that arrival by that day is likely ("send by Thursday to
land by month-end").
INPUT DISCIPLINE (important):
- Mid-flight payment: pass ONLY the uetr (from TrackingContext or
track_payment). The server resolves the current status, currency and
elapsed time deterministically from the tracking record. NEVER compute
elapsed_business_days yourself.
- Pre-trade question ("how long will a USD wire from X to Y take?"):
pass currency + sender_bic/receiver_bic (8 or 11 chars, or bank names).
current_status / elapsed_business_days are for this path only.
Reading the answer honestly (relay these to the user):
- basis.n is the sample size and confidence reflects it; when confidence
is "low", present the window as a rough range, never a promise.
- route.confirmed=false means the route is INFERRED from settlement
instructions on file, not confirmed by GPI â say so.
- basis.route_adjusted=true means we hold no completed payments for this
exact pair and the window was lifted to a route-composed estimate:
the SSI-implied correspondent chain (route.intermediaries hops) with
typical processing time per hop. Present it as a route-based estimate,
not as observed statistics, and never quote the faster currency-pool
average alongside it as if corridor-specific.
- mode="outlier" means the payment is already slower than ~90% of similar
payments: stop quoting a window, explain the usual manual causes
(compliance review, repair/RFI, missing cover) and pivot to the
stuck-payment diagnostic flow.
- non_arrival.p_reject is the share of similar payments that were
returned or rejected rather than delivered.
- "Delivered" (ACCC) means delivered to the beneficiary bank per GPI;
funds can become usable in the account slightly later.
Available on every surface to any caller with an active subscription. The
estimate itself costs no credits (tracking a payment does cost credits;
never describe tracking as free).
Args:
uetr: UETR of a tracked payment (preferred for mid-flight questions)
currency: 3-letter currency (pre-trade path; ignored when uetr resolves)
sender_bic: Sender bank BIC or name (pre-trade path)
receiver_bic: Receiver bank BIC or name (pre-trade path)
intermediary_bic: Known intermediary BIC (optional)
current_status: GPI status like ACSP (pre-trade/no-uetr path only)
elapsed_business_days: Business days already in flight (pre-trade path only)
amount: Payment amount (improves delay-risk assessment). A plain
number is fine â 50000 and "50,000.00" are both accepted.
sender_country: ISO2 country of the sender bank (optional)
receiver_country: ISO2 country of the receiver bank (optional)
arrive_by_date: YYYY-MM-DD â switches to reverse send-by mode. You do
not know today's date; a deadline stated as "the 20th" or "by
month-end" must be resolved against the `today` block returned by
bank_holidays / value_date / is_business_day_check, not against
your own sense of the current date. A date in the past is rejected.
api_key: Optional API key (internal calls ride the MCP secret)
Input schema
{'type': 'object', 'properties': {'uetr': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'amount': {'anyOf': [{'type': 'number'}, {'type': 'string'}, {'type': 'null'}], 'default': None}, 'api_key': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'currency': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'sender_bic': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'receiver_bic': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'arrive_by_date': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'current_status': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'sender_country': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'intermediary_bic': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'receiver_country': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'elapsed_business_days': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}
Output schema
{'type': 'object', 'additionalProperties': True}
swift_lookup
Search banks and financial institutions by name, SWIFT/BIC code, or country.
Covers both SWIFT-connected banks and non-SWIFT financial institutions
(e-money issuers, payment processors, MFOs, brokerages, VASPs, etc.).
Returns: SWIFT/BIC code (if any), name, city, country, institution type,
GPI membership, a coarse sanctions FLAG across 7 hard-sanctions watchlists
(OFAC SDN, EU, UK, CA, CH, AU, NZ â see sanctions_note; this is NOT a full
screen, use sanctions_screen for a compliance verdict), and enriched bank
profile when available.
EVERY BANK COMES BACK SAYING WHETHER WE HOLD ITS CORRESPONDENT CHAIN.
Read `settlement_instructions` on each bank: `on_file: true` with a
`currencies_on_file` count means we hold that BIC8's actual correspondent
BIC, nostro account number and national clearing ID, and `read_with` is the
exact ssi_lookup call that returns them. `on_file: false` means we hold none
in any currency â a gap in our data, not a finding about the bank. A null is
"not established yet" and is neither. This is the answer to "which
intermediary bank do I put on the instruction?", and it is a fact we either
have or do not have â never one to recall from training data.
The country parameter accepts both 2-letter ISO codes ("ID", "DE") and
full English names ("Indonesia", "Germany"). Names are resolved
automatically.
A BIC IDENTIFIES AN OFFICE, NOT A BRAND, AND THE DIFFERENCE IS PRICED.
A name search returns ONE representative office per bank, elected by BIC
convention rather than by relevance to the payment, and `office_note` says
so whenever the bank holds more than one. Published tariffs, correspondent
chains and settlement instructions are filed per BIC, so the choice changes
the answer: transfer_cost("COBADEFF") returns Commerzbank's published 0.15%
sending fee and transfer_cost("COBADEBB") refuses for want of a filed
tariff, and both of those are Commerzbank AG in Germany. So:
- If the user named a CITY, put it in the query â "Commerzbank Frankfurt"
resolves to the Frankfurt office, and the plain name cannot.
- If they did not, ask which BIC is on their statement or payment
instruction before pricing or routing, and say which office you used.
- Never present a representative office's BIC as "the bank's BIC".
Examples:
swift_lookup("DEUTDEFF") # exact BIC lookup
swift_lookup("Deutsche Bank") # search by name
swift_lookup("Commerzbank Frankfurt") # bank + city -> that office's BIC
swift_lookup("TBC PAY") # find non-SWIFT payment processor
swift_lookup("bank", country="KZ") # explore banks in a country
swift_lookup("Halyk", country="KZ") # find specific bank in country
swift_lookup("Bank Mandiri", country="Indonesia") # full country name OK
Input schema
{'type': 'object', 'required': ['query'], 'properties': {'limit': {'type': 'integer', 'default': 20}, 'query': {'type': 'string'}, 'country': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}
Output schema
{'type': 'object', 'additionalProperties': True}
track_payment
Track a SWIFT payment by UETR or reference number.
Basic SWIFT payment tracking enriched by data from certain banks in
the correspondent chain. Returns the overall payment status and,
when available, per-bank details showing which banks reported
information about this payment.
IMPORTANT â every trace needs four things:
amount, currency, date, and an identifier (uetr, or reference when
there is no UETR). amount, currency and date are required
parameters, on the UETR path too: there is no UETR-only lookup, so
never tell the user the UETR alone is enough to run one. Ask for
whatever is missing before calling, and never guess a value.
IMPORTANT â UETR vs Reference:
The UETR (Unique End-to-End Transaction Reference) is a UUID
assigned to every SWIFT gpi payment. Tracking by UETR succeeds
~80% of the time. Tracking by reference number alone succeeds
less than 1% of the time because most banks only index by UETR.
â Always provide the UETR if available.
â The reference number is Field 20 of the MT103 (or the
equivalent <InstrId>/<EndToEndId> in pacs.008). It is the
sender's transaction reference. Still valuable â provide it
alongside the UETR when you have both.
WHEN THE USER HAS ONLY A REFERENCE AND NO UETR
("how do I find / trace my payment?", "I have a reference number
but no UETR, where is it?"):
This is exactly the scenario this tool can attempt â do NOT answer
from general knowledge. A reference-based trace cannot be run from
the reference alone; you MUST first collect three things from the user:
1. amount â the exact amount as sent
2. currency â ISO 4217 (e.g. "USD")
3. date â the send date (within the last 90 days)
Then call track_payment(reference=..., amount=..., currency=...,
date=...). State the expectation up front: reference-only tracing
succeeds less than 1% of the time.
In parallel, tell the user how to recover the UETR for a reliable
(~80%) trace: ask the SENDING bank for the MT103 confirmation â the
UETR is in Block 3, tag {121:} (a UUID v4), stored by every
gpi-enabled bank against the payment. Re-run with uetr= once they
have it. (swift_message_reference("MT103") returns the full
field/UETR-recovery reference if you need to cite specifics.)
IMPORTANT â Interpreting bank details:
Each entry in the 'details' array represents a bank that reported
data about this payment. The bank could be the SENDER, the
BENEFICIARY, or ANY INTERMEDIARY/CORRESPONDENT in the chain.
Do NOT assume a bank is an intermediary just because it appears
in the list â we only know the payment passed through that bank.
The bank's role is only known when it self-reports via push API
(indicated by a non-null 'role' field).
Requires an API key with an active FI subscription.
To get started: call mcp_register â mcp_verify â subscribe to
an FI plan at https://ohmyfin.ai/subscription.
Args:
uetr: UETR (UUID v4 format, e.g. "eb6305c8-0710-4e41-84ad-f58db3083e82").
Strongly recommended â tracking without UETR rarely returns results.
This is the Unique End-to-End Transaction Reference assigned to every
SWIFT gpi payment.
reference: Sender's bank reference number (MT103 Field 20 / pacs.008
InstrId). Useful alongside UETR for cross-referencing, but
alone it rarely produces results. Required only if uetr is
not provided.
amount: REQUIRED. Transaction amount as sent (e.g. 15000.00). Must match
the original payment amount â even small differences may prevent
tracking from finding the payment, so ask the user for the exact
figure rather than estimating or rounding one.
currency: REQUIRED. ISO 4217 code of the currency the payment was SENT
in (e.g. "USD", "EUR", "GBP"). Ask if you do not know it; do
not assume the sender's or the beneficiary's home currency.
date: REQUIRED. Transaction date. Preferred format: YYYY-MM-DD (ISO 8601).
Also accepted: DD.MM.YYYY or DD-MM-YYYY (European format).
Must be within the last 90 days.
api_key: Your Ohmyfin API key (prod-...). Can also be passed
via KEY header or Authorization: Bearer header.
Returns a dict with:
status: Overall payment status â one of:
"success" â payment delivered to beneficiary (final)
"in progress" â payment is being processed (may update)
"returned" â payment was canceled/returned after processing (final)
"rejected" â payment was refused (final)
"on hold" â temporarily held, e.g. compliance review
"future" â scheduled for a future value date
"unknown" â no tracking data available yet
status_raw: ISO 20022 status code (ACCC/ACSP/RJCT/PDNG) or null
status_reason: ISO 20022 reason code at PAYMENT level, or null. null
is common and does NOT mean no reason code was reported â
most feeds report the qualifier per bank instead, see below.
reason_codes_reported_by_banks: Present whenever any bank line reports
a "STATUS/REASON" qualifier (ACSP/G003, RJCT/MS03). Each entry
is decoded to its name and meaning. This is what answers "is
anything pending / held / rejected / flagged on my payment",
not status_reason.
lastupdate: Date of last status change (YYYY-MM-DD) or null
details: Array of bank-level tracking entries (see role_explanation
in each entry for how to interpret the bank's role)
not_found_guidance: Present only when nothing was found â concrete
next steps (UETR recovery, exact-match checks). Relay these
to the user instead of improvising; a miss on a
reference-only trace is the expected outcome and does NOT
mean the payment failed.
Examples:
track_payment(uetr="eb6305c8-0710-4e41-84ad-f58db3083e82",
amount=15000, currency="USD", date="2026-03-10")
track_payment(uetr="eb6305c8-0710-4e41-84ad-f58db3083e82",
reference="FT2603100123",
amount=15000, currency="USD", date="2026-03-10")
track_payment(reference="FT2603100123",
amount=5000, currency="EUR", date="12.03.2026")
Input schema
{'type': 'object', 'required': ['amount', 'currency', 'date'], 'properties': {'date': {'type': 'string'}, 'uetr': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'amount': {'type': 'number'}, 'api_key': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'currency': {'type': 'string'}, 'reference': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}
Output schema
{'type': 'object', 'additionalProperties': True}
transfer_cost
BETA. Estimate what a cross-border payment will COST, split by WHO
PAYS: the sending bank's published fee (the sender's side), what
correspondents deduct in transit and what the beneficiary's own bank
charges to credit it (the beneficiary's side), and what actually lands.
This estimator is in BETA. Present every number as a typical case and a
high case, never as a quote, and never let a user commit to a contractual
amount on it. The payload carries beta=true while this holds.
HOW TO READ THE ANSWER (relay these honestly):
- `answered=false` means we REFUSED. The most common reason is that we
hold no published tariff rule for the sending bank, in which case there
is deliberately no total and no "recipient receives" figure. Say we do
not know what that bank charges. Do NOT add up the parts yourself and
present a total: treating the unknown fee as zero is the exact defect
this tool was built to remove.
- The correspondent fee is a RANGE (`p50` typical, `p90` high case), not a
point. The spread is real: SWIFT tracking never reveals whether a
payment was sent OUR, SHA or BEN, so a single cohort mixes all three.
- THREE FEES, THREE DIFFERENT PAYERS, AND THEY ARE NOT INTERCHANGEABLE.
`sending_fee` is billed to the SENDER by their own bank.
`correspondent_fee` comes out of the payment in transit, so the
BENEFICIARY bears it. `beneficiary_fee` is what the RECEIVING bank
charges its own customer to credit the payment, so the beneficiary bears
that too - and it is frequently the largest of the three (measured
2026-08-22 on one live corridor: 35.26 USD of sender-side cost against a
245.68 USD beneficiary bank fee). Never quote one of them as "the cost",
and never call the beneficiary bank's fee a correspondent charge.
`total` is the sending fee plus the transit deduction; `total_both_sides`
adds the beneficiary bank's fee and is the all-in figure.
- WHERE EACH NUMBER COMES FROM. The correspondent fee is OBSERVED, from
payments we have tracked. `beneficiary_fee.source` is `tariff` (or
`tariff_fallback`, see below) and never `observed`: a beneficiary bank
deducts after the last bank that reports to GPI, so no tracking data can
see it, and we read it off that bank's published incoming tariff
instead. Say which is which when the user leans on a figure.
- `beneficiary_fee.known=false` means WE HOLD NO INCOMING TARIFF for that
bank (we hold one for roughly two thirds of beneficiary banks). Its
charge is then missing from every figure, `total_both_sides` is null,
and `recipient_receives.typical` is an UPPER BOUND -
`recipient_receives.beneficiary_fee_known` says so. Do not fill that gap
with a zero, a guess or a typical figure; say the receiving bank's own
charge is not included and point the user at that bank's tariff.
- `beneficiary_fee.applies=false` under OUR / OUR-OUR: the instruction says
the sender covers every downstream charge, so the bank claims it back
rather than taking it off the credit. The figure is reported but NOT
subtracted. Our data ends before the account is credited, so we can
neither confirm nor refute that it was honoured on a given payment.
- `beneficiary_fee.segment` says which of the bank's incoming price lists
was read. `segment_fallback=true` means the account type asked for had
no usable schedule so the other one answered - which can only happen
when `beneficiary_segment` was NOT supplied, i.e. when we were assuming
the beneficiary matches the sender. Say that you assumed it.
- `beneficiary_fee.reason='other_segment_only'` means you DID supply
`beneficiary_segment`, and that bank publishes an incoming tariff for
the other account type only (`beneficiary_fee.other_segment` names it).
We decline to quote it. Do NOT report this as "we hold no tariff for
that bank": we hold one, for a different kind of account. Tell the user
which, because it is often the useful half of the answer.
- `basis.n` is how many observed payments back the correspondent figure and
`confidence` reflects it. At "low", present the range as rough.
- `basis.level` says how specific the evidence is: `corridor` is this
correspondent into this destination country, `correspondent` is that
bank overall, and `currency` or `global` mean we hold nothing specific
and are quoting a pool. Say so when it is a pool.
- ON A REFUSAL `basis` IS NULL, and the same two figures are still on each
entry of `correspondent_fee.legs[]` as `level` and `n`. Read them there.
Do not read a missing `basis` as corridor-specific evidence: on a
measured DE->AM screen the legs said `level: "currency", n: 146`, a
currency-wide pool, and the answer described it as a single well-priced
hop because the top-level key was absent.
- `assumptions` is a list of plain sentences explaining what shaped the
number (SEPA, OUR honoured, PSD2, a modelled BEN uplift, a stale
tariff). Relay the ones that matter to the user's question.
- under OUR the correspondent leg carries `our_breach`: the measured share
of OUR payments that lose a charge in transit anyway, and what that
costs. p50 is 0 and p90 is that loss. Quote BOTH - "the beneficiary
should receive the full amount, and in about 7% of the OUR payments we
can follow end to end they do not" - never the p50 alone as a promise.
- `chain.status` = `no_chain` means the pair settles on local rails (SEPA,
domestic, same banking group) with NO correspondent deduction at all.
IMPORTANT ON CHARGE TYPE: charge_type is an INPUT and is never inferred
from tracking. OUR is a real instruction and usually holds - of 150
payments whose own MT103 declared OUR and which we could follow from the
instructed amount to the settled one, 139 reached the beneficiary intact,
against 6 of 52 under SHA. It is NOT a guarantee: the other 11 lost a flat
correspondent charge in transit, and we find no evidence that this depends
on the destination country or on a US correspondent being in the chain, so
do not tell a user that OUR is safe everywhere except the US. BEN is
materially more expensive than SHA and our high case models it rather than
measuring it. If the user has not said which they will use, ask, or state
which one you assumed.
Pass `beneficiary_bic` whenever the user knows the receiving bank: without
it there is no correspondent chain to price and no beneficiary bank to
read a tariff from, so the answer is the sending fee alone and no total.
`customer_segment` selects which side of the SENDING bank's published price
list is read. It is not cosmetic: of 30 banks publishing both schedules, 9
of the 17 that answered on both quote a different fee, one of them 220 PLN
for a company against free for a person. It defaults to `individual` here;
pass `business` when the payer is a company, and say which you assumed.
`beneficiary_segment` does the same for the RECEIVING side, which is a
different bank's price list and not a restatement of the sender's. Of 120
banks publishing both schedules, 28 quote a different incoming fee
(measured 2026-08-24), and it runs both ways: Hipotekarna banka (HBBAMEPG)
credits a 100,000 EUR payment free of charge to a company and takes 0.1%
of it from a person, while Nordea charges a person 60 SEK and a company
250. Omit it and we assume the beneficiary matches the sender, which is
what this tool did before 2026-08-24 - so if you omit it, say you assumed
it. Supply it when the user has told you who is being paid, and prefer
asking over guessing when the amount makes the difference material.
Available to any caller with an active subscription. The estimate itself
costs no credits (tracking a payment does cost credits; never describe
tracking as free).
Args:
bank_swift: Sending bank BIC (8 or 11 chars)
amount: Transfer amount
currency: 3-letter transfer currency
charge_type: SHA (default), OUR or BEN. Ask the user rather than guessing
beneficiary_bic: Receiving bank BIC; needed for a total
channel: online | branch | mobile_app | any
customer_segment: individual | business | financial_institution - the SENDER
beneficiary_segment: individual | business | financial_institution - the
party being PAID. Omitted, it mirrors customer_segment
customer_sub_segment: standard | premium | private_banking | vip
api_key: Optional API key (internal calls ride the MCP secret)
Input schema
{'type': 'object', 'required': ['bank_swift', 'amount', 'currency'], 'properties': {'amount': {'type': 'number'}, 'api_key': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'channel': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'currency': {'type': 'string'}, 'bank_swift': {'type': 'string'}, 'charge_type': {'type': 'string', 'default': 'SHA'}, 'beneficiary_bic': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'customer_segment': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'beneficiary_segment': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'customer_sub_segment': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}
Output schema
{'type': 'object', 'additionalProperties': True}
Changed
tracking_history
Sept. 25, 2026, 3 a.m.
Changed
track_payment
Sept. 21, 2026, 2:58 a.m.
Added
company_registries
Sept. 17, 2026, 7:57 a.m.
Added
company_search_result
Sept. 17, 2026, 7:57 a.m.
Added
company_search_company
Sept. 17, 2026, 7:57 a.m.
Added
company_search_person
Sept. 17, 2026, 7:57 a.m.
Added
banks_using_correspondent
Sept. 17, 2026, 7:57 a.m.
Added
ssi_lookup
Sept. 17, 2026, 7:57 a.m.
Added
tracking_history
Sept. 17, 2026, 7:57 a.m.
Added
track_payment
Sept. 17, 2026, 7:57 a.m.
Added
federal_register_changes
Sept. 17, 2026, 7:57 a.m.
Added
goods_classify
Sept. 17, 2026, 7:57 a.m.
Added
hs_code_lookup
Sept. 17, 2026, 7:57 a.m.
Added
export_controls_screen
Sept. 17, 2026, 7:57 a.m.
Added
country_export_controls
Sept. 17, 2026, 7:57 a.m.
Added
eccn_lookup
Sept. 17, 2026, 7:57 a.m.
Added
sanctions_screen
Sept. 17, 2026, 7:57 a.m.
Added
mcp_verify
Sept. 17, 2026, 7:57 a.m.
Added
mcp_register
Sept. 17, 2026, 7:57 a.m.
Added
transfer_cost
Sept. 17, 2026, 7:57 a.m.
Added
settlement_eta
Sept. 17, 2026, 7:57 a.m.
Added
value_date
Sept. 17, 2026, 7:57 a.m.
Added
is_business_day_check
Sept. 17, 2026, 7:57 a.m.
Added
bank_holidays
Sept. 17, 2026, 7:57 a.m.
Added
payment_method_compare
Sept. 17, 2026, 7:57 a.m.
Added
fx_timing_advisor
Sept. 17, 2026, 7:57 a.m.
Added
fx_volatility
Sept. 17, 2026, 7:57 a.m.
Added
payment_cutoff_times
Sept. 17, 2026, 7:57 a.m.
Added
swift_message_reference
Sept. 17, 2026, 7:57 a.m.
Added
gpi_status_codes
Sept. 17, 2026, 7:57 a.m.