{{ liveMsg }}
Your account has no role yet — ask an administrator for access. You're signed in, but you won't see or be able to do anything here until a role is granted.
Booking needs {{ rolePhrase('shipment.book') }}. You can still open and work existing shipments.
{{ error }}
Booked {{ lastBooked.reference }} — draft
Lane: {{ (lastBooked.lane.origin && (lastBooked.lane.origin.resolved || lastBooked.lane.origin.typed)) || "?" }} → {{ (lastBooked.lane.destination && (lastBooked.lane.destination.resolved || lastBooked.lane.destination.typed)) || "?" }}
{{ ep.reason }} {{ ep.fix }}
{{ lastBooked.creditSignal.party }} is within its credit limit. {{ lastBooked.creditSignal.reason }} Within limit only on the AR we could value — some of this party's AR couldn't be converted, so the true exposure may be higher. Not a firm clear. Credit HELD — {{ lastBooked.creditSignal.party }}: {{ lastBooked.creditSignal.reason }} Cash-in-advance — collect prepayment; no credit extended. No credit limit is set for {{ lastBooked.creditSignal.party || 'this party' }} — nothing was compared. The booking is accepted, but releasing it (document, departure, delivery) is blocked until a credit limit is set or an authorized credit override releases it. Credit not confirmed.
{{ openedReport.report.label }}
— {{ openedReport.report.excludes }}
Window: {{ openedReport.window.label }}
Loading the figure…
{{ openedReport.error }}
{{ t.label }} — {{ t.count }} row(s){{ t.truncated ? ' (showing first ' + t.rows.length + ')' : '' }}
{{ c }}
{{ cell }}
none
No figures returned for this period.

What needs me

Nothing needs you right now.
{{ taskSelectedIds.length }} selected
{{ taskBulkResult.done }} resolved · {{ taskBulkResult.refused }} refused
{{ r.ref }} — {{ r.ok ? '✓ ' : '✕ ' }}{{ r.msg }}
No open exceptions.
⛔ Denied-party / sanctions match — human decision required
⚠ Credit hold — release decision required
⚠ Dangerous goods — carrier acceptance not recorded
{{ t.type }}
Cancelled · {{ t.shipper }} · {{ t.origin }} → {{ t.destination }}
{{ t.detail }}
{{ reasonLabel(t.reason) }} · {{ taskAge(t.createdAt) }} old
{{ chOf(t.id).error }}
At raise · {{ fmtWhen(chOf(t.id).evidence.raisedAt) }}
No stored snapshot (raised before evidence capture).
Loading…
Now · live
Live exposure needs analytics access.
No current exposure line for this customer.
Loading…
Receivable cover: · limit source: {{ chOf(t.id).live.creditLimitSource }} · limit source: no source on record
{{ chOf(t.id).msg }}
Releasing needs a credit-override request; you don't have permission to raise one.
{{ p.direction }} · prepared by {{ p.preparedByAgentId ? ('agent ' + p.preparedByAgentId) : ('user ' + (p.preparedBy || '').slice(0, 8)) }} {{ p.status }}
Bill to {{ p.billTo }}
Amount: mixed currency — see the lines below (not summed) no sell charges yet
Reference {{ p.reference }}
{{ l.chargeCode }} {{ l.currency }} {{ l.amount.toFixed(2) }}
{{ r.kind === 'WriteOff' ? 'Write-off' : 'Credit note' }} · prepared by {{ (r.preparedBy || '').slice(0, 8) }} {{ r.status }}
Prepared — awaiting a second approver; nothing is reversed yet.
Amount: unavailable — the invoice currency couldn't be resolved; open the invoice's shipment (the shipment button on this row, when shown) to check it
Invoice {{ r.invoiceNumber || (r.invoiceId || '').slice(0, 8) }}
Reason: {{ r.reason }}
awaiting an invoice approver
Credit override requested · by {{ ov.requestedBy === (me && me.userId) ? 'you' : 'a colleague' }} {{ fmtWhen(ov.requestedAt) }}
Reason given: {{ ov.reason }}
· no credit-hold task is open for it, so there is no hold card; the release gate still blocks it until this is decided.
You requested this override — a different approver must decide it (segregation of duties).
awaiting a holder of credit.override.approve
{{ orphanOverrideMsg[ov.id] }}
{{ a.proposedAction }}· {{ a.actorId }} {{ a.reversible ? 'reversible' : 'irreversible' }}
Confidence: {{ Math.round(a.confidence * 100) }}%
· {{ a.grounding.chargeCount }} charge(s)
FieldBeforeAfter
{{ d.field }}{{ d.before }}{{ d.after }}
{{ a.commitPermission ? ('Approving this needs ' + rolePhrase(a.commitPermission) + '.') : 'No permission is mapped to approve this action, so it cannot be approved here.' }}
Loading explanation…
Couldn't load the explanation — try again.

Shipments

⛔ {{ triageCounts.sanctioned }} sanctions {{ triageCounts.needReview }} need review {{ triageCounts.active }} active {{ triageCounts.drafts }} drafts
{{ selectedIds.length }} selected
{{ bulkResult.done }} advanced · {{ bulkResult.refused }} refused
{{ r.ref }} — {{ r.ok ? '✓ ' : '✕ ' }}{{ r.msg }}
{{ refusalSentence('shipment.read', 'shipments') }}
No shipments yet — book one above.

{{ detail.reference }}

