auth_requestLink
Email a one-time sign-in link. Always answers ok, so it never reveals whether an email has an account.
emailrequired
work.doingworkPublished by doingwork.workOfficial publisherv1.0.1Updated Nov 3, 2026
Headless field service software. Your AI agent runs jobs, schedules, quotes, invoices and payments.
The publisher's own server: Home Service Quotes by Doing Work
Field Service Business Platform by Doing Work's hosted MCP server (doingwork.work), published by doingwork.work; no sign-in required; Streamable HTTP; 200 tools.
No AI overview yet: these facts come from the registry entry and the server itself.
Web executable via Streamable HTTP. Remote servers run from the web runtime once configured in a workspace.
Paste this prompt into Claude Code, Codex, Cursor or another agent — or into SourceWeft chat. The agent reads this server's install guide, shows you its publisher, endpoint and sign-in, and adds it to your client once you agree. Keys never go into a command.
Read https://sourceweft.com/mcp/work.doingwork%2Fshop/install.md and connect the MCP server it describes to my client. Before changing any config, show me its publisher, endpoint and sign-in method and wait for my OK. Never put an API key in a command or in a file I would commit; ask me where it should come from.Add this to your client's mcpServers config.
{
"mcpServers": {
"field-service-business-platform-by-doing": {
"type": "http",
"url": "https://doingwork.work/mcp"
}
}
}Email a one-time sign-in link. Always answers ok, so it never reveals whether an email has an account.
emailrequiredEmail a person a one-time sign-in link that opens a named Doing Work screen after they sign in, so an agent can hand its person straight to the page that needs a human (brand, terms, job photos and so on). The screen comes from a fixed list: today, prices, brand, payments, resume, terms, transfer, close, capture, subcontractors, claim, card, hub, board, override, start. Shop screens take shop_id; capture and subcontractors take job_id; claim is refused here, because the agent connect flow sends its own link; board takes shop_id and an optional date; override takes kind (job or visit) and id; card and hub take the key from their link. To send a page to a named member of your shop with role and assignment checks, use members.sendPage. The link works once, in any browser, and expires in 15 minutes. Always answers ok, so it never reveals whether an email has an account. The page still checks that the person may see it.
emailrequiredparamsscreenrequiredRegister an OAuth client (RFC 7591 dynamic registration). Public clients only: PKCE, no secret. Redirects must be https, or http on loopback.
scopetos_uricontactslogo_uriclient_uripolicy_uriclient_namegrant_typessoftware_idredirect_urisrequiredresponse_typessoftware_version+1 moreA signed-in person approves an agent client. Returns the redirect with a one-time code (PKCE S256). Needs a browser session, not an agent token. `resource` (RFC 8707) binds the token to this server's MCP endpoint.
scopestateshop_idresourceclient_idrequiredredirect_urirequiredresponse_typecode_challengerequiredcode_challenge_methodrequiredExchange an authorization code and PKCE verifier, or a refresh token, for a short-lived agent access token and a new refresh token. Refresh tokens rotate: each works once, and reusing one revokes the whole chain. With grant_type urn:workos:agent-auth:grant-type:claim and your claim_token (auth.md), poll until the owner approves: errors are authorization_pending, slow_down, expired_token and access_denied; success hands over a named agent key once (no refresh token, it does not expire until revoked).
codescoperesourceclient_idgrant_typerequiredclaim_tokenredirect_uricode_verifierrefresh_tokenThe signed-in person.
Takes no parameters.
Create a shop. The caller becomes its one owner. On the sign-up page the person also agrees to the Terms of Service (accept_terms_version), recorded with the version, time, IP address and browser; an agent cannot agree for them.
namerequiredjurisdictionrequiredaccept_terms_versionInvite a person by email as office or field. Owners and office can invite. The invite link works once.
rolerequiredemailrequiredshop_idrequiredEmail an open invite again with a new link, for a worker or office member who lost it or let it expire. The old invite is revoked and a new one is made with the same email and role: use the invite_id this returns from now on. The new link works once for 14 days. Owners and office only. Accepted or revoked invites are refused.
invite_idrequiredEmail a current member of your shop a one-time sign-in link that opens one page: board (the day board, for owner or office), override (mark a job or visit done anyway, owner only), or capture (job photos, for anyone on the job; a field worker must be assigned to a visit on it). Owners and office only. The member is named by membership_id, so the link only goes to someone in the shop. The link works once and expires in 15 minutes. The page still checks access when it opens.
paramsscreenrequiredshop_idrequiredmembership_idrequiredAccept an invite as the signed-in person. The invite email must match yours.
tokenrequiredCurrent members of a shop with role and start date.
shop_idrequiredinclude_endedEnd a membership: the owner removes a worker, or a worker leaves. Shop tokens end with it. The owner cannot leave; ownership moves only by transfer.
membership_idrequiredOwner changes a worker between office and field. The old membership ends and a new one starts, so history keeps both.
rolerequiredmembership_idrequiredStart a job at a home (the home is found or created from the address).
addressrequiredshop_idrequiredsummarycustomer_idJobs of a shop, newest first. Optional status filter.
limitstatusshop_idrequiredOne job with its home address.
job_idrequiredGet a signed upload URL for a job photo or video. Before you call this, look at the file and say what it shows in summary: plain words, findings, any text you can read (model and serial plates), measurements, and for video a transcript, key moments and the length. If you cannot look at it, send summary.unable_to_analyze with a reason and the media is listed by media.needsSummary. Summaries stay inside the shop and are searchable with media.list q and search.global. Photos: JPEG, PNG, WebP, HEIC or TIFF (HEIC and TIFF are kept as sent, with a JPEG copy for viewing). Video: MP4, MOV or WebM, kept as sent, at most 100 MB and 10 minutes, never shared outside the shop. Declare the sha256 of the bytes you will send; the upload is rejected if they differ. Taken time, GPS location, heading and camera details are read from photos and kept for your shop. Copies shared outside the shop (share links, quote pages, PDFs) have that metadata removed.
kindstagerequiredjob_idrequiredsha256requiredsummaryrequiredshows_interiorList the photos and videos you are allowed to see, with what the agent said each shows (summary), taken time, GPS location, heading and camera details. Filter by job, kind, words in the summary or transcript (q), summary status, distance from a point, taken time, or whether it has a location.
qkindsortlimitjob_idshop_idnear_latnear_lngradius_mtaken_afterhas_locationtaken_before+1 morePhotos with a GPS location as a GeoJSON FeatureCollection (points in longitude, latitude order), ready for a map. Takes the same filters as media.list.
qkindsortlimitjob_idshop_idnear_latnear_lngradius_mtaken_afterhas_locationtaken_before+1 moreOne photo or video's details, including its full summary (findings, readable text, measurements, transcript and key moments), taken time, location, camera fields and the full metadata read from the file. Set include_content to get the stored bytes as base64 (metadata included), or include_original to get the original HEIC or TIFF when the photo was converted.
media_idrequiredinclude_contentinclude_originalGet a single-use link the customer opens to confirm the work was done (or flag a problem).
job_idrequiredWrite or correct what a photo or video shows. Use it to fix a summary, to fill in one marked needs_summary (older photos and browser captures have none), or after a person edits the words. Each change keeps the earlier wording. Workers on the shop can edit; the summary is never shown to customers.
summaryrequiredmedia_idrequirededited_by_personPhotos and videos with no summary yet: older uploads, browser captures, and uploads whose agent could not look at the file. Open each with media.get include_content, look at it, then send media.setSummary.
kindlimitjob_idshop_idrequiredCreate a quote from lines the worker wrote. Lines are never filled in by AI. Optional: good, better, best options and optional lines the customer picks when signing.
linesrequiredjob_idrequiredoptionstax_rate_idLock the quote and get a single-use signing link for the customer.
quote_idrequiredemail_customerReplace an unsigned quote with a new version. Earlier signing links stop working; send it again for a new link.
linesrequiredoptionsquote_idrequiredtax_rate_idWithdraw a draft or sent quote the customer has not signed, with an optional reason. Signing links stop working and follow-ups stop. A withdrawn quote cannot be reopened; create a new quote if needed.
reasonquote_idrequiredThe Idaho 45-525(3) subcontractor and supplier statement for a job: the latest signed one, any prepared draft, and whether final payment needs one.
job_idrequiredPrepare the Idaho 45-525(3) statement for the shop to sign: a list of subcontractors, materialmen and rental equipment providers over $500, or none_attestation "yes" for "No subcontractors or suppliers over $500 on this job". Does not sign.
job_idrequiredentriesnone_attestationOwner only: the link to the shop's payment setup page. Give it to the owner; they open it, sign in, and press one button to set up card and bank payments with Stripe. Nothing starts until they do. status is none, onboarding, active, restricted or settling_only.
shop_idrequiredCreate an invoice for a signed quote, for the total of the option and optional lines the customer picked.
quote_idrequireddeposit_minorSend an invoice (or the next part of it) and get a single-use pay link. Earlier pay links stop working. Refused with conflict on a Doing Work deposit invoice whose booking ended (shop cancel or no-show). payments_ready false means the shop has no active payments account yet (after a hand-off, connect one with payments.connectStart); the link shows payment isn't available until it does.
percentinvoice_idrequiredamount_minoremail_customerRecord that the customer paid an invoice outside Doing Work (check, cash, financing, insurance or other). Owner or office, or their agent. Closes the invoice, and the job too unless its checklists still block done (job_status says which; finish them and call jobs.complete). The job record says "Paid outside Doing Work", is never marked paid or verified, and no Doing Work receipt goes to the customer. There is no limit on jobs paid outside Doing Work and no fee on them. Agents can record these too unless the owner turned that off with shops.setAgentMoney.
notemethodrequiredpaid_onrequiredinvoice_idrequiredRefund part or all of a payment (owner or office, or their agent). The refund shows up once the processor confirms it. An agent refund above the shop's agent refund cap (shops.setAgentMoney, $250 unless the owner changed it) does not run: it waits for the owner's OK and the reply says approval_required.
charge_idrequiredamount_minorrequiredDoing Work's fee schedule: one stepped rate on each shop's calendar month of card and bank payments, taken out of the payments. No plans, no monthly fee, no card on file. Every shop gets every feature and unlimited workers.
Takes no parameters.
What Doing Work would take on a payment of this size right now, the effective rate on it, the month's volume so far (all locations under the same owner), and how far the shop is from the next, cheaper band (owner or office). Leave out amount_minor for just the month picture and the next band line.
shop_idrequiredamount_minorA month's Doing Work fees for a shop: card and bank volume, fees by kind, the effective rate, each line, and how far the shop is from the next band this month (owner or office).
monthrequiredshop_idrequiredPublic keys that verify signed job records.
Takes no parameters.
The latest signed record for a job and its level (logged, paid, verified).
job_idrequiredAdd a webhook endpoint for a shop (owner or office, or their agent). The url must be https on a public internet address. Returns the signing secret once; it is never shown again.
urlrequiredeventsshop_idrequiredList a shop's webhook endpoints and their recent delivery counts. Secrets are not returned.
shop_idrequiredRemove a webhook endpoint. Pending deliveries to it stop.
endpoint_idrequiredRead a shop's audit log, newest first (owner only).
limitshop_idrequiredbefore_idCreate a developer platform account (private beta). The caller owns it.
namerequiredterms_versionrequiredList the platform accounts you own and the shops each one manages.
Takes no parameters.
Stop a platform from managing this shop. Shop owner only.
grant_idrequiredAdd a customer to a shop, with kind, company, email, phone, billing address, lead source, tags and notes in one call.
kindnamerequiredtagsemailnotesphoneshop_idrequiredlead_sourcecompany_namebilling_addressOne customer with contacts, properties, custom fields and open balance.
customer_idrequiredCustomers of a shop, newest first, filtered by tag, lead source or archived.
taglimitcursorshop_idrequiredarchivedlead_sourceFind customers by name, company, email, phone or property address.
qrequiredlimitshop_idrequiredinclude_archivedChange a customer's name, kind, company, email, phone, billing address, lead source, tags or notes.
kindnametagsemailnotesphonecustomer_idrequiredlead_sourcecompany_namebilling_addressArchive a customer (hidden from lists, history kept) or bring one back.
archivedcustomer_idrequiredLikely duplicate customers in a shop: same email, same phone digits, or same name.
shop_idrequiredcustomer_idMerge a duplicate customer into another: jobs, requests, contacts, properties and fields move over.
from_customer_idrequiredinto_customer_idrequiredAdd a contact person to a customer (tenant, manager, billing, spouse).
namerequiredroleemailphoneis_primarycustomer_idrequiredChange or remove one contact of a customer.
nameroleemailphoneremovedcontact_idrequiredis_primaryAdd a service address to a customer, with optional label and access notes.
labeladdressrequiredcustomer_idrequiredaccess_notesService addresses of a customer, or every property of a shop.
limitcursorshop_idcustomer_idinclude_archivedChange a property's label or access notes, or archive it.
labelarchivedproperty_idrequiredaccess_notesRecord equipment at a property: kind, make, model, serial, install date and warranty.
kindrequiredmakemodelnotesserialproperty_idrequiredinstall_datewarranty_untilEquipment at a property, or warranties ending soon across a shop.
shop_idproperty_idinclude_archivedwarranty_ends_within_daysChange or archive an equipment record.
kindmakemodelnotesserialarchivedequipment_idrequiredinstall_datewarranty_untilSet the tags and lead source on a job.
tagsjob_idrequiredlead_sourceEverything that happened with a customer, newest first: requests, jobs, quotes, signatures, invoices and payments.
limitcursorcustomer_idrequiredA customer's account statement: every invoice with total, paid and balance, and the total owed.
customer_idrequiredEverything the shop holds about one customer, as one JSON document, for a privacy request.
customer_idrequiredAdd a custom field to customers, properties, jobs, quotes or invoices for a shop.
keyrequiredpiityperequiredlabeltargetrequiredoptionsshop_idrequiredrequiredshared_with_homeownerCustom fields a shop has defined, optionally for one kind of record.
targetshop_idrequiredSet one custom field value on a customer, property, job, quote or invoice.
keyrequiredvaluerequiredtargetrequiredshop_idrequiredcurrencyobject_idrequiredCustom field values on one record, with any required fields still empty.
targetrequiredshop_idrequiredobject_idrequiredLog a request for work from a customer or a new lead.
tagstitlerequiredsourceaddressdetailsshop_idrequiredcustomer_idlead_sourceproperty_idcontact_namecontact_emailcontact_phone+1 moreRequests of a shop, newest first, filtered by stage, customer or tag.
taglimitstagecursorshop_idrequiredcustomer_idinclude_archivedHow many open requests a shop has in each stage, and how many were won or lost in the last 30 days.
shop_idrequiredOne request with its customer and the job it became.
request_idrequiredMove a request to another stage or change its details, customer or property.
tagsstagetitledetailsarchivedrequest_idrequiredcustomer_idlead_sourcelost_reasonproperty_idpreferred_timesTurn a request into a job at its property or address; the worker then writes the quote or books a visit.
addresssummaryrequest_idrequiredcustomer_idTurn on the shop's public request form and get its key. Making a new one turns off the old key.
shop_idrequiredSend a shop a request through its public form. No sign-in; needs the form key.
namerequiredemailphonetitlerequiredaddressdetailsform_keyrequiredpreferred_timesBook a repeating visit (daily, weekly or monthly, every n) for a job. All visits are booked now, up to 104. Times repeat in the shop's local time zone. Overlaps and unavailable workers come back as warnings, never blocks.
freqrequiredeverynotestitleuntiljob_idrequiredends_atrequiredstarts_atrequiredoccurrencesassignee_idsarrival_window_minutesCancel the visits of a repeating series that have not started yet, from a time onward (default now). Past, started and done visits stay.
fromreasonseries_idrequiredMark a visit started (from scheduled, on the way, or arrived). The worker on the visit (or the office) can do this.
visit_idrequiredMark a visit done, with an optional note. The worker on the visit (or the office) can do this. A visit not yet started is started too. Refused with checklist_open while a checklist on the visit has required items open or a sign-off missing; the owner, signed in on the hosted override page (/p/checklist/override), may pass override_reason to mark it done anyway (recorded and audited). Agents, keys and office staff cannot override.
notevisit_idrequiredoverride_reasonBook a visit to a job at a time, optionally with the workers going (assignee_ids, a saved crew_id, or both). Overlaps for those workers come back in conflicts.
notestitlejob_idrequiredcrew_idends_atrequiredprioritystarts_atrequiredassignee_idsarrival_window_minutesMove a visit or change its title, notes or arrival window. Overlaps for its workers come back in conflicts. Moving it re-plans the appointment reminder.
notestitleends_atvisit_idrequiredstarts_atarrival_window_minutesSet who is going on a visit: person_ids, a saved crew_id, or both. The list replaces the current one; an empty person_ids with no crew leaves it unassigned.
crew_idvisit_idrequiredperson_idsCancel a visit that is scheduled, on the way, or arrived. It stays on record with the reason, and customer notices not yet sent for it are dropped.
reasonvisit_idrequiredSet a visit's priority: normal, urgent or emergency. Sends visit.priority_set. For urgent or emergency, call dispatch.suggest for who could go.
reasonpriorityrequiredvisit_idrequiredRead only: for an urgent or emergency visit, the shop's field workers and owners ranked by who is free (no overlapping visit, not on time off, inside their hours) and then by the fewest visits that day. Suggestions only; assign with visits.assign.
limitvisit_idrequiredOne visit with its job and workers.
visit_idrequiredA shop's visits that overlap a time window, earliest first. Filter by worker, job, or only mine. Field workers only ever see their own.
torequiredfromrequiredminejob_idshop_idrequiredperson_idunassignedinclude_cancelledSave the map point for a job's address, so routes.day can give it to you with each stop (owner or office). Look the address up with your own maps tools, or have a person type it in. Doing Work does not look addresses up. The point is kept for this shop's jobs at the same address.
latrequiredlngrequiredjob_idsourcevisit_idSave where a worker starts the day (their home or a yard), or with no person_id the shop's yard, used when a worker has none. Owner or office for anyone; a worker for themselves. A worker's own start is seen only by them and the owner or office.
latrequiredlngrequiredlabelrequiredsourceshop_idrequiredperson_idOne day's stops for planning a route, per worker in visit time order: each worker's start point (their own, else the shop yard), and for each stop the address, map point (null until you save one with routes.setLocation; source says where it came from), time, length, arrival window, priority, and locked when the worker is already on the way, there, or done. Visits with no worker come back in unassigned. Owner and office see everyone; a field worker sees only their own day. Plan the order with your own tools, then write it back with routes.apply.
daterequiredshop_idrequiredperson_idsWrite a planned route back: new times, and optionally new workers, for up to 100 visits at once (owner or office). All or nothing: if any visit is not scheduled (already on the way, there, started, done or cancelled), not this shop's, or the plan leaves a worker with overlapping visits, nothing changes and the problems come back in conflicts. Pass allow_overlaps true to save overlaps anyway, or dry_run true to check without saving. Each moved visit gets its appointment reminder planned again once.
changesrequireddry_runshop_idrequiredallow_overlapsAdd a supplier the shop buys parts from. Owner or office.
namerequirednoteemailphoneshop_idrequiredaccount_numberChange a supplier's name, contact details or note, or archive it (archived: true). Owner or office.
namenoteemailphonearchivedvendor_idrequiredaccount_numberList the shop's suppliers (archived ones only with include_archived). Owner or office.
shop_idrequiredinclude_archivedStart a purchase order (draft) for parts for a job from a supplier. Nothing counts as job cost until po.receive. Owner or office.
notelinesrequiredjob_idrequiredvendor_idrequiredChange a draft purchase order's supplier, note or lines (lines replace all lines). Owner or office.
notelinespo_idrequiredvendor_idA purchase order with its lines, what was received (in job cost) and the supplier's bill. Owner or office.
po_idrequiredList purchase orders for the shop, or for one job or supplier, newest first. Owner or office.
limitjob_idshop_idrequiredvendor_idMark a draft purchase order as sent to the supplier (the agent or a person sends it). Owner or office.
po_idrequiredRecord parts that arrived. Each received line becomes a material on the job at the line's cost (this is the only way a purchase order reaches job cost; do not also add an expense for it). Leave lines out to receive everything left. Owner or office.
linespo_idrequiredvisit_idTake back a received material from a purchase order (wrong part, returned). It leaves job cost and the line can be received again. Owner or office.
reasonmaterial_idrequiredCancel a purchase order that has nothing received (undo receipts first). Owner or office.
po_idrequiredRecord the supplier's bill for a purchase order, for paying the supplier. It is never added to job cost or expenses (the received materials already are); the difference from what was received is shown. Owner or office.
po_idrequiredbill_refbill_minorrequiredMake a calendar feed link (.ics) of one worker's visits that a calendar app subscribes to (read only). Leave person_id out for your own; owner or office can make one for any current member. A new feed turns that person's old one off. The link is shown once.
shop_idrequiredperson_idCalendar feeds in a shop, newest first, with whether each is active and how often it was fetched. Field workers see only their own. The link is not shown again.
shop_idrequiredperson_idTurn a calendar feed off now. Calendar apps that fetch it after this get 410 and stop showing new visits.
feed_idrequiredSet a worker's weekly hours, replacing what was there. Days are 0 (Sunday) to 6, times are shop local HH:MM. An empty list means no set hours (always available).
hoursrequiredshop_idrequiredperson_idAdd time off for a worker (vacation, sick, appointment).
reasonends_atrequiredshop_idrequiredperson_idstarts_atrequiredRemove a time-off entry.
time_off_idrequiredA worker's weekly hours, time off, and booked visits in a window (at most 62 days). Defaults to me.
torequiredfromrequiredshop_idrequiredperson_idThe shop's scheduling setup: time zone, booking hours (or the default when none are set), arrival window, travel buffer, reminder lead time, whether on the way notices go out, and whether arrival times are shown. on_my_way_notices covers both the on the way and the arrived notice. arrival_notices is off unless the shop turns it on. When on, an on the way message includes an arrival time when one is known (a stored route estimate, or the time the worker entered; no drive time is looked up). On the way and arrived each go by text and by email. Any worker in the shop can read it.
shop_idrequiredSet the shop's booking hours, replacing what was there (owner or office). Days are 0 (Sunday) to 6, times are shop local HH:MM, several blocks a day are fine. An empty list clears them, and find-a-time falls back to Monday to Friday 08:00 to 17:00. Visits outside these hours are still allowed and come back with outside_shop_hours.
hoursrequiredshop_idrequiredChange the shop's scheduling rules (owner or office; the time zone is owner only). arrival_window_minutes is the default window customers are told for new visits (0 means an exact time). buffer_minutes is travel and setup time find-a-time keeps clear around booked visits. reminder_hours is how long before a visit the customer gets an appointment reminder (0 turns reminders off). on_my_way_notices tells the customer by text and by email when a worker says they are on the way. Text is the main one. The email goes whenever the customer has an email address, even if the text does not. arrival_notices (off by default) adds an arrival time to that message when one is known (a stored route estimate, or the time the worker entered; route data has no drive time, so with no worker time there is no arrival line). The arrived text and email follow on_my_way_notices, the same setting as the on the way message. A do-not-email address is not emailed. Only the fields you send change. Visits already booked keep their window and reminder.
shop_idrequiredtime_zonebuffer_minutesreminder_hoursarrival_noticeson_my_way_noticesarrival_window_minutesFind open times for a visit of a given length. Looks inside shop hours (or Monday to Friday 08:00 to 17:00 when none are set), skips worker time off and times outside a worker's own hours, and keeps the shop's travel buffer clear around booked visits. Give person_ids or a saved crew_id (or both) to check those workers (together: all of them free at once, the default; or any one of them). Leave it out to check every worker in the shop and get back who is free. Field workers can only check themselves. Nothing is booked; call visits.create with a slot.
tofromlimitcrew_idshop_idrequiredtogetherperson_idsstep_minutesduration_minutesrequiredMark that the worker is on the way to a visit, with an optional ETA (eta_at, or eta_minutes from now). The worker on the visit (or the office) can do this. When the shop has on the way notices on, the customer gets a text and an email. Text is the main one. The email goes whenever the customer has an email address, even if the text is blocked, refused, or does not go through. When arrival notices are also on, the message includes an arrival time: a route estimate when the visit already has one, otherwise the time the worker entered, otherwise no arrival line. Route data stores the booked start and the arrival window, not a drive time. Doing Work does not look up a drive time.
eta_atvisit_idrequiredeta_minutesMark that the worker arrived at a visit. The worker on the visit (or the office) can do this. Any on the way message not yet sent is dropped. When on the way notices are on, the customer gets one arrived text and one arrived email. Text is the main one. The email goes whenever the customer has an email address, even if the text does not. A do-not-email address is not emailed. Once only.
visit_idrequiredMark that the worker is on the way to a visit when they tell their agent, for example on my way, there by 2. eta is that time in their words and can be left out. A worker may call this only for a visit they are assigned to. The owner or office may call it for any visit in the shop. When on the way notices are on, the customer gets a text and an email. Text is the main one. The email goes whenever the customer has an email address, even if the text is blocked, refused, or does not go through. When arrival notices are also on, the message includes the time the worker gave. A repeat call does not send again.
etavisit_idrequiredMark that the worker has arrived at a visit when they tell their agent, for example I am here. A worker may call this only for a visit they are assigned to. The owner or office may call it for any visit in the shop. When on the way notices are on, the customer gets one arrived text and one arrived email. Text is the main one. The email goes whenever the customer has an email address, even if the text does not. A do-not-email address is not emailed. When on the way notices are off, this sends nothing. A repeat call does not send again.
visit_idrequiredCustomer notices planned or handled for a visit (appointment reminder, on the way, arrived), with status pending, queued (handed to text, email, or both), cancelled or skipped and why. Owner or office.
visit_idrequiredTimes the shop marked open for its voice agent to book (upcoming only), and which are booked. Any worker in the shop can read it.
shop_idrequiredMark times open for the shop's voice agent to book callers into (owner or office). The agent books them only when phone.setVoiceAi has book_open_slots true, which is off by default. Each slot is at most 12 hours and in the future. A booked slot becomes a request with that time for the office.
slotsrequiredshop_idrequiredTake back an open time that is not booked yet (owner or office).
shop_idrequiredslot_idrequiredTurn the automatic unpaid-invoice reminder on or off for the whole shop (owner only). When on, a customer gets one friendly email reminder a set number of days (default 1) after an invoice or deposit request is sent if it is still unpaid. Mail comes from a doingwork.work address on the shop's behalf, with replies going to the owner.
enabledrequiredshop_idrequireddelay_daysSet the phone and email customers see when they open a canceled invoice or quote link (owner only). Leave a field out or send null to fall back to the owner's own email and phone.
emailphoneshop_idrequiredLet field workers in the shop see job costs (labor cost, material cost, expenses others entered, price book cost), or hide them again (owner only). Off by default. A worker whose own see_costs is off still does not see costs.
enabledrequiredshop_idrequiredTurn the customer hub link in quote and invoice emails on or off for the whole shop (owner only). On by default: each quote or invoice email the customer gets from Doing Work ends with a link to their hub, where they see their quotes, invoices and visits with you.
enabledrequiredshop_idrequiredTurn the automatic unpaid reminder on or off for one invoice (owner or office).
enabledrequiredinvoice_idrequiredAdd a price book item, or change one when item_id is given (owner or office). Items are a pick list for quote lines that workers write; they are never filled into a quote automatically.
kindnameunitpartsitem_idshop_idrequiredtaxablecategorytask_codecost_minordescriptionest_minutes+4 moreList the shop's price book items, by name. Filter by category or text; archived items are left out unless asked for. cost_minor is null for a worker the owner has not let see costs.
qshop_idrequiredcategoryinclude_archivedArchive a price book item, or bring it back with archived false (owner or office). Quotes that used it keep their lines.
item_idrequiredarchivedSave a quote template: worker-written lines (and good, better, best options) to start quotes from. Give template_id to replace one (owner or office).
namerequiredlinesrequiredoptionsshop_idrequiredtemplate_idList the shop's saved quote templates with their lines. To use one, pass its lines and options to quotes.create, changed as the worker says.
shop_idrequiredinclude_archivedArchive a quote template, or bring it back with archived false (owner or office).
archivedtemplate_idrequiredWhat the customer has done with a quote: when each version was first opened and how often, and any decline or change request with its note.
quote_idrequiredSet how many days after a quote is sent the customer gets one friendly follow-up email if they have not answered (owner only). 0 turns it off. Default 3.
daysrequiredshop_idrequiredCreate an invoice without a quote, from lines the worker wrote (never filled in by AI). Optional due date, memo and deposit. Send it with invoices.send.
memolinesrequireddue_onjob_idrequiredtax_rate_iddeposit_minorCreate many invoices at once (up to 100), each from a job and the lines the worker wrote. All or nothing. With send=true each is sent and its pay link returned.
senditemsrequiredshop_idrequiredOne invoice with its lines, what has been paid, the balance, the due date, and whether a bank payment is still clearing. display_status is payment_pending while a bank payment clears (3 to 5 business days), otherwise the invoice status. last_bank_payment_failed_at is set when the latest bank payment failed and the customer can pay again.
invoice_idrequiredThe invoice as a PDF (base64), with shop, customer, lines, paid so far and balance. Attach it to email or save it.
invoice_idrequiredAccounts receivable aging: every open invoice's balance by how late it is (current, 1-30, 31-60, 61-90, over 90 days past due), with totals per customer (owner or office). An invoice with no due date is due when sent.
as_ofshop_idrequiredTurn tips on or off on this shop's invoice pay page (owner only). Off by default. A tip is paid with the invoice, never counts toward the invoice total, and shows in tips.report.
enabledrequiredshop_idrequiredSet the review link (for example your Google review page, https only) and how many days after an invoice is paid the customer gets one email asking for a review (owner only). No link means no email. Default 1 day; 0 turns it off. Review emails show the shop name and mailing_address in the footer, so a link can only be set once the shop has a mailing address (send it here).
daysshop_idrequiredreview_urlmailing_addressTips customers paid, by invoice and in total, between two dates (owner or office). Tips are kept apart from invoice totals. Refunds of a payment are not split out from its tip.
torequiredfromrequiredshop_idrequiredHow this shop's quotes and invoices look: accent color, license number, footer text, logo size, and whether "Sent with Doing Work" shows.
shop_idrequiredSet how this shop's quotes, invoices and emails to customers look, on the customer's page, in the PDF and in every email (owner only). The owner can also change it on the brand page at /p/shop/brand. Send only what changes; null clears a field. accent_color is "#rrggbb" and must reach 4.5 to 1 contrast on white (the default is #1f4fd1). logo_base64 is a PNG or JPEG of up to 5 MB, stored as a JPEG of at most 600 pixels on its long side. sent_with_doing_work (on by default) prints "Sent with Doing Work" in the PDF footer, on the page and at the bottom of emails.
footershop_idrequiredlogo_base64accent_colorlicense_numbersent_with_doing_workA quote as a PDF (base64) in the shop's brand: logo, accent color, license number, lines, options and total. Financing links use the signed total once the customer has signed, and the lowest option until then. The latest version unless version is given. Attach it to email or save it.
versionquote_idrequiredGet a secure page where the customer saves a card with the shop's payment processor (owner or office). Send the link to the customer; Doing Work never sees the card number. Saving a new card replaces the old one.
customer_idrequiredThe card a customer has on file (brand, last 4, expiry) and whether auto-pay is on (owner or office).
customer_idrequiredRemove a customer's saved card (owner or office). Auto-pay turns off with it.
customer_idrequiredTurn auto-pay on or off for a customer (owner or office). On needs a saved card. With auto-pay on, each invoice sent to them is charged to the card on its due date (or the day it is sent if it has none). A failed charge is not retried; you get an email and the pay link still works.
enabledrequiredcustomer_idrequiredStart a maintenance plan for a job's customer (owner or office). You write the priced lines for one term (never filled in by AI). The first term's invoice is created now (and sent if send_first is true). When a term ends, the next term's invoice is created automatically and sent if auto_send is on. With visits_per_term, each term also gets that many service due dates (see services.listDue), so the shop knows when each covered visit is due; schedule the actual visit with visits.create as usual.
namerequiredlinesrequiredjob_idrequiredauto_sendstarts_onsend_firsttax_rate_idterm_monthsrequiredvisit_titlevisits_per_termOne maintenance plan: price per term, current term, renewal date, each term's invoice, and this term's covered visits with the next one due.
plan_idrequiredA shop's maintenance plans, optionally for one customer or by status, soonest renewal first.
statusshop_idrequiredcustomer_idReplace a plan's priced lines (owner or office; you write them, never AI), and optionally its tax rate. Applies from the next term's invoice; invoices already made keep their price.
linesrequiredplan_idrequiredtax_rate_idChange how many visits a plan covers each term, and what they are called (owner or office). Applies from the next term. Pass this_term true to also add them now to the current term when it has none yet.
plan_idrequiredthis_termvisit_titlevisits_per_termrequiredCancel a maintenance plan (owner or office). No more renewal invoices. Invoices already sent stay as they are. The plan's open visit due dates are cancelled.
plan_idrequiredAdd or change a sales tax rate the shop charges in one jurisdiction (owner or office). You enter the rate; Doing Work never looks it up. rate_bps is hundredths of a percent (600 = 6%). Changing a rate applies to new quotes and invoices only. is_default makes it the rate used when a quote or invoice does not name one.
namerequiredshop_idrequiredrate_bpsrequiredis_defaulttax_rate_idjurisdictionrequiredThe shop's tax rates. Archived (replaced or removed) rates are left out unless include_archived is true.
shop_idrequiredinclude_archivedStop using a tax rate (owner or office). Quotes and invoices that already used it keep it.
tax_rate_idrequiredChoose how the sales tax report counts a period (owner only). accrual (default): invoices sent in the period. cash: money collected in the period, after refunds. Pick the one your state files on.
basisrequiredshop_idrequiredSales tax report for a period (owner or office), shop local dates, from and to inclusive. Uses the shop's basis (shops.setTaxReportBasis) unless basis is given. accrual: invoices sent in the period, with sales, taxable sales, tax billed, and tax collected so far. cash: money collected in the period through Doing Work (payments minus refunds, tips left out), with the tax share of it. Grouped by the tax name, jurisdiction and rate on each invoice. Untaxed sales are one row with no rate. Void invoices are left out. For filing, check the numbers against your own records.
torequiredfromrequiredbasisshop_idrequiredShow an uploaded photo or file of the same job with a quote, with an optional caption. Upload it first with the media ops. The customer sees it on the quote page.
captionmedia_idrequiredquote_idrequiredTake a photo or file off a quote. The media item itself stays on the job.
attachment_idrequiredPhotos and files shown with a quote, in order.
quote_idrequiredAdd or remove tags on a photo (for example: leak, panel, permit). Tags are lower case; returns the photo's tags.
addremovemedia_idrequiredEvery tag used in the shop, with how many photos and jobs carry it.
shop_idrequiredFind photos across the shop that carry all the given tags. Narrow by job, stage, or upload dates (shop time zone). Newest first, up to 200.
tofromtagslimitstagejob_idshop_idrequiredJobs in the shop that carry all the given tags (set with jobs.setTags), newest first, up to 200.
tagsrequiredshop_idrequiredSave markup over a photo as a new layer version: arrows, lines, boxes, circles, text and freehand strokes in 0..1 photo coordinates (0,0 is top left). The photo is never changed; earlier versions are kept. An empty list clears the markup.
shapesrequiredmedia_idrequiredA photo's markup: the latest version unless one is named, with an SVG overlay to lay over the original photo. Also lists all versions.
versionmedia_idrequiredMake a link to a gallery of a job's photos that anyone with the link can open without signing in. Name the photos, or leave media_ids out to share every photo on the job (including ones added later). Expires after days (1 to 90, default 14); revoke it any time. Markup shows over the photos unless include_markup is false. Set include_daily_log to also show the job's daily log entries (off by default; names of who wrote them are not shown). The url is shown once.
daystitlejob_idrequiredmedia_idsinclude_markupinclude_daily_logPhoto share links on a job, newest first, with whether each is still active and how often it was opened. The link itself is not shown again.
job_idrequiredTurn a photo share link off now. Anyone opening it after this sees that it is no longer available.
share_idrequiredWrite a daily log entry on a job: what happened on site that day, in the worker's own words. Any shop member can add one. log_date defaults to today in the shop's time zone. Attach photos already on the job with media_ids.
bodyrequiredjob_idrequiredlog_datemedia_idsDaily log entries on a job, oldest first, optionally between two dates (inclusive). Removed entries are left out.
tofromjob_idrequiredTake a daily log entry out of the log. Only the worker who wrote it or the owner can. It stays in history and in any PDF already made.
entry_idrequiredRender a photo report PDF for a job: a title and the worker's own notes, then the job's photos in time order with stage and tags. Name photos with media_ids or leave it out for every photo on the job. Core stores the PDF with its sha256 and returns it (base64).
notestitlejob_idrequiredmedia_idsRender the daily log for a job as a PDF: each day's entries in the workers' own words with who wrote them, and the photos they attached. Optional from and to dates (inclusive). Core stores the PDF with its sha256 and returns it (base64).
tofromjob_idrequiredinclude_photosPDF documents core made for a job (photo reports, daily logs and submitted forms), newest first, with each file's sha256.
job_idrequiredOne stored job PDF (base64) with its sha256, byte for byte as it was made.
document_idrequiredRecord money a worker spent on a job, with the receipt photo. Parts received on a purchase order are already job cost; when the vendor matches a received purchase order on the job, possible_po_duplicates lists it so you can ask before keeping both. The worker types the amount and tax from the receipt; core never reads or fills in amounts. spent_on defaults to today in the shop's time zone.
notejob_idrequiredvendorcategoryspent_ontax_minoramount_minorrequiredreceipt_media_idChange an expense: date, vendor, category, amount, tax, receipt photo or note. Amounts are still typed by a worker. The worker who entered it, the owner or office can change it.
notevendorcategoryspent_ontax_minorexpense_idrequiredamount_minorreceipt_media_idTake an expense off the books (kept in history). The worker who entered it, the owner or office can.
expense_idrequiredExpenses on a job, or across the shop between dates, with totals by category. Owner and office see every expense; a field worker sees the ones they entered.
tofromjob_idshop_idcategorySearch one shop for customers (name, email, phone), properties (address), jobs (summary), requests (title), notes (words, on any record) and photos and videos (what the agent said they show, readable text such as serial numbers, video transcripts). Case-insensitive; you see only what your role can read.
qrequiredlimitshop_idrequiredEvery event a webhook can receive, with its payload keys and types. Approved agent actions add requested_by_token_id to any event.
Takes no parameters.
List deliveries to one webhook endpoint, newest first, with event, status, attempts and last HTTP status.
limitstatusbefore_idendpoint_idrequiredSend a failed or dead delivery again from attempt 0 (owner or office).
delivery_idrequiredThe customer import fields and the built-in presets (jobber, housecall_pro, companycam) with the export column each reads.
Takes no parameters.
Dry run of a customer CSV import. Writes nothing. Returns the headers, a suggested mapping (from a preset or the header names), and for every row the customer it would create or the problems found. Show the mapping to the owner before imports.run.
csvrequiredpresetsourcemappingshop_idrequiredon_matchOwner only: import customers (and one service address each) from a CSV with the mapping the owner confirmed. mode all_or_nothing (default) writes nothing if any row fails; per_row writes the good rows and reports the rest. dry_run true checks without writing.
csvrequiredmodesourcedry_runmappingrequiredshop_idrequiredon_matchpreview_hashFields for importing history from another system (jobs with visit history, open quotes, unpaid invoices, price book, equipment, maintenance plans as service-due reminders, payment history as read-only records) and the jobber and housecall_pro presets per kind.
Takes no parameters.
Dry run of a history import (kind jobs, quotes, invoices, pricebook, equipment, maintenance_plans, payments or flat_rate). Writes nothing. Returns a suggested mapping, what each record would do (create, update, skip, skip_blank, skip_closed or error) with how its customer matched, and a preview_hash. Show it to the owner; imports.historyRun needs the same hash.
csvrequiredkindrequiredpresetsourcemappingshop_idrequiredon_matchplans_asequipment_kindOwner only: write a history import the owner confirmed in imports.historyPreview (send its preview_hash, plus the same csv, kind, source, on_match and mapping). Records already imported are matched by old id and skipped or updated, never duplicated. Imported quotes and invoices are drafts and are not sent. Maintenance plans become service-due reminders (no invoice, no charge), or with plans_as billed, maintenance plans at the confirmed price with auto_send off and no invoice until the next due date; payments become read-only history records (no charge, no fee, no invoice change). flat_rate rows become price book tasks, matched by old id, then task code, then name. mode all_or_nothing (default) or per_row.
csvrequiredkindrequiredmodesourcemappingrequiredshop_idrequiredon_matchplans_aspreview_hashrequiredequipment_kindOwner or office: payments imported from another system (read-only history; never charged, never counted toward Doing Work fees). Filter by customer_id.
limitshop_idrequiredcustomer_idOwner only: everything the shop holds as one ZIP: data/<table>.csv and data/<table>.json for every shop table, files/ with job photos (and the original HEIC or TIFF file next to its JPEG copy) and PDFs, and manifest.json. Signing secrets and token hashes are left out. By default you get download_url, a link that works for 60 minutes and up to 5 downloads; anyone with the link can download, so do not share it. delivery "inline" returns zip_base64 instead, only for exports up to 10 MB. Large shops: pass include_files false for data only.
shop_idrequireddeliverylink_minutesinclude_files83% of the applicable checks met
How complete this listing is, computed from the registry entry, the endpoint and public sources. Not a rating of the server and not a statement that it is safe or working today: reachability is a dated check, and no installs or reviews go into the score.
Declare a GitHub repository with a README, or serve resource_documentation in the OAuth protected-resource metadata.
A hosted service is used under its provider's terms, so no license is expected here. This check is left out of the percentage.