TMS Webhooks Developer Guide
Last updated: September 10, 2026
Webhooks let your TMS receive real-time notifications when something changes on a job in Denim, instead of polling the API. Denim sends an HTTP POST request with a JSON payload to an endpoint you register, as soon as the underlying event happens.
Webhooks are a complement to the Denim Public API — use the API to fetch full job state on demand, and webhooks to know when to fetch it (or to fetch a subset of what a webhook already gives you).
How delivery works
Something happens on a job in Denim (for example, a job is approved).
Denim publishes an internal event describing that change.
Our webhook delivery service builds the event payload and sends it to your registered endpoint as an HTTP
POSTwith a JSON body.
Webhooks are sent at least once. Use source_event_id (see below) to deduplicate on your end if you receive the same event more than once — for example, after a retried delivery.
We recommend treating webhooks as a signal to sync, not as the sole source of truth. If you ever suspect you’ve missed an event, the corresponding job can always be re-fetched from the API.
Retries
If a delivery attempt doesn’t get a successful (2xx) response from your endpoint — including a non-2xx status, a timeout, or a connection error — Denim retries it. We attempt delivery up to 5 times total, spaced out with increasing delay: immediately, then after 5 minutes, 30 minutes, 4 hours, and 20 hours — spreading the 5 attempts across roughly 24 hours. If the 5th attempt still fails, the event is abandoned and no further attempts are made.
Every retry of the same event carries the same source_event_id as the original attempt, so the dedup guidance above applies to retries too. If an event is ever abandoned before it reaches you, nothing about the underlying job/obligation state is lost — re-fetch it from the API using job_uuid whenever you suspect you’ve missed something.
Getting set up
Webhooks are not yet self-serve. When they are, you can log in to Denim, click on “Integrations”, and “Configure” in the Webhooks container to get started.
In the Configure Webhooks modal that pops up, you will need to enter:
URL where you’d like Webhooks to be sent. This should be obtainable from your TMS Provider.
Optionally, an API Key (also provided by your TMS Provider) that will identify you as the recipient of the webhook. a. We will send this value via
X-API-KEYheader in the request. We do not generate this value; it is something that, if present in the configuration, we will send with all webhook requests.
Verifying requests
We currently do not sign webhook payloads (for example, no HMAC signature header). To verify that a request genuinely came from Denim today, you have two options:
IP allowlisting — Webhook requests from Denim (Production) will come from
35.231.193.139.A shared API key — the API Key entered during configuration can also serve as a point of verification.
The event envelope
Every webhook, regardless of type, is sent in the same outer shape:
Field | Type | Description |
|---|---|---|
| string (UUID) | Unique ID of the underlying event that produced this webhook. Use this to deduplicate retried/duplicate deliveries. |
| string | Dot-namespaced event name, e.g. |
| string (ISO 8601 datetime) | When the underlying change happened in Denim. |
| string (UUID) | The job this event relates to. |
| object | The event-specific payload. Shape depends on |
All monetary amounts throughout every payload are integers in cents — e.g. $2,850.00 will come across as 285000.
One structural note that applies to every webhook type below except job.approved: data.job is a minimal reference —
{ "uuid": "...", "reference_number": "...", "status": "..." }
— rather than the full job snapshot. If you need full job detail for one of these events, look it up via the API using job_uuid.
job.approved
Sent when a job is approved. data.job on this event will contain a full snapshot of the job at the moment it was approved:
Field | Type | Description |
|---|---|---|
| string (UUID) | Job identifier. |
| boolean | Whether the job is factored. |
| string | Job status at the time of approval ( |
| string | null | Optional status detail. |
| string | null | Your reference number for the job. |
| string | null | Name of the job’s company. |
| string (ISO 8601) | When the job was created. |
| string | null | Name of the user who created the job, if available. |
| integer | Count of open document-audit issues requiring action. |
| boolean | Whether the job is flagged as needing attention. |
| array | See obligation shape below. |
| array | See document shape below. |
Each entry in obligations (this same shape is reused inside job.payment and job.audit_issue.* below):
Field | Type | Description |
|---|---|---|
| string (UUID) | Obligation identifier. |
| integer | null | Set for receivable obligations. |
| integer | null | Set for payable obligations to a contractor/carrier. |
| integer | Total amount, in cents. |
| integer | null | Amount applied so far, in cents. |
| integer | null | Remaining amount due, in cents. |
| string (ISO 8601) | When the obligation is due. |
| string (ISO 8601) | The obligation’s effective date. |
| string |
|
| string | e.g. |
| string | Customer-facing payment status (e.g. |
| string | null | Reference number for this obligation. |
| string | null | Name of the counterparty company. |
| string | null | Name of the factor, if the obligation is paid to/by a factor. |
| boolean | null | Whether the obligation was express-factored. |
| array | Breakdown of the obligation — see below. |
Each entry in obligations[].line_items:
Field | Type | Description |
|---|---|---|
| integer | Line item identifier. |
| string | One of the line item types in the table below. |
| string | null | Human-readable description. |
| integer | Amount, in cents. Negative for fees; positive for the base amount and most accessorials — see below. |
| number | null | Basis-points rate, if the line item is rate-based (currently only |
| string (UUID) | The obligation this line item belongs to. |
An obligation’s line_items[].amount values always sum to its total_amount. An obligation with no fees or accessorials applied has no need to itemize and comes across with line_items: [].
Line item types
| Where it comes from |
|
|
|
|---|---|---|---|---|
| System-generated. The obligation’s gross amount before any fees or adjustments. Only present once the obligation has at least one other line item — an obligation with no fees/accessorials has | Positive. |
| Always |
| Submitted by the client/TMS via the API (e.g. detention, lumper, layover), or added automatically when a document-audit resolution pulls a matching line item off the carrier invoice/rate confirmation. | Positive. |
| Free text supplied by whoever added the line item (max 40 chars), e.g. |
| A manual correction to the obligation total, submitted via the API/UI. | Either sign. |
| Free text. |
| QuickPay. System-generated discount fee charged to a payee being paid directly (no factor) in exchange for faster payment. Only appears on non-client payable obligations where a QuickPay rate applies. | Negative — basis points of the adjusted base amount. | The basis-points rate used, e.g. | Always |
| Express Factoring / Express Pay. System-generated fee charged when an obligation is expedited via RTP. Appears once the obligation is (or becomes) | Negative — a flat fee from the client’s policy. |
| Always |
| System-generated servicing fee taken from the job total per the client’s policy. Lives on the job’s | Negative. | The basis-points rate from the client’s policy. | Always |
| System-generated flat per-job fee from the client’s policy. | Negative. |
| Always |
| System-generated flat fee charged on non-factored jobs with a receivable. | Negative. |
| Always |
| Legacy values kept for schema compatibility. No current code path produces either — you shouldn’t see them on new obligations. | — | — | — |
QuickPay and Express Factoring fees ride along in line_items like any other line item — there’s no separate top-level field for them (is_express_factored on the obligation is the one exception: it’s a boolean flag alongside line_items, not a substitute for the express_factoring_fee line item itself).
Each entry in documents (this same shape is reused inside job.audit_issue.* below):
Field | Type | Description |
|---|---|---|
| string (UUID) | Document identifier. |
| string | Original file name. |
| string | e.g. |
| string | null | Optional document subtype. |
| string (ISO 8601) | When the document was uploaded. |
| string | A temporary download link. Expires 24 hours after the webhook is sent — if you need the file later, re-fetch it from the API. |
Example: job.approved
{
"source_event_id": "018f2b6a-9c3d-7a1e-b5a2-4d3f1e9a2b70",
"webhook_type": "job.approved",
"occurred_at": "2026-07-31T14:23:05Z",
"job_uuid": "0b1e9a3d-6f2c-4e11-9a77-2c8f4d1b3a90",
"data": {
"job": {
"uuid": "0b1e9a3d-6f2c-4e11-9a77-2c8f4d1b3a90",
"is_factored": true,
"status": "approved",
"status_message": null,
"reference_number": "TS-482913",
"company_name": "Summit Freight Brokers LLC",
"created_at": "2026-07-28T18:02:11Z",
"created_by_user_full_name": "Jamie Rivera",
"actionable_doc_audit_issue_count": 0,
"needs_attention": false,
"obligations": [
{
"uuid": "b3f2e4a1-8d3c-4a2e-9f11-7c6d5e4a3b21",
"client_debtor_relationship_id": 340,
"client_payee_relationship_id": null,
"total_amount": 285000,
"applied_amount": 0,
"amount_due": 285000,
"due_date": "2026-08-30T00:00:00Z",
"obligation_date": "2026-07-31T00:00:00Z",
"type": "receivable",
"subtype": "primary",
"payment_status": "expected",
"reference_number": "INV-98213",
"company_name": "Northbound Debtor Co.",
"factor_company_name": null,
"is_express_factored": true,
"line_items": [
{ "id": 501, "type": "base_amount", "description": "Base Amount", "amount": 260000, "rate": null, "obligation_uuid": "b3f2e4a1-8d3c-4a2e-9f11-7c6d5e4a3b21" },
{ "id": 502, "type": "accessorial_fee", "description": "Detention", "amount": 25000, "rate": null, "obligation_uuid": "b3f2e4a1-8d3c-4a2e-9f11-7c6d5e4a3b21" }
]
},
{
"uuid": "4c5d6e7f-8a9b-4c1d-9e2f-3a4b5c6d7e8f",
"client_debtor_relationship_id": null,
"client_payee_relationship_id": 512,
"total_amount": 235000,
"applied_amount": 0,
"amount_due": 235000,
"due_date": "2026-08-15T00:00:00Z",
"obligation_date": "2026-07-31T00:00:00Z",
"type": "payable",
"subtype": "primary",
"payment_status": "expected",
"reference_number": "PO-33210",
"company_name": "Rolling Thunder Trucking",
"factor_company_name": null,
"is_express_factored": false,
"line_items": [
{ "id": 503, "type": "base_amount", "description": "Base Amount", "amount": 235000, "rate": null, "obligation_uuid": "4c5d6e7f-8a9b-4c1d-9e2f-3a4b5c6d7e8f" }
]
}
],
"documents": [
{ "uuid": "2b3c4d5e-6f7a-4b8c-9d0e-1f2a3b4c5d6e", "file_name": "rate_con_TS-482913.pdf", "type": "customer_rate_con", "subtype": null, "inserted_at": "2026-07-30T12:00:00Z", "url": "https://link-to-gcp-file.gcp.com" },
{ "uuid": "3c4d5e6f-7a8b-4c9d-0e1f-2a3b4c5d6e7f", "file_name": "pod_TS-482913.pdf", "type": "pod", "subtype": null, "inserted_at": "2026-07-30T16:20:00Z", "url": "https://link-to-gcp-file.gcp.com" }
]
}
}
}
job.rejected
Sent when a job fails manual review and is rejected. data.job is the minimal reference; data.manual_review.message carries a human-readable explanation.
{
"source_event_id": "4f5a6b7c-8d9e-4f0a-9b1c-2d3e4f5a6b70",
"webhook_type": "job.rejected",
"occurred_at": "2026-07-31T09:47:22Z",
"job_uuid": "0b1e9a3d-6f2c-4e11-9a77-2c8f4d1b3a90",
"data": {
"job": {
"uuid": "0b1e9a3d-6f2c-4e11-9a77-2c8f4d1b3a90",
"reference_number": "TS-482913",
"status": "rejected"
},
"manual_review": {
"message": "Job Rejected: Proof of delivery not received; Rate confirmation amount does not match invoice"
}
}
}
job.resolved
The inverse of job.rejected — sent when a previously rejected/flagged job is corrected and returned to normal processing. Same shape, different message content and job status.
{
"source_event_id": "5a6b7c8d-9e0f-4a1b-9c2d-3e4f5a6b7c80",
"webhook_type": "job.resolved",
"occurred_at": "2026-07-31T10:15:49Z",
"job_uuid": "0b1e9a3d-6f2c-4e11-9a77-2c8f4d1b3a90",
"data": {
"job": {
"uuid": "0b1e9a3d-6f2c-4e11-9a77-2c8f4d1b3a90",
"reference_number": "TS-482913",
"status": "pending"
},
"manual_review": {
"message": "Job Resolved: Proof of delivery and corrected rate confirmation uploaded; job returned for reprocessing."
}
}
}
job.manual_review.failed / job.manual_review.resolved
Sent when a job is flagged for manual review at any of three separate processing stages (data processing, review, and third-party/debtor-portal verification), and again when that flag clears. Regardless of which stage triggered it, the webhook shape is identical — only data.manual_review.message differs, describing what was flagged or resolved at that stage.
{
"source_event_id": "7e8f9a0b-1c2d-4e3f-9a4b-5c6d7e8f9a10",
"webhook_type": "job.manual_review.failed",
"occurred_at": "2026-07-31T11:03:18Z",
"job_uuid": "0b1e9a3d-6f2c-4e11-9a77-2c8f4d1b3a90",
"data": {
"job": {
"uuid": "0b1e9a3d-6f2c-4e11-9a77-2c8f4d1b3a90",
"reference_number": "TS-482913",
"status": "pending"
},
"manual_review": {
"message": "Issue found in review"
}
}
}
{
"source_event_id": "8f9a0b1c-2d3e-4f4a-9b5c-6d7e8f9a0b20",
"webhook_type": "job.manual_review.resolved",
"occurred_at": "2026-07-31T15:47:02Z",
"job_uuid": "0b1e9a3d-6f2c-4e11-9a77-2c8f4d1b3a90",
"data": {
"job": {
"uuid": "0b1e9a3d-6f2c-4e11-9a77-2c8f4d1b3a90",
"reference_number": "TS-482913",
"status": "pending"
},
"manual_review": {
"message": "Review Passed"
}
}
}
job.payment
The most involved webhook type — worth reading carefully. It’s sent whenever a payment is applied to, or removed from, an obligation on a job, which covers ordinary payments, chargebacks, and givebacks alike.
Overall shape: data.job is the minimal reference, and data.payment_data is always an array of payment entries — one consistent parsing contract regardless of which internal event produced the webhook. Most of the time it has exactly one entry; it can have more when a single action affects several obligations at once (for example, reversing a payment that had touched a receivable, a contractor payable, and a client advance together).
Each entry in payment_data embeds a full obligation snapshot (same shape as in job.approved, above) plus these fields:
Field | Type | Description |
|---|---|---|
| object | Full obligation snapshot — same shape as |
| string |
|
| string | What kind of payment action this is — see below. |
| integer | Amount involved, in cents. Sign and meaning depend on |
obligation_type is derived from the obligation’s type/subtype and whether its company matches the job’s company:
| Derived from |
|---|---|
| obligation |
| obligation |
| obligation |
| obligation |
payment_type tells you what happened, and which additional fields to expect alongside the ones above:
| Meaning | Additional fields |
|---|---|---|
| An ordinary payment was applied to the obligation. |
|
| A previously applied payment was reversed. | Same additional fields as |
| A chargeback was recorded against the obligation. |
|
| A giveback was recorded against the obligation. | Same additional fields as |
| A previously created chargeback was reversed. |
|
| A previously created giveback was reversed. | Same as |
One subtlety on applied_amount: for chargeback_created/giveback_created, it’s the sign-adjusted value — for example, a chargeback against a client_advance obligation carries applied_amount: -225000. For *_reverted types, applied_amount is already the fully reversal-signed value (the negation of what was originally applied).
Example: payment_unapplied touching three obligations in one reversal
Shows the array shape and all three of receivable/contractor_payable/client_advance in one payload (rebate follows the same pattern, just with subtype == "rebate"):
{
"source_event_id": "2c3d4e5f-6a7b-4c8d-9e9f-0a1b2c3d4e50",
"webhook_type": "job.payment",
"occurred_at": "2026-08-05T10:22:47Z",
"job_uuid": "0b1e9a3d-6f2c-4e11-9a77-2c8f4d1b3a90",
"data": {
"job": {
"uuid": "0b1e9a3d-6f2c-4e11-9a77-2c8f4d1b3a90",
"reference_number": "TS-482913",
"status": "approved"
},
"payment_data": [
{
"obligation": {
"uuid": "b3f2e4a1-8d3c-4a2e-9f11-7c6d5e4a3b21",
"client_debtor_relationship_id": 340,
"client_payee_relationship_id": null,
"total_amount": 285000,
"applied_amount": 285000,
"amount_due": 0,
"due_date": "2026-08-30T00:00:00Z",
"obligation_date": "2026-07-31T00:00:00Z",
"type": "receivable",
"subtype": "primary",
"payment_status": "fully_paid",
"reference_number": "INV-98213",
"company_name": "Northbound Debtor Co.",
"factor_company_name": null,
"is_express_factored": true,
"line_items": [
{ "id": 501, "type": "base_amount", "description": "Base Amount", "amount": 260000, "rate": null, "obligation_uuid": "b3f2e4a1-8d3c-4a2e-9f11-7c6d5e4a3b21" },
{ "id": 502, "type": "accessorial_fee", "description": "Detention", "amount": 25000, "rate": null, "obligation_uuid": "b3f2e4a1-8d3c-4a2e-9f11-7c6d5e4a3b21" }
]
},
"obligation_type": "receivable",
"payment_type": "payment_unapplied",
"applied_amount": 285000,
"applied_transaction_uuid": "4a5b6c7d-8e9f-4a0b-9c1d-2e3f4a5b6c70",
"transaction_uuid": "5b6c7d8e-9f0a-4b1c-9d2e-3f4a5b6c7d80",
"transaction_date": "2026-08-05T10:22:40Z",
"transaction_type": "incoming",
"obligation_company_id": 5510,
"transaction_company_id": 5510
},
{
"obligation": {
"uuid": "4c5d6e7f-8a9b-4c1d-9e2f-3a4b5c6d7e8f",
"client_debtor_relationship_id": null,
"client_payee_relationship_id": 512,
"total_amount": 235000,
"applied_amount": 235000,
"amount_due": 0,
"due_date": "2026-08-15T00:00:00Z",
"obligation_date": "2026-07-31T00:00:00Z",
"type": "payable",
"subtype": "primary",
"payment_status": "fully_paid",
"reference_number": "PO-33210",
"company_name": "Rolling Thunder Trucking",
"factor_company_name": null,
"is_express_factored": false,
"line_items": [
{ "id": 503, "type": "base_amount", "description": "Base Amount", "amount": 235000, "rate": null, "obligation_uuid": "4c5d6e7f-8a9b-4c1d-9e2f-3a4b5c6d7e8f" }
]
},
"obligation_type": "contractor_payable",
"payment_type": "payment_unapplied",
"applied_amount": 235000,
"applied_transaction_uuid": "0a1b2c3d-4e5f-4a6b-9c7d-8e9f0a1b2c30",
"transaction_uuid": "1b2c3d4e-5f6a-4b7c-9d8e-9f0a1b2c3d40",
"transaction_date": "2026-08-05T10:22:42Z",
"transaction_type": "outgoing",
"obligation_company_id": 6002,
"transaction_company_id": 6002
},
{
"obligation": {
"uuid": "7a8b9c0d-1e2f-4a3b-9c4d-5e6f7a8b9c0d",
"client_debtor_relationship_id": null,
"client_payee_relationship_id": null,
"total_amount": 225000,
"applied_amount": 225000,
"amount_due": 0,
"due_date": "2026-07-31T00:00:00Z",
"obligation_date": "2026-07-31T00:00:00Z",
"type": "payable",
"subtype": "advance",
"payment_status": "fully_paid",
"reference_number": null,
"company_name": "Summit Freight Brokers LLC",
"factor_company_name": null,
"is_express_factored": true,
"line_items": []
},
"obligation_type": "client_advance",
"payment_type": "payment_unapplied",
"applied_amount": 225000,
"applied_transaction_uuid": "7d8e9f0a-1b2c-4d3e-9f4a-5b6c7d8e9f00",
"transaction_uuid": "8e9f0a1b-2c3d-4e4f-9a5b-6c7d8e9f0a10",
"transaction_date": "2026-08-05T10:22:45Z",
"transaction_type": "outgoing",
"obligation_company_id": 4821,
"transaction_company_id": 4821
}
]
}
}
Example: chargeback_created
Shows the entry-specific fields (obligation_entry_uuid, target_company_id, description, applied_at) that appear on the chargeback/giveback family instead of the transaction fields above. A giveback_created payload looks identical aside from payment_type and obligation_type; *_reverted variants drop description, target_company_id, and applied_at, keeping only obligation_entry_uuid.
{
"source_event_id": "5a6b7c8d-9e0f-4a1b-9c2d-3e4f5a6b7c90",
"webhook_type": "job.payment",
"occurred_at": "2026-08-20T13:05:22Z",
"job_uuid": "0b1e9a3d-6f2c-4e11-9a77-2c8f4d1b3a90",
"data": {
"job": {
"uuid": "0b1e9a3d-6f2c-4e11-9a77-2c8f4d1b3a90",
"reference_number": "TS-482913",
"status": "approved"
},
"payment_data": [
{
"obligation": {
"uuid": "b3f2e4a1-8d3c-4a2e-9f11-7c6d5e4a3b21",
"client_debtor_relationship_id": 340,
"client_payee_relationship_id": null,
"total_amount": 285000,
"applied_amount": 285000,
"amount_due": 0,
"due_date": "2026-08-30T00:00:00Z",
"obligation_date": "2026-07-31T00:00:00Z",
"type": "receivable",
"subtype": "primary",
"payment_status": "fully_paid",
"reference_number": "INV-98213",
"company_name": "Northbound Debtor Co.",
"factor_company_name": null,
"is_express_factored": true,
"line_items": [
{ "id": 501, "type": "base_amount", "description": "Base Amount", "amount": 260000, "rate": null, "obligation_uuid": "b3f2e4a1-8d3c-4a2e-9f11-7c6d5e4a3b21" },
{ "id": 502, "type": "accessorial_fee", "description": "Detention", "amount": 25000, "rate": null, "obligation_uuid": "b3f2e4a1-8d3c-4a2e-9f11-7c6d5e4a3b21" }
]
},
"obligation_type": "receivable",
"payment_type": "chargeback_created",
"applied_amount": 285000,
"obligation_entry_uuid": "6b7c8d9e-0f1a-4b2c-9d3e-4f5a6b7c8d90",
"target_company_id": 4821,
"description": "Full chargeback — debtor disputed invoice, payment not received",
"applied_at": "2026-08-20T13:05:20Z"
}
]
}
}
job.audit_issue.failed / job.audit_issue.resolved
Sent for each of nine document-audit issue types we check for — job.audit_issue.failed when DocAudit flags one, and a matching job.audit_issue.resolved when that same issue is later resolved.
Overall shape: data.job is the minimal reference; data.issue carries the issue itself:
Field | Type | Description |
|---|---|---|
| string (UUID) | Identifies this specific issue — the same value on both the |
| string | One of the nine types below. |
| string |
|
| object | Full obligation snapshot — same shape as |
| object | null | Same shape as |
| string (UUID) | Identifies the audit run that produced this issue. |
| object | Issue-specific — shape depends on |
The nine issue types fall into three categories, each with its own details shape:
Mismatch (amount_mismatch, company_name_mismatch, reference_number_mismatch) — the document exists, but something on it doesn’t match what’s expected. On .failed, details has check, document_uuid, an expected_*/found_* pair specific to what’s being checked, and page_numbers. On .resolved, it has check, document_uuid, a resolved_* value, and resolution_reason.
Missing document (missing_pod_document, missing_customer_rate_con_document, missing_carrier_invoice_document) — the document doesn’t exist yet. document is null on .failed. On .failed, details is just expected_document_type; on .resolved, once it’s uploaded, details adds document_uuid and resolution_reason, and document is populated.
Miscategorized document (miscategorized_pod_document, miscategorized_customer_rate_document, miscategorized_carrier_invoice_document) — the document exists but was classified as the wrong type. On .failed, details has document_uuid, expected_document_category ("billing_paperwork" for POD/rate-con, "supporting_paperwork" for carrier invoice), expected_document_type, and found_classification. On .resolved, found_classification is replaced with resolution_reason.
Example: amount_mismatch (mismatch category)
{
"source_event_id": "5e7a2c14-3f8b-4d1a-9e6c-8b2f5a4d3c17",
"webhook_type": "job.audit_issue.failed",
"occurred_at": "2026-07-31T09:12:03Z",
"job_uuid": "0b1e9a3d-6f2c-4e11-9a77-2c8f4d1b3a90",
"data": {
"job": {
"uuid": "0b1e9a3d-6f2c-4e11-9a77-2c8f4d1b3a90",
"reference_number": "TS-482913",
"status": "approved"
},
"issue": {
"issue_uuid": "a1b2c3d4-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
"issue_type": "amount_mismatch",
"status": "action_required",
"obligation": {
"uuid": "4c5d6e7f-8a9b-4c1d-9e2f-3a4b5c6d7e8f",
"client_debtor_relationship_id": null,
"client_payee_relationship_id": 512,
"total_amount": 235000,
"applied_amount": 0,
"amount_due": 235000,
"due_date": "2026-08-15T00:00:00Z",
"obligation_date": "2026-07-31T00:00:00Z",
"type": "payable",
"subtype": "primary",
"payment_status": "expected",
"reference_number": "PO-33210",
"company_name": "Rolling Thunder Trucking",
"factor_company_name": null,
"is_express_factored": false,
"line_items": [
{ "id": 503, "type": "base_amount", "description": "Base Amount", "amount": 235000, "rate": null, "obligation_uuid": "4c5d6e7f-8a9b-4c1d-9e2f-3a4b5c6d7e8f" }
]
},
"document": {
"uuid": "3c4d5e6f-7a8b-4c9d-0e1f-2a3b4c5d6e7f",
"file_name": "rate_con_TS-482913.pdf",
"type": "customer_rate_con",
"subtype": null,
"inserted_at": "2026-07-30T12:00:00Z",
"url": "https://link-to-gcp-file.gcp.com"
},
"audit_result_uuid": "d4e5f6a7-8b9c-4d1e-9f2a-3b4c5d6e7f80",
"details": {
"check": "total_amount_check",
"document_uuid": "3c4d5e6f-7a8b-4c9d-0e1f-2a3b4c5d6e7f",
"expected_amount": 235000,
"found_amount": 228500,
"page_numbers": [2]
}
}
}
}
{
"source_event_id": "6f8b3d25-4a9c-4e2b-9f7d-9c3a6b5e4d28",
"webhook_type": "job.audit_issue.resolved",
"occurred_at": "2026-08-01T10:45:12Z",
"job_uuid": "0b1e9a3d-6f2c-4e11-9a77-2c8f4d1b3a90",
"data": {
"job": {
"uuid": "0b1e9a3d-6f2c-4e11-9a77-2c8f4d1b3a90",
"reference_number": "TS-482913",
"status": "approved"
},
"issue": {
"issue_uuid": "a1b2c3d4-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
"issue_type": "amount_mismatch",
"status": "resolved",
"obligation": {
"uuid": "4c5d6e7f-8a9b-4c1d-9e2f-3a4b5c6d7e8f",
"client_debtor_relationship_id": null,
"client_payee_relationship_id": 512,
"total_amount": 235000,
"applied_amount": 0,
"amount_due": 235000,
"due_date": "2026-08-15T00:00:00Z",
"obligation_date": "2026-07-31T00:00:00Z",
"type": "payable",
"subtype": "primary",
"payment_status": "expected",
"reference_number": "PO-33210",
"company_name": "Rolling Thunder Trucking",
"factor_company_name": null,
"is_express_factored": false,
"line_items": [
{ "id": 503, "type": "base_amount", "description": "Base Amount", "amount": 235000, "rate": null, "obligation_uuid": "4c5d6e7f-8a9b-4c1d-9e2f-3a4b5c6d7e8f" }
]
},
"document": {
"uuid": "4d5e6f7a-8b9c-4d0e-9f1a-2b3c4d5e6f7a",
"file_name": "rate_con_TS-482913.pdf",
"type": "customer_rate_con",
"subtype": null,
"inserted_at": "2026-07-30T12:00:00Z",
"url": "https://link-to-gcp-file.gcp.com"
},
"audit_result_uuid": "e5f6a7b8-9c0d-4e2f-9a3b-4c5d6e7f8a91",
"details": {
"check": "total_amount_check",
"document_uuid": "4d5e6f7a-8b9c-4d0e-9f1a-2b3c4d5e6f7a",
"resolved_amount": 235000,
"resolution_reason": "document_reaudited"
}
}
}
}
Example: missing_pod_document (missing document category)
Note "document": null on the .failed event — the document doesn’t exist yet, so there’s nothing to reference until it’s uploaded and the issue resolves.
{
"source_event_id": "9f3d1a2b-6c4e-4f8a-9b2d-1e3c5a7f9d40",
"webhook_type": "job.audit_issue.failed",
"occurred_at": "2026-07-31T09:12:03Z",
"job_uuid": "0b1e9a3d-6f2c-4e11-9a77-2c8f4d1b3a90",
"data": {
"job": {
"uuid": "0b1e9a3d-6f2c-4e11-9a77-2c8f4d1b3a90",
"reference_number": "TS-482913",
"status": "approved"
},
"issue": {
"issue_uuid": "b2c3d4e5-6f7a-4b8c-9d0e-1f2a3b4c5d6e",
"issue_type": "missing_pod_document",
"status": "action_required",
"obligation": {
"uuid": "4c5d6e7f-8a9b-4c1d-9e2f-3a4b5c6d7e8f",
"client_debtor_relationship_id": null,
"client_payee_relationship_id": 512,
"total_amount": 235000,
"applied_amount": 0,
"amount_due": 235000,
"due_date": "2026-08-15T00:00:00Z",
"obligation_date": "2026-07-31T00:00:00Z",
"type": "payable",
"subtype": "primary",
"payment_status": "expected",
"reference_number": "PO-33210",
"company_name": "Rolling Thunder Trucking",
"factor_company_name": null,
"is_express_factored": false,
"line_items": [
{ "id": 503, "type": "base_amount", "description": "Base Amount", "amount": 235000, "rate": null, "obligation_uuid": "4c5d6e7f-8a9b-4c1d-9e2f-3a4b5c6d7e8f" }
]
},
"document": null,
"audit_result_uuid": "d4e5f6a7-8b9c-4d1e-9f2a-3b4c5d6e7f80",
"details": {
"expected_document_type": "pod"
}
}
}
}
{
"source_event_id": "0a1b2c3d-4e5f-4a6b-9c7d-8e9f0a1b2c30",
"webhook_type": "job.audit_issue.resolved",
"occurred_at": "2026-08-01T11:02:47Z",
"job_uuid": "0b1e9a3d-6f2c-4e11-9a77-2c8f4d1b3a90",
"data": {
"job": {
"uuid": "0b1e9a3d-6f2c-4e11-9a77-2c8f4d1b3a90",
"reference_number": "TS-482913",
"status": "approved"
},
"issue": {
"issue_uuid": "b2c3d4e5-6f7a-4b8c-9d0e-1f2a3b4c5d6e",
"issue_type": "missing_pod_document",
"status": "resolved",
"obligation": {
"uuid": "4c5d6e7f-8a9b-4c1d-9e2f-3a4b5c6d7e8f",
"client_debtor_relationship_id": null,
"client_payee_relationship_id": 512,
"total_amount": 235000,
"applied_amount": 0,
"amount_due": 235000,
"due_date": "2026-08-15T00:00:00Z",
"obligation_date": "2026-07-31T00:00:00Z",
"type": "payable",
"subtype": "primary",
"payment_status": "expected",
"reference_number": "PO-33210",
"company_name": "Rolling Thunder Trucking",
"factor_company_name": null,
"is_express_factored": false,
"line_items": [
{ "id": 503, "type": "base_amount", "description": "Base Amount", "amount": 235000, "rate": null, "obligation_uuid": "4c5d6e7f-8a9b-4c1d-9e2f-3a4b5c6d7e8f" }
]
},
"document": {
"uuid": "2c3d4e5f-6a7b-4c8d-9e0f-1a2b3c4d5e60",
"file_name": "pod_TS-482913.pdf",
"type": "pod",
"subtype": null,
"inserted_at": "2026-07-30T12:00:00Z",
"url": "https://link-to-gcp-file.gcp.com"
},
"audit_result_uuid": "1b2c3d4e-5f6a-4b7c-9d8e-9f0a1b2c3d40",
"details": {
"expected_document_type": "pod",
"document_uuid": "2c3d4e5f-6a7b-4c8d-9e0f-1a2b3c4d5e60",
"resolution_reason": "document_uploaded"
}
}
}
}