{{ detail.status }} {{ detail.shipper }} · {{ detail.origin }} → {{ detail.destination }}
Where this booking came from
{{ capturedSource.explanation }}
On the shipment now
Shipper:
{{ detail.shipper || '-' }}
Consignee:
{{ detail.consignee || '-' }}
Route:
{{ detail.origin || '-' }} → {{ detail.destination || '-' }}
Mode:
{{ detail.mode || '-' }} {{ detail.direction || '' }}
Incoterm / freight:
{{ detail.incoterm || '-' }} / {{ detail.paymentTerm || '-' }}
Cargo:
{{ cargo ? (cargo.cargo || []).length + ' line(s), ' + (cargo.containers || []).length + ' container(s)' : '-' }}
These are the current values (they may have been corrected since capture); compare them with the text.
Party onboarded — re-grounding this draft… Party onboarded and this draft re-grounded — it no longer waits on that party. ({{ relinkStatus.relinked }} draft(s) relinked.) Party onboarded and re-grounded — a screening hit was raised, so this is awaiting compliance review.
These figures may be out of date after that change.
{{ blockers.length }} thing{{ blockers.length === 1 ? '' : 's' }} blocking this shipment - {{ blockerCounts.yours }} you can fix yourself · {{ blockerCounts.others }} need someone else
✓ {{ r.text }}
  • {{ b.fix }}
    • {{ c.legalName }} - {{ c.city }}, customer, added {{ String(c.createdAt).slice(0, 10) }}, id {{ String(c.id).slice(0, 8) }}
    If it is the same party, do nothing - the hold stays. If it is a different one, say why and clear it:
    A charge you add by hand also clears this.
    Credit is checked once the {{ b.credit.role }} is linked to a company - nothing to decide until then.
    {{ blockerUnreachableNote(b.action.kind) }} Needs {{ rolePhrase(b.action.permission) }}.
No blockers — this shipment is ready to operate.
✓ {{ r.text }}
Heads-up
{{ a.summary }}.
{{ a.fix }}
Recording an exchange rate needs {{ rolePhrase('fx.rate.manage') }}.
Couldn't load the carrier acceptance of this shipment's dangerous goods. That is a failed read — it does not mean nothing is declared or that anything is accepted.
{{ (dgAcceptance.statement || 'No dangerous goods declared on this shipment').replace(/^./, c => c.toUpperCase()) }}.
Dangerous goods — carrier acceptance
{{ door.label }}: {{ dgClaimLabel(door.v) }}
  • {{ f.subject }} · {{ f.cargo }} — {{ f.reason }} · as of {{ f.basis.asOf }} · {{ f.basis.source }} · recorded by the booking agent (automated)
Not assessed: {{ n }}
Answer age: {{ dgAcceptance.ageLimit }}.
{{ dgAcceptance.answers.length }} recorded answer{{ dgAcceptance.answers.length === 1 ? '' : 's' }} for this cargo
  • {{ a.status }} · {{ a.key }} ({{ a.grain === 'UnNumber' ? 'substance' : 'class' }}) · {{ a.mode }} · as of {{ a.asOf }} · {{ a.source }} · recorded by the booking agent (automated) · a person confirmed the agent-relayed answer
Record a carrier's answer
The declaration has no valid UN number or class, so there is nothing to record an answer against yet.
Recording a carrier's answer needs shipment.edit.
{{ detail.groundingReason }}
Onboarding a party requires an administrator.
Cancelling records a CANCELLED event on this shipment's timeline. It is not deleted - its record, documents and history are kept and it shows as Cancelled. Only a Draft or Booked shipment can be cancelled; once cargo has moved the server refuses and says why.
Cancelled - this shipment is not deleted. Its record, documents and timeline are kept; it can no longer be advanced.
{{ editHint }}

Review & correct

Extraction confidence: {{ Math.round((lastIngest.shipment.confidence || 0) * 100) }}% — verify each field against the source document.
⚠ {{ detail.freightTermMismatch }}
Changing the freight terms or the Incoterm needs {{ rolePhrase('shipment.edit') }}.
Correcting a draft needs {{ rolePhrase('shipment.edit') }}.
🔒 Parsed fields are locked — this shipment is {{ detail.status }}. A correction is pre-commit only.

Correct a party or place

Correcting a booked shipment needs {{ rolePhrase('shipment.correct') }}.
Corrections of this shipment
{{ c.field }}: {{ c.before || '(blank)' }} → {{ c.after || '(blank)' }} {{ c.status === 'Pending' ? 'Waiting for approval' : c.status }}
{{ c.reason }} - {{ c.decisionNote }} - approved by the same person (sole operator)

Send a document

An issued document goes to the consignee exactly as it was issued. Handed to the email provider is not the same as delivered - delivery is reported separately.
{{ humanizeDocType(d.docType) }} - {{ d.transportNumber || '-' }} {{ d.state === 'voided' ? 'Voided' : (d.state === 'telex_released' ? 'Issued - telex released' : 'Issued') }} issued {{ fmtWhen(d.issuedAt) }}
Sends of this shipment's documents
{{ s.docType ? humanizeDocType(s.docType) : 'Document' }} to {{ s.recipient }} {{ sendStatusText(s) }} {{ sendDeliveryText(s) }}
{{ s.failureReason }}
{{ s.decisionNote }}

Job P&L

Revenue
{{ money(costing.revenue, costing.currency) }}
Cost
{{ money(costing.totalCost, costing.currency) }}
{{ money(costing.actualCost, costing.currency) }} billed + {{ money(costing.accruedCost, costing.currency) }} accrued
Margin
{{ money(costing.margin, costing.currency) }} ({{ costing.marginPct }}%)
Provisional — {{ costing.openAccrualCount }} vendor bill(s) still to land.

Route

No route planned.
· {{ legFrom('origin') }}
· {{ legFrom('destination') }}
· {{ legFrom('mode') }}
Nothing is saved until you press Add leg.

Cargo & containers

{{ sliceFailures.cargo.message }}
No cargo entered.
Planned equipment (no container numbers yet — the carrier assigns those later)
No planned equipment.
{{ req.count }} × {{ req.isoType }} planned — no number yet

Milestones

No milestones yet.
{{ m.code }} ETA {{ fmtWhen(m.estimatedAt) }} · actual {{ m.actualAt ? fmtWhen(m.actualAt) : '—' }} {{ m.status }}

