October 1, 2026

Yardi Voyager CommitPayments and Construction Draws, Explained

Ask a property accountant how AP works in Yardi Voyager and you'll hear a clean story: invoice comes in, it hits the register, it becomes a payable, it gets paid. Ask the same question about a capital project or a ground-up construction job, and the story gets a second track — one where the "invoice" is a payment certificate against a commitment, not a standalone bill.

That second track is what trips people up the first time they go looking for construction spend in the schema and can't find it where AP spend normally lives.

Commitment accounting, briefly

Construction and capital-project accounting runs on a different premise than routine AP. Before any money moves, a commitment is booked — a contract or purchase order value the project is on the hook for, whether or not a dollar has been paid yet. As work gets certified, draws (or payment certificates) get issued against that commitment: a contractor bills for percentage-complete, an architect or PM certifies it, and only the certified amount becomes payable.

The accounting question that matters at every stage isn't "what have we paid" — it's "what have we committed, what's been certified against it, and what's left to draw." A commitment can sit open for months with a fraction drawn. That's normal. It's the whole point of tracking commitment and actual separately instead of only recording spend when cash moves.

Standard AP tables aren't built to answer that question, because they only know about invoices and payments — not about a commitment that predates either.

Where Voyager keeps this: COMMITPAYMENTS

Voyager's Construction & Projects module carries this as its own layer, in a table named COMMITPAYMENTS. It sits between the job-cost commitment and Voyager's normal AP spine, and its job is to bridge the two: it's what turns a certified draw into an actual payable and, eventually, an actual payment.

The columns that do the bridging, execution-verified against a live Voyager schema:

That last pair is the whole point of the table existing: commitment and draw, sitting together, instead of a commitment number living only in a project-management system that never talks to the general ledger.

The trap: not every payable comes from the invoice register

Voyager's payable population — TRANS rows with iType = 3 — is a hub, not the end of a single pipeline. (We've written about decoding TRANS.iType and separately about the hub-and-spoke shape of Voyager's procure-to-pay architecture; 3 is the AP-invoice/payable code, and the payable is the hub both posts describe.) The normal route into that hub is the AP invoice register: GLInvRegTrans/GLInvRegDetail posts an invoice, and the header links out to the TRANS row it creates.

Construction payment certifications don't have to take that route. A draw can post through COMMITPAYMENTS and create its TRANS payable directly — with or without a matching row in the invoice register at all. That means a query that assumes every payable started life as a registered invoice will quietly miss real construction spend, not because the data is wrong, but because it came in through the other door.

The practical fix is to check both doors before you draw a conclusion about where a payable came from: reverse-lookup a TRANS row (iType = 3) against GLInvRegTrans.hPayable (the invoice-register path) and against COMMITPAYMENTS.hTran (the construction path). The two aren't mutually exclusive — a construction invoice can flow through both, registered and certified — and a payable matching neither is standalone, direct-entry AP. Three populations, not one, and the label depends on which link (if any) resolves.

What that looks like in ySQL

A starting shape for pulling committed-vs-drawn-vs-paid status per project, built from the verified COMMITPAYMENTS columns above:

SELECT
  cp.hDetail            AS gl_distribution,
  cp.dCommitted          AS committed_amount,
  cp.cAmount             AS certified_amount,
  t.STOTALAMOUNT         AS payable_amount,
  cp.bPaid               AS is_paid,
  gd.Checkdate            AS payment_date
FROM COMMITPAYMENTS cp
JOIN TRANS t             ON cp.hTran = t.HMY
LEFT JOIN GLDisbursement gd ON cp.hGlDisbursement = gd.hMy
WHERE t.ITYPE = 3
  AND cp.dCommitted <> 0
ORDER BY cp.dCommitted - ISNULL(cp.cAmount, 0) DESC

Ordering by the gap between dCommitted and cAmount surfaces exactly the number a project accountant actually wants: how much of each commitment is still undrawn. Extending it to flag invoice-register overlap means adding the GLInvRegTrans.hPayable reverse-lookup described above — worth doing before you report a total, not after.

One more thing worth knowing before you run anything like this at scale: Voyager's ySQL console caps results at 5,000 rows per query, and it does so silently — no error, just a truncated result set that looks complete. On a portfolio with real construction volume, bound by date or project before you trust a total.

Stop reverse-engineering the construction ledger from scratch

This is the kind of table nobody documents until they've been burned by it — a real commitment layer sitting one join away from the AP spine everyone already knows, invisible until a project's spend doesn't reconcile against the invoice register you were checking. PropETL's SQL Query Assistant carries COMMITPAYMENTS and the rest of Voyager's procure-to-pay architecture — invoice register anatomy, MM2 purchasing traps, the hub-and-spoke shape of the payable itself — as queryable, execution-verified knowledge inside Claude.

It ships in every tier. Start the free 7-day trial — no credit card — and ask it where a project's spend actually lives before you write the next query by hand.