Skip to main content

Fetching an MLS: the three legs

Fetching an MLS document​

There are two calls, and which one you need depends on who wrote the MLS you want. Get this the wrong way round and you will be told there is no answer when there is one, so the rule comes first:

The MLS you wantWho wrote itThe call to use
The one GoRoute sent as C3, acknowledging a document that arrived for youGoRoute, on your behalfGET /api/v1/transactions/{transaction_id}/mls?leg=sent
The buyer's accept or reject of an invoice you sentThe buyer's access point (C2)GET /api/v1/oman/transactions/{transaction_id}/mls?leg=received
The Oman Tax Authority's answer on your invoice's Tax Data DocumentThe Tax Authority (C5)GET /api/v1/oman/transactions/{transaction_id}/mls?leg=authority
The core call cannot return the buyer's or the Authority's answer

GET /api/v1/transactions/{transaction_id}/mls?leg=received looks the MLS up inside your own organisation. Both of the answers that come back to you — the buyer's and the Tax Authority's — are addressed to GoRoute's own service-provider identity rather than to yours, so they are filed under GoRoute's organisation and that lookup finds nothing. The call answers 404 DOCUMENT_NOT_STORED, and it does so whether or not the buyer has answered.

A 404 from that call is therefore not evidence that nobody has answered. If you have been treating it that way, you may have missed rejections. Use the Oman call below for the received and authority legs. leg=sent on the core call is unaffected and still correct.

The core call — the MLS GoRoute sent​

GET /api/v1/transactions/{transaction_id}/mls?leg=sent

Returns the MLS as unaltered UBL ApplicationResponse XML, with content type application/xml. Nothing is reformatted or re-serialised. Permission: transactions:read.

ParameterValuesBehaviour
legsentThe ApplicationResponse GoRoute issued as C3 to the sending access point (C2). This is the leg this call is for.
legreceivedAccepted by the call, but see the warning above: for an Omani invoice it answers 404 DOCUMENT_NOT_STORED. Use the Oman call instead.
legomittedThe sent leg if one exists, otherwise it falls back to the received leg — and so to the same 404. Name the leg rather than omitting it.

Errors

Statuserror_codeWhen
404TRANSACTION_NOT_FOUNDNo such transaction in your organisation.
404MLS_NOT_AVAILABLEThe transaction exists but no MLS leg of the kind you asked for has been recorded on it at all.
404DOCUMENT_NOT_STOREDThe leg is recorded on the transaction but the call cannot read it. For leg=received on an Omani invoice this is the normal answer, for the reason in the warning above — not a sign of missing storage.

The Oman call — the buyer's answer and the Tax Authority's​

GET /api/v1/oman/transactions/{transaction_id}/mls?leg=received

This reads the MLS across organisations, after proving that the document it returns really does answer the invoice you named. Details:

PointDetail
legRequired. received — the buyer's access point's MLS on your invoice. authority — the Tax Authority's MLS on your invoice's Tax Data Document. There is no default and no sent value here.
Permissiontransactions:read, the same as the core call.
Response200 with the stored UBL ApplicationResponse, unaltered, as application/xml.
TransactionYour own invoice, read in your own organisation. A transaction belonging to someone else is a 404, not a 403.

Errors

Statuserror_codeWhen
404TRANSACTION_NOT_FOUNDNo such transaction in your organisation.
404MLS_NOT_AVAILABLENo MLS of that leg has been received yet. This is also the answer if the stored MLS turns out not to answer the invoice you named, so that a mismatch can never leak another document.
404DOCUMENT_NOT_STOREDThe MLS was received but its XML is not retrievable from storage.

The authority leg is new capability rather than a replacement: the core call has no selector for the Tax Authority's MLS at all, so before this call existed there was no way to download it.

This call exists only where the Oman pack is switched on

It is part of the Oman country pack, and a pack is mounted only on a service configured to run it. It is live on the test service; it is not mounted on app.goroute.ai today, even though that service runs the same build. You can tell the two apart in one request, with no API key and any transaction id:

  • 401 — the route exists and is asking you to authenticate. It is available.
  • 404 — the route is not mounted on that service.

Compare it against /api/v1/transactions/{id}/mls, which answers 401 everywhere: if the Oman path gives 404 while the core path gives 401, the pack is off rather than your request being wrong.

Fetching both, in order​

Ask the reporting endpoint which legs exist, then fetch each from the call that can return it. Note that mls.legs[] publishes a document_url for the received leg that points at the core call — the address that cannot serve it. Build the address from the request lines above rather than from that field.

import requests

status = requests.get(
f"{BASE_URL}/api/v1/transactions/{transaction_id}/reporting",
headers={"X-API-Key": API_KEY},
).json()

print(status["clearance_status"], status["ota_target"])
if status["note"]:
print(status["note"])

legs = {leg["leg"] for leg in status["mls"]["legs"]}

# The MLS we sent: the core call.
if "sent" in legs:
sent_xml = requests.get(
f"{BASE_URL}/api/v1/transactions/{transaction_id}/mls",
params={"leg": "sent"},
headers={"X-API-Key": API_KEY},
).text

# The buyer's answer: the Oman call. The core call answers 404 for this leg.
if "received" in legs:
received_xml = requests.get(
f"{BASE_URL}/api/v1/oman/transactions/{transaction_id}/mls",
params={"leg": "received"},
headers={"X-API-Key": API_KEY},
).text

# The Tax Authority's answer on the TDD. It is not listed in mls.legs[];
# tdd.authority_response tells you whether it has arrived.
if status["tdd"]["authority_response"]:
authority_xml = requests.get(
f"{BASE_URL}/api/v1/oman/transactions/{transaction_id}/mls",
params={"leg": "authority"},
headers={"X-API-Key": API_KEY},
).text

If you would rather not poll at all, the buyer's status message also reaches the invoice's owner as a webhook event — see Status events for invoices you sent.