Charges

We bill
{{ money(chargesView.strip.bill, chargesView.strip.currency) }}
We pay
{{ money(chargesView.strip.pay, chargesView.strip.currency) }}
We make
{{ money(chargesView.strip.make, chargesView.strip.currency) }} ({{ chargesView.strip.makePct }}%)
{{ chargesView.strip.text }}
{{ chargesView.strip.basis }}
The leg figures don't add up to the shipment's total cost - tell an administrator.
No charge lines yet.
{{ sec.title }} , {{ money(t.amount, t.currency) }}
{{ l.name }} - {{ l.who }} est. {{ money(l.amount, l.currency) }}
Missing
  • {{ m.text }}
This checks that lines exist and are named, not that the amounts are right.

Demurrage evidence

{{ e.containerNo || 'container' }} · {{ e.equipmentType }} · {{ e.port }} · last free day {{ e.lastFreeDay }} · est. {{ money(e.estimatedAmount, e.currency) }} · actual {{ money(e.actualAmount, e.currency) }} · actual not yet in (awaiting carrier invoice)
Cost by leg

Costs can be assigned to the leg they belong to. Unassigned costs belong to the whole shipment - that is normal.

{{ chargeLabel(c) }} {{ money(c.amount, c.currency) }} {{ c.legId ? ('Leg ' + (legSeqFor(c.legId) || '?')) : 'Whole shipment' }}
Costs not assigned to a leg
cost {{ money(costingByLeg.unallocatedCost, costingByLeg.currency) }} estimated, supplier bill not in yet {{ money(costingByLeg.unallocatedAccruedCost, costingByLeg.currency) }} sell {{ money(costingByLeg.unallocatedSell, costingByLeg.currency) }}
Estimates waiting to be assigned to a leg ({{ unallocatedAccruals.length }})
No unassigned estimates - nothing awaiting a leg.
{{ a.chargeCode }} {{ a.vendorName || 'no vendor' }} · {{ a.status }} {{ money(a.estimatedAmount, a.currency) }} est.
Cost write-offs
{{ accrualLabel(w.accrualId) }} reason: {{ w.reason }} prepared by {{ (w.preparedBy || '').slice(0, 8) }} {{ w.status }} awaiting a payment approver

Screening

No screening on record for this shipment yet.
Cannot close: {{ costing.closeBlockers.join('; ') }}
No customs filings provisioned for this shipment.
Provision a filing:

Documents & EDI

{{ transportDoc.docType }} · {{ transportDoc.loadingLabel }}: {{ transportDoc.portOfLoading }} → {{ transportDoc.dischargeLabel }}: {{ transportDoc.portOfDischarge }} · not ready: {{ transportDoc.missingElements.join(', ') }}
{{ siFailed }}
{{ siDoc.docType }} {{ siStateWords(siDoc) }}
{{ siCutoffWords }}
{{ p.k }}: {{ p.b && p.b.name ? p.b.name : 'not named' }} - {{ siAddress(p.b) }} - no postal address
Notify: {{ n.name }} - {{ siAddress(n) }} - no postal address
{{ siDoc.loadingLabel }}: {{ siDoc.portOfLoading || 'not stated' }} → {{ siDoc.dischargeLabel }}: {{ siDoc.portOfDischarge || 'not stated' }} · place of receipt {{ siDoc.placeOfReceipt }} · place of delivery {{ siDoc.placeOfDelivery }} · final destination {{ siDoc.finalDestination }}
Incoterm {{ siDoc.incoterm || 'not stated' }} · freight {{ siDoc.freightTerms ? siDoc.freightTerms.toLowerCase() : 'terms not stated' }}
DescriptionPackage kindPiecesGross weight (kg)Net weight (kg)Marks
{{ c.description || '-' }}{{ c.packageKind || 'not stated' }}{{ c.pieces != null ? c.pieces : '-' }}{{ c.weightKg != null ? c.weightKg : '-' }}{{ c.netWeightKg != null ? c.netWeightKg : 'not stated' }}{{ c.marks || 'none' }}
Total{{ siDoc.totalPieces }}{{ siDoc.totalWeightKg }}{{ siDoc.totalNetWeightKg != null ? siDoc.totalNetWeightKg : 'not stated for every line' }}
{{ k.containerNo }} (seal {{ k.sealNumber || 'none' }}), · {{ siDoc.containersInWords }}
Carrier booking reference:
  • {{ g }}
  • {{ g }}
Net weight {{ siDoc.totalNetWeightKg }} kg (gross {{ siDoc.totalWeightKg }} kg)
{{ siGaps.length }} thing{{ siGaps.length === 1 ? '' : 's' }} to fix before this can be sent
  • {{ g.words }} Where to fix it: {{ g.where }}. This is locked because the shipment is booked - it can't be changed here.
Ready - nothing is missing from the document of record.
Sent to the carrier - it is locked; a change after this is a carrier amendment.
Sending this to the carrier needs {{ rolePhrase('shipment.edit') }}.
{{ ediOut }}

Master number

Current master: {{ detail.mbl }} confirmed provisional — not yet confirmed
No master number recorded yet.
current: {{ detail.bookingRef }}
current: {{ detail.coloaderMbl }}

Master document — issue & telex-release

Documents — view & print

Required: {{ (docReadiness.requiredLabels || []).join(', ') || '—' }} · present: {{ (docReadiness.presentLabels || []).join(', ') || 'none' }} · missing: {{ (docReadiness.missingLabels || []).join(', ') }}
Loading document…

Timeline

No events yet.
{{ e.actorType }} {{ e.eventTypeCode }} {{ e.kind === 'ESTIMATED' ? 'estimate' : 'actual' }} {{ fmtWhen(e.occurredAt) }} · {{ e.actorId }} superseded by a later actual

Onboarding

