Skip to content

Developers

Record lifecycle

A record is one wait billed as a charge. These are the statuses it moves through, what moves it from one to the next, and the webhook each move sends.

On this page

Statuses

A record's status is one of these. Carriers see every status; a fuel buyer's key sees a record only once it was sent to them. New statuses may be added, so treat one you don't know as still in progress.

StatusWhat it meansFinalBuyer sees it
recordingRecordingThe driver's clock is running: the wait is in progress (carriers only).NoNo
draftDraftThe clock stopped; the driver hasn't submitted the record yet (carriers only).NoNo
pending_reviewCarrier ReviewWaiting for the carrier's review before it goes to the fuel buyer (carriers only).NoNo
rejected_by_employerRejected by CarrierThe carrier's review rejected its driver's record. It's never billed; the carrier can reopen it (carriers only).NoNo
sent_to_customerAwaiting CustomerWith the fuel buyer, to approve or dispute.NoYes
disputedDisputedThe buyer disputed it. The carrier corrects and resends it, accepts the buyer's offer, escalates, or closes it.NoYes
escalatedEscalatedThe carrier escalated the dispute. The buyer approves or closes it.NoYes
customer_approvedApprovedThe buyer approved it: it's owed (amount_approved). Unpaid until a payment completes.NoYes
payment_pendingPayment PendingA payment is on its way: a bank payment is processing, or the buyer marked it paid outside Demurly and the carrier hasn't confirmed it.NoYes
paid_stripePaidPaid through Demurly (card or bank). Final, unless the payment is refunded or lost to a chargeback, which puts it back to customer_approved.YesYes
paid_externalPaid (Outside Demurly)Paid outside Demurly, confirmed by the carrier or its accounting system. Final.YesYes
cancelledCancelledThe carrier cancelled it before the buyer answered. Final; never billed.YesNo
closedClosedA dispute ended without payment. Final.YesYes

Diagram

Record lifecycleA record goes from recording to draft, pending_review, sent_to_customer, customer_approved, payment_pending and paid. From pending_review the carrier can reject it (rejected_by_employer) and reopen it. A buyer can dispute a sent record; a dispute goes back to the buyer when the carrier resends it, or to customer_approved, escalated or closed. Payments can fail back to customer_approved, and a card payment can be reversed. Records can be cancelled until the buyer answers. The table below lists every move.recordingRecordingdraftDraftpending_reviewCarrier Reviewrejected_by_employerRejected by Carriersent_to_customerAwaiting CustomerdisputedDisputedcustomer_approvedApprovedescalatedEscalatedpayment_pendingPayment PendingclosedClosed (final)paid_stripePaid (final)paid_externalPaid (Outside Demurly) (final)cancelledCancelled (final)
Solid arrows move a record forward; dashed copper arrows move it back. Bold boxes are final. A record marked × can be cancelled by the carrier, which makes it cancelled. Imported past records go straight from draft to closed or paid_external.

What moves a record

