Recipe 05 — LC discrepancy detection in a trade-finance workflow
20 minutes. Result: a single call validates a letter of credit + commercial invoice + bill of lading against UCP 600 + cross-document consistency and returns every discrepancy with the offending rule citation.
What this recipe does
Before a bank pays out on a letter of credit, every supporting document is examined for discrepancies. OilFlow's /api/v1/lc/validate runs the UCP 600 rule engine plus cross-document amount, currency, port, and date checks in one call.
Step 1 — Gather the three documents
You'll be sending structured JSON, not the source PDFs. Extract whatever fields you have:
lc = {
"amount": 1_000_000,
"currency": "USD",
"beneficiary": "Acme Trading FZE",
"port_of_loading": "Fujairah",
"expiry_date": "2026-07-15",
}
invoice = {
"total_amount": 1_000_000,
"currency": "USD",
"seller_name": "Acme Trading FZE",
"presentation_date": "2026-06-15",
}
bl = {
"currency": "USD",
"port_of_loading": "Fujairah",
"issue_date": "2026-06-01",
"shipped_on_board": True,
}(If your input is PDFs, run them through your existing OCR + extraction layer first.)
Step 2 — Validate
from oilflow import Client
client = Client()
report = client.lc.validate(lc=lc, invoice=invoice, bl=bl)
print(f"report_id: {report['report_id']}")
print(f"discrepancies: {len(report['discrepancies'])}")Node
import OilFlow from "@oilflow/sdk";
const client = new OilFlow();
const report = await client.lc.validate({ lc, invoice, bl });Step 3 — Branch on severity
blocking = [d for d in report["discrepancies"] if d["severity"] == "blocking"]
major = [d for d in report["discrepancies"] if d["severity"] == "major"]
minor = [d for d in report["discrepancies"] if d["severity"] == "minor"]
if blocking:
print(f"REJECT: {len(blocking)} blocking discrepancies")
for d in blocking:
print(f" - {d['rule']}: {d['detail']}")
elif major:
print(f"REVIEW: {len(major)} major discrepancies (human review required)")
for d in major:
print(f" - {d['rule']}: {d['detail']}")
else:
print(f"OK: {len(minor)} minor notes only")Severity meanings:
- blocking — must reject the presentation (UCP 600 hard stop).
- major — needs your reviewer's eyes. The LC officer decides whether to waive or reject.
- minor — cosmetic; flagged for the audit trail.
Step 4 — Pull the PDF report for your audit pack
fetched = client.lc.report(report["report_id"])
print(fetched["download_url"]) # signed URL, 10-minute TTLThe PDF is suitable for inclusion in the bank's audit pack. Discrepancies are listed with rule citations.
Step 5 — Full LC officer workflow
def review_presentation(lc, invoice, bl):
report = client.lc.validate(lc=lc, invoice=invoice, bl=bl)
blocking = [d for d in report["discrepancies"] if d["severity"] == "blocking"]
if blocking:
return {
"decision": "reject",
"discrepancies": blocking,
"report_url": client.lc.report(report["report_id"])["download_url"],
}
major = [d for d in report["discrepancies"] if d["severity"] == "major"]
if major:
return {
"decision": "human_review",
"discrepancies": major,
"report_url": client.lc.report(report["report_id"])["download_url"],
}
return {"decision": "approve", "discrepancies": [], "report_url": None}UCP 600 articles covered
The rule engine covers (non-exhaustive):
- Art. 14(a) — Standard for examination of documents
- Art. 14(d) — Data consistency across documents
- Art. 14(e) — Description of goods
- Art. 18 — Commercial invoice
- Art. 19 — Transport documents
- Art. 20 — Bill of lading
- Art. 23 — Sea waybill
- Art. 28 — Insurance documents
Each discrepancy returned cites the article number in rule.
Common gotchas
- Date formats: pass ISO 8601 (
YYYY-MM-DD). Other formats are parsed best-effort but may silently drop info. - Currency mismatch: a USD LC against a EUR invoice surfaces as
blockingeven with otherwise matching amounts. - Partial shipments: the engine assumes a single shipment unless the LC permits partial shipments (you'd indicate this in your LC structured input — see the OpenAPI spec for the full field list).
Next steps
- Recipe 01: Pipe results into Slack so the LC officer is alerted automatically.
- See the OpenAPI spec for the complete LC validation schema.