✓ Company setup is complete - {{ setupGuide.done }} of {{ setupGuide.applicable }} steps done.
Getting started — configure your tenant's master data
{{ setupState.parties.done ? '✓' : '○' }} Onboard parties{{ setupState.parties.count }} configured
{{ setupState.ports.done ? '✓' : '○' }} Add ports / locations{{ setupState.ports.count }} configured
{{ setupState.rateCards.done ? '✓' : '○' }} Add rate cards{{ setupState.rateCards.count }} configured
{{ setupState.deniedParties.done ? '✓' : '○' }} Load a denied-party list{{ setupState.deniedParties.count }} entries
Reference data is present, but no denied-party list is loaded — screening is not operational; shipments depart with an unscreened alert recorded until a list is loaded.
Checking whether screening can clear against the loaded list…
A denied-party list is loaded, but whether screening can clear against it couldn't be checked just now — not confirmed operationally ready.
Not operationally ready. {{ screeningReadiness.detail }}
Not operationally ready. Until this is fixed, a party with no sanctions hit reads Not screened instead of Clear (a real hit is still shown). {{ screeningReadiness.currencyDetail || '' }} Fix it from the Screening page (screening authority required): load a newer release of a stale list (re-loading the same release is refused), or reload an untracked list with its publication date.
Operationally ready — master data is configured and an Official denied-party list is loaded and within its refresh window. This is a refresh-recency check only; it does not mean the list is complete.
{{ screeningReadiness.integrityDetail }}
Parties have their own screen now.
Places have their own screen now.
Loading a sanctions list and re-screening the book have their own page now. Loading a list needs {{ rolePhrase('screening.adjudicate') }}.
Re-ground the whole book — after onboarding, link every shipment that referenced a now-known party or port
Re-ground, re-screen and re-price ALL {{ regroundSweep.n }} active shipment(s) that are still unlinked. This may raise credit holds. Type CONFIRM to proceed.
Re-grounding the book requires screening authority.

Users & roles

Sole-operator exceptions — who changed the setting, and why
{{ soleOpAuditError }}
Loading the setting history…
Booking agent — carrier dangerous-goods answers
Currently {{ agentDgCapture.loaded ? (agentDgCapture.enabled ? 'ON — the agent may relay carrier answers' : 'OFF — only people record carrier answers') : '—' }}
If ON, {{ agentDgCapture.permits }}
Couldn't load this setting - that is a failed read, not "off".
{{ agentDgCapture.audit.length }} change{{ agentDgCapture.audit.length === 1 ? '' : 's' }} on record
  • {{ a.enabled ? 'Turned ON' : 'Turned OFF' }} · {{ fmtWhen(a.at) }} · {{ a.reason }}
Access scope readiness
The readiness check could not be read.
Every user has a resolved scope.
Invite a user
{{ roleHint(invite.roleId) }}
Pending invitations (activate on first verified sign-in): {{ u.email }}
Users & roles
No users yet.
{{ u.email }}{{ u.status }}
{{ roleName(rid) }} no roles
{{ statusConfirm[u.id] === 'Offboarded' ? 'Offboarding is final: the person cannot be restored and must be invited again.' : 'Confirm.' }} Offboarded: final. To restore access, invite the person again.

Rate cards

{{ expiringRates.length }} lane rate{{ expiringRates.length === 1 ? '' : 's' }} need renewing
A lapsed lane stops quoting — renew before the desk finds out on a broken quote.
{{ e.mode }} {{ e.originPort }}→{{ e.destinationPort }} {{ money(e.amount, e.currency) }} {{ e.currency }} {{ e.expired ? 'expired ' + (-e.daysUntilExpiry) + 'd ago' : 'lapses in ' + e.daysUntilExpiry + 'd' }} · {{ (e.validTo || '').slice(0, 10) }}
Rates / tariffs
No rate lines — add one so lanes price.
{{ r.mode }} {{ r.originPort }}→{{ r.destinationPort }} {{ r.basis }} · {{ money(r.amount, r.currency) }} {{ r.currency }} · fuel {{ r.fuelSurchargePct }}%
Reference tariffs — the rates we price from
No reference tariffs configured.
AIR {{ c.origin }}→{{ c.destination }} min {{ money(c.minimumCharge, c.currency) }} {{ c.currency }} · {{ (c.validUntil || '').slice(0, 10) || 'open-ended' }}
OCEAN FCL {{ c.origin }}→{{ c.destination }} {{ c.isoType }} · {{ money(c.ratePerContainer, c.currency) }} {{ c.currency }}/ctr · {{ (c.validUntil || '').slice(0, 10) || 'open-ended' }}
OCEAN LCL {{ c.origin }}→{{ c.destination }} {{ money(c.ratePerWm, c.currency) }} {{ c.currency }}/wm · min {{ money(c.minimumCharge, c.currency) }} · {{ (c.validUntil || '').slice(0, 10) || 'open-ended' }}
{{ c.code }} {{ c.origin }}→{{ c.destination }} {{ c.basis }} · {{ money(c.rate, c.currency) }} {{ c.currency }}
DUTY {{ c.hsCode }} → {{ c.destinationCountry }} duty {{ c.duty }}% · tax {{ c.tax }}%

Inbox — the work arrives

{{ refusalSentence('shipment.book', 'ingest documents') }}
{{ lastIngest.rejected.length }} document(s) were rejected and NOT extracted:
{{ r.name }} — {{ r.reason }}
Extracted a draft — {{ lastIngest.shipment.reference }} confidence {{ Math.round((lastIngest.shipment.confidence || 0) * 100) }}%
{{ lastIngest.sourceText }}
Shipper · {{ lastIngest.shipment.grounded ? 'grounded ✓' : 'not matched — review' }}
Open the draft to see every parsed field and correct any of them; a party correction re-screens on the spot.

Ingest review

The door read these emails and is waiting for you to confirm what arrived — nothing was created automatically. Oldest first: the one waiting longest is a customer who believes they're already booked.