Each move is an event in the record's history (its type is the first column) and sends the webhook in the last column to every endpoint subscribed to it. Moves marked with an endpoint can be made through the API; the rest happen in the web app, the driver app, or by themselves.

  • (new record)torecording

    A driver starts the clock in the driver app; a reported wait (API, EDI 214, import) is created and passes straight through to pending_review

    Event record_createdWebhook record.createdAPI POST /api/v1/records

  • recordingtodraft

    The driver stops the clock, or it stops itself (the truck drove off); a reported wait stops at its end_time

    Event gps_tracking_stoppedWebhook record.stoppedAPI POST /api/v1/records

  • drafttopending_review

    The driver submits it for review; a reported wait is submitted at once

    Event record_submittedWebhook record.submittedAPI POST /api/v1/records

  • pending_reviewtorejected_by_employer

    A carrier admin rejects the driver's record in review (web app)

    Event employer_rejectedWebhook record.rejected_internal

  • rejected_by_employertopending_review

    A carrier admin takes a review rejection back (web app)

    Event record_reopenedWebhook record.reopened

  • pending_review | disputedtosent_to_customer

    The carrier sends it to the fuel buyer, or resends it after correcting a disputed charge (send: true on create does it in the same call)

    Event record_sent_to_customerWebhook record.sentAPI POST /api/v1/records/{id}/send

  • disputedtosent_to_customer

    The carrier accepts the buyer's counter-offer from a dispute: back to the buyer at that amount (web app)

    Event dispute_offer_acceptedWebhook record.offer_accepted

  • sent_to_customer | disputed | escalatedtocustomer_approved

    The fuel buyer approves it (API, web app, or an emailed review link)

    Event record_approvedWebhook record.approvedAPI POST /api/v1/records/{id}/approve

  • sent_to_customer | disputed | escalatedtocustomer_approved

    The fuel buyer approves a lower amount (web app)

    Event record_partially_approvedWebhook record.approved

  • sent_to_customertodisputed

    The fuel buyer rejects it (the older form of a dispute)

    Event record_rejectedWebhook record.disputed

  • sent_to_customertodisputed

    The fuel buyer disputes it with a reason (API, web app, or an emailed review link)

    Event record_disputedWebhook record.disputedAPI POST /api/v1/records/{id}/dispute

  • disputedtoescalated

    The carrier escalates the dispute (web app)

    Event record_escalatedWebhook record.escalated

  • disputedtoescalated

    The carrier escalates the dispute (web app)

    Event dispute_escalatedWebhook none

  • disputed | escalatedtoclosed

    The carrier accepts the buyer's dispute, or the buyer rejects an escalated charge (web app): closed unpaid

    Event record_closedWebhook record.closed

  • drafttoclosed

    A past record from the carrier's spreadsheet import lands closed, or paid outside Demurly when its row says so

    Event record_importedWebhook none

  • drafttopaid_external

    A past record from the carrier's spreadsheet import lands closed, or paid outside Demurly when its row says so

    Event record_importedWebhook none

  • recording | draft | pending_review | sent_to_customertocancelled

    A carrier admin cancels it, before the buyer has answered (web app)

    Event record_cancelledWebhook record.cancelled

  • customer_approvedtopayment_pending

    The buyer starts a bank payment in Demurly, or hands it to its accounts payable

    Event payment_processingWebhook record.payment_pending

  • payment_pendingtocustomer_approved

    A payment fails: the record is approved and unpaid again

    Event payment_failedWebhook record.payment_failed

  • customer_approved | payment_pendingtopaid_stripe

    A card or bank payment through Demurly completes

    Event payment_completedWebhook record.paid

  • customer_approvedtopayment_pending

    The buyer marks it paid outside Demurly (web app, or its accounting system's bill was paid)

    Event external_payment_markedWebhook record.payment_pending

  • customer_approved | payment_pendingtopaid_external

    The carrier confirms the outside payment arrived

    Event external_payment_confirmedWebhook record.paid

  • customer_approvedtopaid_external

    The carrier records an outside payment, or its accounting system shows the invoice paid

    Event external_payment_recordedWebhook record.paid

  • payment_pendingtocustomer_approved

    The carrier says the outside payment never arrived

    Event external_payment_rejectedWebhook record.payment_failed

  • paid_stripetocustomer_approved

    A card payment is fully refunded or lost to a chargeback

    Event payment_reversedWebhook record.payment_reversed

Some webhooks don't follow a status change: record.withdrawn (a charge you were sent was sent to another buyer or taken back for review by the carrier; data.record is the tombstone the API shows you (buyers only)), record.updated (a record's details or billed times changed (a field edit, or times adjusted, which changes the amount); data.event.type says which) and record.comment_added (someone on the carrier or the buyer side commented on a record).

A wait reported through POST /api/v1/records runs its first moves in one call: it's created, stopped at its end_time, calculated and submitted, so a carrier's endpoint gets record.created, record.stopped and record.submitted (and record.sent with send: true).

Owed or paid?

