Webhooks and events
A developer adds an endpoint with their own sign-in (webhooks.create); the secret is shown once. Deliveries are POSTs with DW-Signature: t=<unix seconds>,v1=<hex HMAC-SHA256 of t.body>. Any non-2xx is retried with backoff. Delivery is at least once, so dedupe on the event id.
| Event | What happened |
|---|---|
shop.created | A shop was created. |
membership.invited | A person was invited to a shop. |
membership.role_changed | A worker's role in a shop changed. The old membership ended and a new one started. |
quote.revised | An unsigned quote was replaced by a new version. |
quote.withdrawn | The shop took back an unsigned quote; its signing links stopped working. |
charge.succeeded | A payment succeeded. |
dispute.closed | A payment dispute closed (won, lost or closed). |
plan.changed | A shop changed plan. |
subcontractor_list.signed | A shop signed the Idaho 45-525(3) subcontractor list for a job. |
subcontractor_list.prepared | An agent prepared the Idaho 45-525(3) subcontractor list for a person to sign. |
plan.change_scheduled | A shop scheduled a move down; it starts on the first day of effective_period (shop time). |
fee.owed_to_shop | A fee that was credited against a plan price is owed back to the shop after a refund or lost dispute. |
plan.billed | Not sent. Doing Work has no plans or monthly fee; kept so old subscriptions stay valid. |
membership.started | A person joined a shop. |
membership.ended | A person's membership in a shop ended. |
membership.permissions_changed | The owner changed what a worker may do: see_prices, see_costs, take_money, delete and manage_schedule. |
ownership.transfer_started | The owner started handing the shop to someone else. |
ownership.transferred | Shop ownership moved to a new owner. |
ownership.transfer_cancelled | An open hand-off was stopped: the owner cancelled it or the person asked declined. |
shop.closed | The owner closed the shop. Everyone lost access and every link stopped; records are kept. |
job_subcontractor.added | A subcontractor was added to a job. |
job_subcontractor.updated | A subcontractor's contact name, trade or scope note changed. |
job_subcontractor.removed | A subcontractor was taken off a job; their link stopped. |
job_subcontractor.joined | A subcontractor opened their link for the first time, signed in. |
job_subcontractor.note_added | A subcontractor left a note on a job. |
recovery.opened | Someone asked to take over a shop whose owner cannot be reached. |
recovery.decided | A recovery request was decided. |
home.claimed | A person claimed a home. |
home_role.ended | A person's role at a home ended. |
job.created | A job was started at a home. |
job.completed | A job was marked done with jobs.complete (W2). override_id is set when the owner overrode open checklist work. |
media.uploaded | A photo was added to a job. |
media.tagged | Tags on a photo changed. |
photo_share.created | A share link for job photos was made. It expires on its own and can be revoked. |
photo_share.revoked | A photo share link was turned off before it expired. |
daily_log.added | A worker wrote a daily log entry on a job. |
daily_log.removed | A daily log entry was taken out (it stays in history). |
job_document.created | Core rendered a PDF for a job (photo report or daily log) and stored it with its sha256. |
signature.requested | A shop asked someone to sign a document (contract text or a stored job PDF) on a hosted page. |
signature.link_issued | A new signing link was made for an open signature request; earlier links stopped working. |
signature.cancelled | An open signature request was cancelled. |
document.signed | A person signed a document on a hosted page. The signature holds the document sha256, the consent text and its sha256. |
change_order.created | A change order was written on a job (draft). |
change_order.sent | A change order was sent to the customer to approve by signing. |
change_order.approved | The customer signed a change order; it now counts toward the job's revised total. |
change_order.cancelled | A draft or sent change order was cancelled. |
change_order.invoiced | An approved change order was billed on an invoice. |
note.added | A note or voice memo transcript was added on a job. |
note.updated | A note's words, photos, pin or audience changed. |
note.removed | A note was taken off its job (kept in history). |
report.saved | A saved report was made or changed (R3). |
report.removed | A saved report was removed (R3). |
message_template.saved | A customer message template was set (H2). |
message_template.reset | A customer message template went back to the built-in wording (H2). |
customer.unsubscribed | A customer used the unsubscribe link in a review request email; the address is on the shop's do-not-email list. |
shop.hub_link_in_emails_changed | The owner turned the customer hub link in quote and invoice emails on or off. |
shop.reopened | The owner reopened the shop within 90 days of closing it. |
shop.purged | 90 days after closing, working data the shop no longer needs was deleted. Money, tax, signature and job records are kept. |
shop.field_costs_changed | The owner let field workers see job costs, or hid them again. |
shop.contact_changed | The owner changed the phone or email shown on canceled invoice and quote links. |
hub_link.created | A customer hub link was made (H2). |
hub_link.revoked | A customer hub link was revoked (H2). |
visit_change.requested | A customer asked from their hub to move or cancel a visit (H2). |
visit_change.withdrawn | A customer took back their request to move or cancel a visit (H2). |
visit_change.answered | The shop accepted or declined a customer's request to move or cancel a visit (H2). |
form_template.saved | A form template was created or replaced. |
form_template.archived | A form template was archived. |
form.started | A form was started on a job or one visit (a draft). |
form.updated | Answers were saved on a draft form. |
form.submitted | A form was submitted: its PDF is stored on the job and the form is final. |
form.cancelled | A draft form was cancelled (kept in history). |
time.clocked_in | A person's clock started (work on a job, drive, shop or break). |
time.clocked_out | A running clock stopped; the time waits for approval. |
time.added | Time was added after the fact (a manual entry); it waits for approval. |
time.edited | A time entry that was not approved was fixed. |
time.approved | The owner or office approved a time entry; it is locked. |
time.rejected | The owner or office rejected a time entry; the worker can fix it. |
time.voided | A time entry that was never approved was taken back. |
time.reopened | The owner reopened approved time so it can be fixed. |
labor_rate.set | A labor cost rate was set for a worker or the shop default (the amount is not in the event). |
material.added | A material used was recorded on a job. |
material.updated | A recorded material's quantity, visit or notes changed. |
material.removed | A recorded material was removed (kept in history). |
checklist_template.saved | A checklist template was created or replaced. |
checklist_template.archived | A checklist template was archived. |
checklist.created | A checklist was put on a job or on one visit. |
checklist.items_added | Items were added to a checklist. |
checklist.item_checked | A checklist item was ticked or unticked. |
checklist.item_removed | A checklist item was removed (kept in history, audited). |
checklist.overridden | The owner marked a visit or job done with checklist work left. The reason and the open items are in the audit log. |
expense.added | A worker recorded an expense on a job (amount typed by the worker). |
expense.updated | An expense was changed. |
expense.removed | An expense was taken off the books (kept in history). |
approval_rule.set | The owner required approval before agents run an action. |
approval_rule.removed | The owner dropped an approval rule. |
approval.requested | An agent action is waiting for the owner's approval. |
approval.decided | The owner approved or denied a held agent action. |
media.markup_saved | A new markup layer was saved over a photo. The photo itself is unchanged. |
customer.created | A customer was added to a shop. |
quote.created | A quote was written. |
quote.sent | A quote was locked and sent for signing. |
quote.signed | The customer signed a quote. |
pricebook.item_saved | A price book item was added, changed, archived or brought back. |
quote_template.saved | A quote template was saved, archived or brought back. |
quote.declined | The customer declined a quote on the sign page. |
quote.change_requested | The customer asked for changes to a quote. The quote is back to draft; read the note with quotes.activity. |
quote.viewed | The customer opened a sent quote version for the first time. |
quote.followup_queued | A follow-up email was queued for a quote the customer has not answered. |
shop.quote_followup_changed | The owner changed the quote follow-up delay. |
quote.choice_signed | The customer signed a quote with options or optional lines. Says which option and optional lines they picked and the total. |
shop.tax_report_basis_changed | The owner chose how the sales tax report counts a period (accrual or cash). |
maintenance_plan.tax_changed | The office changed the tax rate a maintenance plan charges from the next term. |
shop.tips_changed | The owner turned tips on or off on the pay page. |
shop.review_request_changed | The owner changed the review link or the review email delay. |
review.request_queued | A review request email was queued for a customer whose invoice was paid. |
card.saved | A customer saved a card on the shop's payment account. |
card.removed | A customer's saved card was removed. |
customer.autopay_changed | Auto-pay was turned on or off for a customer. |
invoice.autopay_started | An invoice was charged to the customer's saved card. invoice.paid follows when the charge succeeds. |
invoice.autopay_failed | An auto-pay charge failed. The invoice stays open. |
tax_rate.saved | A tax rate was added, replaced or archived. A replaced rate is archived and a new one takes its place. |
quote.attachment_added | A photo or file was shown with a quote. |
quote.attachment_removed | A photo or file was taken off a quote. |
maintenance_plan.created | A maintenance plan was started. Its first term's invoice was created. |
maintenance_plan.price_changed | A worker changed a maintenance plan's price. It applies from the next term. |
maintenance_plan.cancelled | A maintenance plan was cancelled. No more renewal invoices. |
maintenance_plan.renewed | A maintenance plan started its next term and that term's invoice was created (and sent when auto_send is on). |
invoice.created | An invoice was created. |
invoice.batch_created | Many invoices were created at once, and maybe sent. |
invoice.sent | An invoice was sent for payment. |
invoice.payment_pending | A bank payment was started and is clearing. The invoice is not paid yet. |
invoice.payment_failed | A bank payment failed after it was started. The payer can pay again. |
invoice.paid | An invoice was paid. |
invoice.paid_outside | The shop recorded an invoice as paid outside Doing Work (check, cash, financing, insurance or other). The job record says so and is never marked paid or verified. |
invoice.voided | The shop voided an invoice nobody had paid (X3). Its pay links stop working; the reason is included. |
charge.needs_refund | Money arrived that the shop must give back (a paid-twice or void invoice). |
charge.refunded | A payment was refunded. |
dispute.opened | A payment was disputed. |
processor_account.updated | The shop's payment setup changed. |
record.levelled | A job record reached a new level (logged, paid, verified). |
confirmation.created | The customer confirmed a job. |
grant.created | Access was granted. |
grant.revoked | Access was revoked. |
field_value.set | A custom field value was set. |
field_definition.created | A shop added a custom field. |
customer.updated | A customer's details, contacts, properties or archive state changed. |
customer.merged | A duplicate customer was merged into another. |
customer.erased | A customer's personal details were erased for a privacy request. |
equipment.changed | Equipment at a property was added, changed or archived. |
job.updated | A job's tags or lead source changed. |
request.created | A request for work came in. |
request.updated | A request changed stage or details. |
request.converted | A request became a job. |
visit.scheduled | A visit to a job was booked. |
visit.updated | A visit moved or its details changed. |
visit.assigned | The workers on a visit changed. |
visit.cancelled | A visit was cancelled. |
visit.started | A worker started a visit. |
visit.done | A visit was marked done. |
visit.series_created | A repeating set of visits was booked. |
availability.changed | A worker's weekly hours or time off changed. |
visit.on_the_way | A worker is on the way to a visit, with an ETA when given. |
visit.arrived | A worker arrived at a visit. |
visit.notice_queued | A customer notice for a visit (appointment reminder or on my way) was handed to email. |
schedule.hours_changed | The shop's booking hours changed. |
schedule.settings_changed | The shop's scheduling rules changed (arrival window, buffer, reminders, on-my-way notices, time zone). |
invoice.pay_link_ready_queued | One email was queued telling the customer an invoice can be paid again after its pay link waited on the shop's payments account. |
signature.copy_queued | One email was queued giving a signer their own copy of what they signed (a document, a quote or a subcontractor list). |
card.resave_queued | One email was queued asking a customer to save their card again after the shop's payments account changed. |
invoice.reminder_queued | A friendly reminder was queued for an invoice still unpaid a day after it was sent. |
shop.invoice_reminders_changed | The owner turned the automatic unpaid-invoice reminder on or off for the shop. |
invoice.reminder_changed | The automatic unpaid reminder was turned on or off for one invoice. |
request_form.created | A shop turned on or renewed its public request form. |
webhook_endpoint.created | A webhook endpoint was added. |
webhook_endpoint.deleted | A webhook endpoint was removed. |
webhook_delivery.retried | An owner or office worker queued a failed webhook delivery to send again. |
webhook_endpoint.creator_left | The worker who added a webhook endpoint left the shop. The endpoint keeps running; the owner can keep it or remove it. |
agent_key.created | The owner made a named agent key for the shop. |
agent_key.revoked | The owner revoked a named agent key. It stops working at once. |
platform.created | A developer platform account was created. |