Couldn't load the review queue — this is not the same as nothing waiting. {{ proposalsError }}
Nothing waiting — the review queue is clear.

{{ proposalCard.action }}

{{ proposalCard.degradedReason }}
Booking
shipper: {{ (b.booking && b.booking.shipper) || '—' }} · consignee: {{ (b.booking && b.booking.consignee) || '—' }} · {{ (b.booking && b.booking.origin) || '—' }} → {{ (b.booking && b.booking.destination) || '—' }} · {{ (b.booking && b.booking.mode) || '—' }} · {{ (b.booking && b.booking.direction) || '—' }} · {{ (b.booking && b.booking.incoterm) || '—' }} · {{ (b.booking && b.booking.paymentTerm) || '—' }}
{{ b.text }}
Amendment to {{ a.reference || '—' }}
{{ a.text }}
{{ s.kind }}: {{ s.text }}
Compliance to decide: {{ proposalCard.complianceFlags.join('; ') }}
{{ proposalCard.action === 'NeedsManualReview' ? 'Classification could not read this email, and the console can\'t show its source documents yet — handle it from the original email outside the console, then dismiss this card.' : 'The classifier found nothing to act on in this email.' }}

Showing what the classifier extracted — the interim queue doesn't render the raw email; the full source side-by-side arrives with the ingest review screen.

Nothing to create here — {{ proposalCard.action === 'NeedsManualReview' ? 'the console can\'t show this email\'s source documents yet — handle it from the original email outside the console, then dismiss.' : 'dismiss to clear it; the customer’s questions are preserved as work, nothing lost.' }}
Select a proposal to review what the email contained.

Reports

Ask for a number in the command box (⌘K) — e.g. “what's our DSO”, “who owes us”, “which lanes lost money”. This page is the full list for when you don't yet know what to ask.

{{ g.label }}

Reached in context (per-shipment / per-customer drills & setup reference — not standalone reports)
  • {{ c.endpoint }} — {{ c.reason }}
Exists but not yet reachable (named, not hidden — a surface is owed)
  • {{ c.endpoint }} — {{ c.reason }}

The books

{{ selfApproved.count }} invoice{{ selfApproved.count === 1 ? '' : 's' }} self-approved this period — approved by their own preparer (no second checker).
{{ refusalSentence('ledger.read', 'the books') }}
Chart of accounts not seeded — nothing posts to the ledger.

Accounting periods

{{ periodsError }}
PeriodStatusClosed by
{{ p.period }} {{ p.status }} —
Close {{ closeConfirm.period.period }}?
Checking what this would freeze…

Pending approvals

{{ awaitingError }}

Analytics

{{ refusalSentence('analytics.read', 'analytics') }}

Screening

What is loaded

Checking what is loaded...
Couldn't confirm what is loaded - that is a failed check, not "nothing loaded".

Load a list

Denied-party list — required before any screening can assert 'clear'
⚠ A publication date can't be in the future — it would lock this list from ever being refreshed.
Loading a denied-party list requires screening authority.

Re-screen the book

Re-screen the in-flight book — after loading an updated denied-party list, re-check every in-flight booking against it
Re-screens ALL in-flight bookings against the current denied-party list. A booking cleared before may raise a new hit — a prior clearance can be superseded. This does not re-price or raise credit holds.
{{ reScreenSweep.result.shipmentsScreened }} re-screened · {{ reScreenSweep.result.shipmentsWithHits }} now hit · {{ reScreenSweep.result.shipmentsNotScreened }} could not be screened (a blank name, or no list that can vouch for a clear - not a match) — none newly hit (a measured clear). — no match found, but this is not a clear: the shipments above could not be screened. · {{ reScreenSweep.result.staleListExceptionsRewritten }} raw-document exception(s) updated: a list is loaded now, but the document text is not kept - re-submit the document to screen it.
{{ reScreenSweep.error }}
Re-screening the book requires screening authority.

Hits to review

A possible match on a shipment's party raises a review in the Work queue, where it is adjudicated or left to hold the shipment.

Entries on file

Declare each row's provenance. TenantPrivate = your own list — reversible, tenant-removable. Official = a genuine sanctions listing — permanent, one-way, and the tenant can no longer remove it (only a privileged sanctions-correction authority can, audited).

No denied parties loaded.
NameListSourceDeclare source
{{ d.name }} · {{ d.country }} {{ d.listName }} {{ d.source }} · stored source not recognised; still screens, never Official · {{ d.sourceDeclaredBy }}

Correction audit trail

Every Official → TenantPrivate correction recorded for your organisation, newest first — the complete record, not a page. Correcting an Official sanctions listing is a privileged, audited act that breaks a lock the system otherwise refuses; this is who did it, when, and why.

No corrections recorded.
PartyListChangeByWhenReason
{{ c.partyName }} {{ c.listName }} {{ c.correctedFrom }} → {{ c.correctedTo }} {{ c.correctedBy }} {{ fmtWhen(c.correctedAt) }} {{ c.reason }}

Apply a customer receipt

Record a customer's payment; it settles their open invoices oldest-due-first, same-currency only. Any excess, or a receipt in a currency with no open invoice, is held on account — shown, never cross-applied.

No customers yet — onboard a customer first.
Nothing to apply in {{ receiptResult.currency }} — {{ money(receiptResult.unapplied, receiptResult.currency) }} held on account (no open invoice in this currency; never cross-applied).

Demurrage watch

New demurrage / detention tariff

Per-day rates are money: choose the currency — there is no default. Tier days count chargeable days (the days after the free days): the first tier starts at day 1, tiers must not leave a gap, and a blank ‘to day’ means open-ended.

Tier {{ i + 1 }}

Customs filings due{{ customsDue.count }}

Unsubmitted filings whose statutory deadline is approaching or past — across every shipment. Overdue first. A filing also shows on its own shipment; this is the cross-shipment worklist.