For an accounts payable or receivable system, group the statuses like this:

  • Owed (approved, not paid yet): customer_approved, payment_pending. Use amount_approved.
  • Waiting for the buyer: sent_to_customer; in dispute: disputed, escalated.
  • Paid: paid_stripe, paid_external (paid_at). A card payment can still be reversed, which brings the record back to customer_approved with a record.payment_reversed webhook.
  • Never billed: cancelled, closed, rejected_by_employer, and a buyer's tombstones (below).

Withdrawn charges

A charge a fuel buyer was sent never just disappears from the buyer's view. If the carrier cancels it, sends it to another buyer or takes it back for review, the buyer's key gets a tombstone in its place: status: "withdrawn" with withdrawn_reason and withdrawn_at (the record tombstone object). withdrawn isn't one of the record's statuses: it's what that buyer sees. The buyer gets record.withdrawn (or record.cancelled for a cancellation). If the charge is sent back to them, it's an ordinary record again.

History event types

GET /api/v1/records/{id} with include=events lists a record's history, oldest first; a webhook names the event behind it in data.event.type. These are the types. New ones may be added.

TypeWhat happenedWebhook
record_createdThe record was made (a driver started the clock, or a wait was reported)record.created
gps_point_capturedA GPS point from the driver's phone (not listed by the API; summarized in gps_evidence)none
gps_tracking_stoppedThe clock stoppedrecord.stopped
photo_capturedThe driver took a photo during the waitnone
document_attachedA photo or document was attached (for example through the photos endpoint)none
attachment_replacedAn attachment was replaced before the record was sentnone
field_updatedA detail changed (load or BOL number, terminal, customer...): data.field and data.valuerecord.updated
field_correctedThe carrier corrected a detail in review or in answer to a disputerecord.updated
record_submittedSubmitted for the carrier's reviewrecord.submitted
record_reviewedThe carrier marked it reviewed (no status change)none
record_sent_to_customerSent to the fuel buyer (again, after a dispute, with resubmission and the carrier's message)record.sent
record_approvedThe buyer approved it (data.approvedAmount; isGuestApproval and guestEmail when approved from an emailed link)record.approved
record_partially_approvedThe buyer approved a lower amountrecord.approved
record_rejectedThe buyer rejected it (older form of a dispute)record.disputed
record_escalatedThe carrier escalated a disputerecord.escalated
record_closedA dispute ended without paymentrecord.closed
record_cancelledThe carrier cancelled itrecord.cancelled
payment_initiatedA payment was started (no status change)none
payment_completedA payment through Demurly completedrecord.paid
payment_failedA payment failed (data.method, failureCode, failureMessage in webhooks)record.payment_failed
external_payment_markedMarked paid outside Demurly (data.method, reference, paid_on)record.payment_pending
external_payment_confirmedThe carrier confirmed an outside paymentrecord.paid
comment_addedSomeone commented (data.comment)record.comment_added
calculation_performedThe charge was calculated (data.amount, total_minutes, billable_minutes, hourly_rate)none
rate_alert_triggeredThe rate is outside what the buyer expects (a warning, no status change)none
geofence_alert_triggeredThe driver's position left the terminal's geofence (a warning)none
conflict_resolvedAn edit conflict was resolvednone
time_drift_alertThe phone's clock was off from Demurly's (a warning)none
record_disputedThe buyer disputed it (data.reason, disputeType, proposedAmount)record.disputed
employer_rejectedThe carrier's review rejected its driver's recordrecord.rejected_internal
payment_processingA bank payment is processing, or it was handed to accounts payablerecord.payment_pending
record_importedImported from the carrier's spreadsheet of past recordsnone
external_payment_rejectedThe carrier said an outside payment never arrived (data.note)record.payment_failed
payment_reversedA card payment was refunded or lost to a chargebackrecord.payment_reversed
time_adjustedThe carrier adjusted the billed times in answer to a dispute (adjusted_start_time, adjusted_end_time, reason, previous_amount)record.updated
record_reopenedThe carrier took a review rejection backrecord.reopened
photo_removedThe driver removed a photo while recordingnone
dispute_offer_acceptedThe carrier accepted the buyer's counter-offerrecord.offer_accepted
NextWebhooksEvent payloads, verifying signatures, retries and delivery rules.
Record lifecycle