No customs filings due soon or overdue.
ShipmentFilingDeadline
{{ f.filingType }} {{ f.deadlineStatus === 'Overdue' ? 'overdue' : 'due soon' }}

Agent invoices

Clearing or rejecting a record means a person reviewed it. It does not approve, release or block any payment. Only invoices that someone has entered for reconciliation appear here — an invoice nobody entered is not checked at all.

Reconciliation has not run: no agent invoice has been entered, so nothing has been checked. An empty list here is NOT an all-clear.
Last reconciled {{ fmtWhen(agentInvoiceStatus.lastReconciledAt) }} · {{ agentInvoiceStatus.total }} record(s) · {{ agentInvoiceStatus.needsReviewOpen }} still need review — ran, and nothing is waiting for review
Enter an agent invoice
{{ (agentForm.currency || '').trim().toUpperCase() }}
{{ agentLinesSum().text }}
Our numbers as they appear on their invoice (at least one, or it cannot be matched to a shipment):
{{ agentForm.result.match.outcome === 'Matched' ? 'Matched to a shipment' : 'Not matched' }} — {{ agentForm.result.match.reason }}
It compared the value exactly (ignoring case) with this company's shipment house bill, master bill and container numbers. A near-miss — a transposed digit, a different spacing — is not matched. Check the number against the shipment and enter it again.
Checked against: {{ agentForm.result.recon.basis === 'Agreed' ? 'agreed rate — every billed charge checked against its own stored agreement' : agentForm.result.recon.basis === 'PartiallyAgreed' ? 'agreed rates on SOME charges only — the rest NOT checked against an agreement' : agentForm.result.recon.basis === 'AggregateOnly' ? 'agreed rates, total only — individual charges NOT verified' : agentForm.result.recon.basis === 'Estimate' ? 'our estimate — not an agreed rate' : 'nothing — NOT reconciled' }}. {{ agentForm.result.recon.label }}
{{ agentForm.result.recon.label }}
  • {{ l.chargeCode }} {{ l.amount }} — {{ l.label }}
{{ agentPayGateText(agentForm.result.payGate) }}
Not verified: {{ agentForm.result.unverifiedScope }}
  • {{ b }}
Agent invoiceMatched toBilledOur estimateVarianceChecked againstAgeWho can work itRecorded byReview
{{ r.agentDocNumber || '(no number)' }} {{ r.match.outcome === 'Matched' ? ('shipment ' + (r.match.key || '')) : ('unmatched — ' + r.match.reason) }} {{ r.invoiceActual }} {{ r.currency }} {{ r.recon.estimatedAmount === null || r.recon.estimatedAmount === undefined ? '—' : (r.recon.estimatedAmount + ' ' + r.currency) }} — {{ r.recon.variance > 0 ? '+' : '' }}{{ r.recon.variance }} ({{ r.recon.variancePct > 0 ? '+' : '' }}{{ r.recon.variancePct }}%) {{ r.recon.basis === 'Agreed' ? 'agreed rate — every billed charge checked against its own stored agreement' : r.recon.basis === 'PartiallyAgreed' ? 'agreed rates on SOME charges only — the rest NOT checked against an agreement' : r.recon.basis === 'AggregateOnly' ? 'agreed rates, total only — individual charges NOT verified' : r.recon.basis === 'Estimate' ? 'our estimate — not an agreed rate' : 'nothing — NOT reconciled' }}
{{ r.recon.label }}
  • {{ l.chargeCode }} {{ l.amount }} — {{ l.label }}
— Unassigned — no desk {{ r.recordedBy ? (r.recordedBy === (me && me.userId) ? 'you' : 'a colleague') : 'not recorded' }}
{{ r.settlement.status === 'SettledOnRelease' ? 'Paid — settled on release (nothing was left unverified)' : (r.settlement.status === 'PaidPostPaymentReviewPending' ? 'Paid — a post-payment review is still owed' : 'Paid') }} · {{ fmtWhen(r.settlement.releasedAt) }}
{{ r.resolution === 'ClearedByHuman' ? 'Cleared by a person' : 'Rejected by a person' }} · {{ fmtWhen(r.resolvedAt) }} You entered this one, so a second person must review it. Waiting for a reviewer with payment approval.
No records to show.

Agent rates

An agreed rate is what we have agreed to pay an agent for one charge. An agent's invoice is checked against the version in force on the date the shipment was created in Tiller (the booking-date proxy). A rate is never edited or deleted: a change is a new version that replaces the old one, and invoices already checked keep the version they were checked against. These rates are internal — never shown to customers or agents.

These rates are read-only for you. Entering or replacing one needs {{ rolePhrase('agent_rate.manage') }}.
AgentChargeLaneAgreedIn effectVersionWhy
{{ agentRateAgentName(a.counterpartyId) }} {{ a.chargeCode }} {{ agentRateLane(a) }} {{ agentRateFigure(a) }} {{ agentRateWindow(a) }} Current version Replaced by a later version
replaces an earlier version
{{ a.reason || '—' }}
entered {{ fmtWhen(a.createdAt) }} by {{ a.createdByUserId === (me && me.userId) ? 'you' : 'a colleague' }}
No agreed rates are on file{{ agentRateFilter ? ' for this agent' : '' }}. Until one is entered, an agent's invoice can only be checked against our own estimate — and every result says so.
Replace this rate with a new version
{{ agentRateSup.summary }} — the agent, charge and lane stay the same; the old version is kept, unchanged, as history.
Enter an agreed rate
The quantity comes from OUR shipment record (weight, volume or containers) — never from the quantity on the agent's invoice. If our shipment has no recorded quantity, that charge is not checked and the result says why.

Invoice numbering

The invoice-number format each issuing unit uses — a statutory artefact. Changing a format governs invoices issued from now on; it never restates numbers already issued.

— make this tenant issuance-ready (idempotent; needed when provisioning is manual).
Provisioning mode — currently {{ me ? me.provisioningMode : '—' }}:
⚠ Switching to manual does NOT change units that are already provisioned — live numbering keeps working. But an UNPROVISIONED unit will then REFUSE to issue a number until you provision it (use “Provision the default unit” above), so a document could be blocked when you go to issue it. Provision before you need to issue.
No issuing unit configured yet — provision the default unit to start issuing.
UnitInvoice number formatCompliance
{{ u.name }} (default) {{ u.numberFormat }} (named default) {{ u.compliance.caveat }}
Change the invoice-number format
Tokens: {PREFIX} · {YYYY} · {YY} · {MM} · {YYYYMM} · and exactly one {SEQ} or {SEQ:N}. The named default is {{ defaultInvoiceFormat }}.
⚠ This governs FUTURE invoices only. Numbers already issued KEEP their current format — the change is not retroactive, so the series becomes heterogeneous from here on, and an issued statutory number cannot be restated.

Company records

The legal entities your branches sell and invoice as. A company's name, tax registration and address can be corrected at any time; a correction applies to invoices issued from then on, and an invoice already issued keeps the seller it was issued with. The one exception is an old invoice that was issued before invoices were frozen and has not been backfilled: the record refuses a correction by name while it would restate one. The base currency stays open only until the company is in use - a branch belongs to it, or anything has been posted to the ledger.

{{ entitiesError }}
No company record yet - add the first one from Getting started.
CodeLegal nameTax registrationBase currencyAddress
{{ en.code }} {{ en.legalName }} {{ en.taxRegistrationId }}not set {{ en.baseCurrency }}not set {{ entityAddress(en) }}
{{ en.legalName }} - offices under this company
{{ b.code }} {{ b.name }} ({{ b.country }}) Default
{{ officeRetireBlock(b).sentence }}
Renaming an office is recorded.
A label for this office. The company's country decides tax.
{{ officeDefaultSentence(b) }}
{{ officeCompanySentence(b) }}
Retire {{ b.code }}? {{ officeRetireSentence(b) }}
This company has no office, so no invoice can name it as the seller.
Retired offices ({{ retiredOfficesOf(en).length }})
{{ b.code }} {{ b.name }} · {{ retiredOfficeLine(b) }}
The code and the company cannot be changed afterwards.
An office is added by {{ rolePhrase('branch.manage') }}.
Offices with no company record
{{ b.code }} {{ b.name }} - no company record: invoices from its shipments cannot name a seller
Linking gives the office the company it was missing; it writes nothing about the company.
Retired offices with no company record ({{ retiredUnlinkedOffices().length }})
{{ b.code }} {{ b.name }} · {{ retiredOfficeLine(b) }}
Edit {{ entityEdit.code }} - the code cannot be changed

Tax treatment

Tax rates loaded from a file your tax adviser reviewed — never typed here. Tiller supplies no rates and does not check them; the file says who verified each one. An invoice's tax comes from the rate in force on the day it is issued.

{{ taxTreat.readError }}

Load a reviewed tax file

The file's columns follow the template, which has headings only: template. Loaded rows can't be edited or removed — to change a rate, add a row with a later start date.
As read from the file:
{{ taxPreviewLine() }}
  • {{ p.what }}. Why: {{ p.why }} Fix: {{ p.fix }}.
and {{ taxTreat.problemTotal - taxTreat.problems.length }} more not shown.
{{ taxDoneLine() }}
Tax treatments are loaded by {{ rolePhrase('tax.treatment.load') }}.

Quotes

New quote

Price a lane from the tariff and create a quote. No rate card for the lane is a named refusal, not a failure — seed a tariff (that needs {{ rolePhrase('rate.manage') }}).

No quotes yet.
CustomerLaneSellStatusValid untilAction
{{ q.customerName }} {{ q.originPort }} → {{ q.destinationPort }} ({{ q.mode }}) {{ q.totalSellUsd }} {{ q.currency }} · {{ q.marginPct }}% margin {{ q.isExpired && q.status !== 'Expired' ? q.status + ' · expired' : q.status }}
Approved {{ fmtWhen(q.approvedAt) }} by {{ q.approvedBy === (me && me.userId) ? 'you' : 'a colleague' }} — {{ q.approvalReason }} · approved by its own creator as the sole operator — a recorded exception, listed for review
Awaiting approval — a person who did not create this quote must approve it before it can be sent or accepted. {{ q.approvalPolicy }}
Accepted before the approval control existed — no approver is on record.
{{ fmtWhen(q.validUntil) }} Approved — {{ q.status === 'Draft' ? 'sending' : 'accepting' }} is done by someone who holds quote.manage. Expired — re-quote to send (validity lapsed {{ fmtWhen(q.validUntil) }}) Accepted — booked Declined

Showing a capped page — more quotes exist than are listed here (narrow by customer/lane to see the rest).

Win rate lives in Analytics — computed over DECIDED quotes (accepted ÷ accepted+declined); an open quote is not a loss.

Payment run

The vendors to pay are not shown — the payment run is shown to {{ rolePhrase('ledger.read') }}. Payments already prepared and awaiting release are listed below.
Nothing to pay — no vendor is net-payable.

Prepare a payment

Prepared — nothing is paid yet; a different approver must release it.

Payments awaiting release

Nothing prepared — no payment is awaiting release.
{{ vendorName(i.vendorId) }} · {{ money(i.amount, i.currency) }}
Prepared — awaiting release; nothing is out yet.
Prepared by {{ i.preparedBy === (me && me.userId) ? 'you' : ('user ' + (i.preparedBy || '').slice(0,8)) }}
Payable, but NOT checked charge by charge — what was not verified:
{{ u.agentDocNumber || '(no agent document number)' }} · {{ u.amount }} {{ u.currency }} — {{ u.scope }}
The approver who releases this payment must acknowledge each of these.
Tick each record to acknowledge it, then release. Releasing is refused until every one listed is acknowledged.
awaiting a payment approver
{{ partyScreeningNotice }}

Parties

Show: {{ retiredParties.error }}
Retired parties - showing {{ retiredParties.shown }} of {{ retiredParties.total }}, most recently retired first. A retired party is hidden from booking and search until restored. Retired parties are permanently removed after {{ retiredParties.purgedAfterDays }} days.
{{ retiredParties.total == null ? 'The retired parties could not be loaded.' : 'No retired parties. A party you retire appears here, and stays here after a reload.' }}
{{ partyAnnouncement }}
No parties yet. The + New party button adds one.
No party matches "{{ partySearch }}".
NameRoleCityCreditDocuments

New party

A party with this name already exists: {{ m.legalName }} Adding another with the same name is allowed - you will be asked to confirm.
Similar existing names:
Identity A new party starts on credit Hold with no limit; Finance sets its credit separately.
Address
Contact
Tax & accounts
{{ partyDuplicateOffer.message }}
Existing: {{ partyDuplicateOffer.existing.legalName }}
Adding a party requires an administrator.

{{ newParty.id ? 'Editing ' + (newParty.legalName || recordParty.legalName) : recordParty.legalName }} · {{ recordParty.isCustomer ? 'Customer' : 'Vendor only' }}

Editing {{ newParty.legalName || 'party' }} — Save applies your changes.
Identity A new party starts on credit Hold with no limit; Finance sets its credit separately.
Address
Contact
Tax & accounts
{{ partyDuplicateOffer.message }}
Existing: {{ partyDuplicateOffer.existing.legalName }}
Adding a party requires an administrator.
Loading…
You don't have permission to read the ledger, so this party's statement and net position can't be shown.

Places

No places yet. The + New place button adds one.
No place matches "{{ placeSearch }}".
CodeNameAliases
{{ l.code }} {{ l.name }} {{ (l.aliases || []).join(', ') || '—' }}

New place

The short code a shipment's origin or destination is matched on, for example a UN/LOCODE such as MYPKG. It must be unique.
Adding a place requires an administrator.

Consolidations

Create a consolidation

{{ consolsListError }}
No consolidations yet{{ can('shipment.edit') ? ' — create one above.' : '.' }}
Showing a capped page — more consolidations may exist than are listed.
{{ c.reference }} {{ c.mode }} {{ c.direction }}

{{ consol.reference }} {{ consol.mode }} {{ consol.level }}

{{ consol.masterConsigneeGap }}
{{ consol.houseCount }} house(s) · {{ consol.consolidatedCargo.pieces }} pcs · {{ consol.consolidatedCargo.weightKg }} kg
Consol P&L ({{ consolPnl.currency }}) — revenue {{ consolPnl.revenue }} · cost {{ consolPnl.cost }} · margin {{ consolPnl.margin }} incomplete — no FX for {{ (consolPnl.missingRates || []).join(', ') || 'some charges' }}
Houses
No houses attached yet.
{{ h.reference }} {{ h.status }}
Confirming a Draft house's booking needs {{ rolePhrase('shipment.advance') }}.
P&L by member ({{ consolBreakdown.currency }})
{{ l.reference }} ({{ l.role }}): revenue {{ l.revenue }} · cost {{ l.cost }} · margin {{ l.margin }}
Total margin {{ consolBreakdown.margin }} {{ consolBreakdown.currency }} ({{ consolBreakdown.marginPct }}%) · {{ consolBreakdown.includedShipments }} included
{{ consolBreakdown.excludedShipments }} excluded, not summed: {{ x }};
Co-load cost allocation
Can't allocate: {{ consolAllocation.reason }}
{{ consolMsg }}

EDI inbox

Paste an inbound EDIFACT IFTMIN (a partner's booking) or an X12 214 (a carrier status).

Stock on hand

No stock on hand — register an item or receive goods.
SKUOwnerUoMOn hand
{{ s.sku }} {{ vendorName(s.ownerPartyId) }} {{ s.uom }} {{ s.onHand }} low stock

{{ item.sku }} — {{ item.description }}

On hand {{ item.onHand }} {{ item.uom }} · Available (ATP) {{ availability ? availability.available : '…' }} at/below reorder point
Movement ledger
No movements yet.
WhenTypeQtyRefNote
{{ (m.occurredAt || '').slice(0,10) }} {{ m.type }} {{ m.quantity }} {{ m.reference || '—' }} {{ m.note || '—' }}

Goods receipt orders

Ladder: Open → Received → PutAway (posts +) → Completed.
No goods-receipt orders.
RefItemQtyStatus
{{ o.reference || o.id.slice(0,8) }} {{ o.itemId.slice(0,8) }} {{ o.quantity }} {{ o.status }} · posted

Goods issue orders

Ladder: Open → Picked → Packed → Issued / PGI (posts −, no-oversell) → Completed.
No goods-issue orders.
RefItemQtyStatusBooking
{{ o.reference || o.id.slice(0,8) }} {{ o.itemId.slice(0,8) }} {{ o.quantity }} {{ o.status }} · PGI posted {{ o.shipmentId.slice(0,8) }}—

Permissions granted to you

Your account has no role yet — ask an administrator for access. You're signed in, but you won't see or be able to do anything here until a role is granted.

You are an external account (a customer or carrier): you see ONLY your own records — shipments and data where you are a party — not the whole tenant. The permissions below are what you're granted; your data is scoped to you, so an empty result means it is outside your scope, not that there is none.

These are the permissions granted to your account. Your actual access may be further scoped by your role and by data ownership — an external account (a customer or carrier), for example, sees only its own records. This lists what you're granted, not the exact records you can reach.

{{ b }}

{{ g.title }}

  • {{ p.label }} ({{ p.code }})