# HeadHoncho public API: the full documentation > The whole API documentation in one Markdown file, for an AI agent. Every section below is a page of https://headhoncho.app/docs/api, in the order a reader needs it: the overview and the guides first, then one section per endpoint. The index of the site is https://headhoncho.app/llms.txt and the OpenAPI file is https://headhoncho.app/docs/api/openapi.json. --- # The HeadHoncho public API The HeadHoncho public API lets your code, or the AI app you already use, read a client's jobs and raw ad data and change jobs, under the same rules as the app. Page: https://headhoncho.app/docs/api | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## What the API is The HeadHoncho public API is the app, reachable from code. It gives a marketing agency's campaigner, or the developer they hired, the same records the app draws: jobs and leads, the raw rows each ad platform and call tracker reported, and the Google Click ID report. An AI app can use it too, through the [MCP server](https://headhoncho.app/docs/api/mcp). It follows the app's own model. A read is a `GET` over a record the app already shows. A change is a `POST` to `/api/v1/commands/`, where the verb is the app's own command name. Nothing is computed here that the app does not compute. The longer version is on [the model](https://headhoncho.app/docs/api/model). There are 138 endpoints in 24 groups today, all under `https://api.headhoncho.app/api/v1`. It gives you building blocks: records, raw rows and single commands. It never gives you a board, a dashboard or an automation to rebuild the app with. The [roadmap](https://headhoncho.app/docs/api/roadmap) says what is planned and what will never be offered. ## The 24 groups ### Account - [Whoami](https://headhoncho.app/docs/api/whoami): Who this key or app acts as, which companies it reaches, what it may do, and the words to use in commands: statuses, job types and technicians. - [List companies](https://headhoncho.app/docs/api/list_companies): The companies this credential reaches, each with its name, time zone, country and service area. The same ids every other call takes as company_id. - [Get company](https://headhoncho.app/docs/api/get_company): One company this credential reaches: its name, time zone, country and service area. - [Get usage](https://headhoncho.app/docs/api/get_usage): What the plan has used, what API calls cost and what this credential called, by day or by endpoint, with the credits left. - [Get credits](https://headhoncho.app/docs/api/get_credits): This month's credits: the plan's grant, what rolled over, what was bought, what was used and what is left. - [List plans](https://headhoncho.app/docs/api/list_plans): The plans on offer, with price and what each includes, and which one this workspace is on. ### Changes - [List events](https://headhoncho.app/docs/api/list_events): What changed on jobs since a cursor: a job opened, moved, assigned or paid, with who did it. Send back next to get the rest. - [List event types](https://headhoncho.app/docs/api/list_event_types): Every kind of change the Changes feed can carry, in plain words, and the facts each one puts in data. ### Webhooks - [List webhooks](https://headhoncho.app/docs/api/list_webhooks): The addresses this key asked us to call when jobs change, with the kinds of change each wants and whether it is paused. - [Get webhook](https://headhoncho.app/docs/api/get_webhook): One webhook: its address, the kinds of change it wants, its companies, and whether it is paused and why. - [List webhook deliveries](https://headhoncho.app/docs/api/list_webhook_deliveries): The last changes sent to one webhook, newest first, with the answer code and time of every try. ### Webhook commands - [Add webhook](https://headhoncho.app/docs/api/add_webhook): Give us an address and the kinds of change you want. We call it for each change, signed, and retry what fails. The signing secret is shown once. - [Change webhook](https://headhoncho.app/docs/api/change_webhook): Rename a webhook, move it to another address, change its kinds or companies, pause or resume it, or replace its secret. Send only what changes. - [Remove webhook](https://headhoncho.app/docs/api/remove_webhook): Stop calling an address for good. Its past deliveries stay readable. - [Send webhook test](https://headhoncho.app/docs/api/send_webhook_test): Send a signed test event to one webhook now and say what the address answered. It is not retried and costs no delivery credit. - [Redeliver webhook](https://headhoncho.app/docs/api/redeliver_webhook): Send one delivery again, from a webhook's list of deliveries. It goes out within a minute. A change already paid for is not paid for twice. ### Jobs - [List jobs](https://headhoncho.app/docs/api/list_jobs): Jobs and leads in the companies this credential reaches, newest first, with status, technician, schedule, money and the ad click each came from. - [Get job](https://headhoncho.app/docs/api/get_job): One job or lead: who, where, when, which status, which technicians, the money on it and the ad click it came from. - [Get job history](https://headhoncho.app/docs/api/get_job_history): Everything that happened to a job, in order, with who did it: created, moved, assigned, noted, paid. The same log the job page shows. - [Get job log](https://headhoncho.app/docs/api/get_job_log): A job's timeline in plain words, one line per thing that happened: notes, moves, texts, money, the rules and the AI, each with who did it. - [List situations](https://headhoncho.app/docs/api/list_situations): The situations the AI dispatcher is working on jobs now: what came up, the plan, and which step it is on. - [List job photos](https://headhoncho.app/docs/api/list_job_photos): The photos stored on a job, oldest first, each with a link that opens it for one minute. - [Get photo](https://headhoncho.app/docs/api/get_photo): One stored photo and a fresh link to its file. The link works for one minute. - [Get calendar](https://headhoncho.app/docs/api/get_calendar): Every job with a booked time between two days, earliest first. Canceled and closed jobs are left out, as on the app's calendar. - [List unscheduled jobs](https://headhoncho.app/docs/api/list_unscheduled_jobs): Open jobs and leads that have no booked time yet, the ones that waited longest first. - [Export jobs](https://headhoncho.app/docs/api/export_jobs): Jobs as a CSV file, newest first, up to 10,000 rows: ticket, technicians, status, dates, address, customer and price. - [Search jobs](https://headhoncho.app/docs/api/search_jobs): Find jobs by ticket number, customer, address or technician name, and technicians by name. - [Get automatic status](https://headhoncho.app/docs/api/get_automatic_status): Whether a person set this job's status by hand, why its facts do not hold it, and where Back to automatic would put it. - [Get job detour](https://headhoncho.app/docs/api/get_job_detour): Whether a job is on a detour, such as Waiting on parts, and where Resolve would put it. - [List job reassignments](https://headhoncho.app/docs/api/list_job_reassignments): The times this job was handed from one technician to another, oldest first, and how far each one got. - [List calendar reassignments](https://headhoncho.app/docs/api/list_calendar_reassignments): Every reassignment on a job booked in a window: open ones, and ones that closed today. ### Job commands - [Create job](https://headhoncho.app/docs/api/create_job): Open a job or a lead in one company: the customer, the address, and optionally the job type, the time window and the technician. - [Update job](https://headhoncho.app/docs/api/update_job): Change a job's facts: the customer, the address, the schedule, the job type or the notes. Only the fields you send change. - [Change job status](https://headhoncho.app/docs/api/change_job_status): Move a job to another status by its name, slug or id. The move lands in the job's history with who asked for it. - [Assign worker](https://headhoncho.app/docs/api/assign_worker): Put a technician or subcontractor on a job. If Job follow-up is on, the automation acts on it at once, as it would from the app. - [Unassign worker](https://headhoncho.app/docs/api/unassign_worker): Take a technician or subcontractor off a job. The ticket's cancellation reaches them the way it does from the app. - [Add job note](https://headhoncho.app/docs/api/add_job_note): Add a note to a job. It appends to the job's log and never overwrites. - [Update job note](https://headhoncho.app/docs/api/update_job_note): Fix what a note says. Only the person who wrote it may change it; the old text stays in the job's history. - [Delete job note](https://headhoncho.app/docs/api/delete_job_note): Take a note off a job. Its author or an owner may. The removal is in the job's history. - [Set job cut](https://headhoncho.app/docs/api/set_job_cut): What one technician or subcontractor on a job is paid on this job: a percent of the total, a percent of the profit, or a flat amount. - [Release job status](https://headhoncho.app/docs/api/release_job_status): Hand a status set by hand back to the automation. The job moves at once to the status its facts hold, and History says why. - [Resolve job detour](https://headhoncho.app/docs/api/resolve_job_detour): Close a job's detour, such as Waiting on parts. The job goes back to the status it left, then on to where its facts put it. - [Archive job](https://headhoncho.app/docs/api/archive_job): File a finished job away, off the boards. It keeps its money and counts in every figure; Unarchive brings it back. - [Unarchive job](https://headhoncho.app/docs/api/unarchive_job): Bring an archived job back onto the boards, as it was. - [Trash job](https://headhoncho.app/docs/api/trash_job): Move a job to Trash, with why. It leaves every list and every figure, and can be restored for 30 days. - [Restore job](https://headhoncho.app/docs/api/restore_job): Bring a job back from Trash, whole: its money, its history and its technicians. - [Upload photo](https://headhoncho.app/docs/api/upload_photo): Put one photo on a job. Send the picture as base64 text; it is stored and confirmed in one call. - [Delete photo](https://headhoncho.app/docs/api/delete_photo): Remove one photo from a job, for good: its record and its file. ### Many jobs at once - [Bulk change status](https://headhoncho.app/docs/api/bulk_change_status): Move up to 200 jobs to one status. Each move lands in that job's history. - [Bulk assign worker](https://headhoncho.app/docs/api/bulk_assign_worker): Put one technician or subcontractor on up to 200 jobs. A job that already has them is skipped. - [Bulk unassign worker](https://headhoncho.app/docs/api/bulk_unassign_worker): Take one technician or subcontractor off up to 200 jobs. - [Bulk add note](https://headhoncho.app/docs/api/bulk_add_note): Add the same note to up to 200 jobs. It appends to each job's log and never overwrites. - [Bulk archive jobs](https://headhoncho.app/docs/api/bulk_archive_jobs): File up to 200 finished jobs away. They keep their money and still count in every figure. - [Bulk unarchive jobs](https://headhoncho.app/docs/api/bulk_unarchive_jobs): Bring up to 200 archived jobs back, as they were. - [Bulk trash jobs](https://headhoncho.app/docs/api/bulk_trash_jobs): Move up to 200 jobs to Trash, with one reason. They leave every list and figure, and can be restored for 30 days. - [Bulk restore jobs](https://headhoncho.app/docs/api/bulk_restore_jobs): Bring up to 200 jobs back from Trash, whole: money, history and technicians. ### Clients - [List clients](https://headhoncho.app/docs/api/list_clients): The people behind your jobs, by name, with their phones and how many jobs each has. - [Get client](https://headhoncho.app/docs/api/get_client): One client: name, phones and email, and their jobs, newest first. ### Client commands - [Create client](https://headhoncho.app/docs/api/create_client): Add a client to the book before they have a job. One phone number is one client. - [Update client](https://headhoncho.app/docs/api/update_client): Correct a client's name, phones or email. Only the fields you send change. - [Delete client](https://headhoncho.app/docs/api/delete_client): Erase a person from the book. Their jobs stay, but lose the name and phone. It cannot be undone. ### Leads - [List leads](https://headhoncho.app/docs/api/list_leads): Leads in the companies this credential reaches, newest first, with stage, service, estimate and where each came from. - [Get lead](https://headhoncho.app/docs/api/get_lead): One lead: who, what and when they asked for, the estimate, its stage and what happened to it so far. - [List needs you](https://headhoncho.app/docs/api/list_needs_you): Jobs that wait on a person, most urgent first, each with the reasons: no technician, unpaid cut, no answer and more. - [List conversion reviews](https://headhoncho.app/docs/api/list_conversion_reviews): Ad clicks the matcher would not guess at. Each waits for you to pick the job it produced, or to reject it. ### Lead commands - [Create lead](https://headhoncho.app/docs/api/create_lead): Add a lead to one company, the way a person adds one by hand. Send what you know; the rest can be filled in later. - [Update lead](https://headhoncho.app/docs/api/update_lead): Change what a lead asked for: the customer, the address, the service, the time, the urgency or the notes. Only the fields you send change. - [Mark lead lost](https://headhoncho.app/docs/api/mark_lead_lost): Close an open lead as lost, with the reason. It moves to Archive on the company's own clock. - [Pass lead](https://headhoncho.app/docs/api/pass_lead): Say a new lead is not yours to take, with an optional reason. It leaves the list to answer. - [Book lead](https://headhoncho.app/docs/api/book_lead): Turn a lead into a job with everything the lead holds. The lead becomes won and is linked to the job. - [Dismiss lead](https://headhoncho.app/docs/api/dismiss_lead): Send a lead to Trash as a mistake. It counts nowhere and is erased after 30 days. - [Review conversion](https://headhoncho.app/docs/api/review_conversion): Decide an ad click the matcher would not guess at: pick the job it produced, or reject it. Only then does it reach the Google file. - [Schedule follow up](https://headhoncho.app/docs/api/schedule_follow_up): Book a date to chase a job or a draft lead again. The job moves onto Follow up when the company has that status. - [Update follow up](https://headhoncho.app/docs/api/update_follow_up): Move the date of an open follow-up, or change why it is open. - [Resolve follow up](https://headhoncho.app/docs/api/resolve_follow_up): Say the chase happened. The follow-up is closed, and the job goes back to the line when it was the last stop. - [Cancel follow up](https://headhoncho.app/docs/api/cancel_follow_up): Call off a follow-up that should never have been booked. It is removed, and no chase is recorded. ### Job money - [Get job money](https://headhoncho.app/docs/api/get_job_money): What a job made and where the money went: money in, parts and fees, the profit, each person's share, and every payment and expense line. - [List field reports](https://headhoncho.app/docs/api/list_field_reports): What technicians reported from the field and nobody booked yet: what they collected, how, the parts and the job's total, newest first. ### Money commands - [Record payment](https://headhoncho.app/docs/api/record_payment): Record money the customer paid on a job. A payment that covers the price closes the job, as it does in the app. - [Void payment](https://headhoncho.app/docs/api/void_payment): Stop a payment entered wrong from counting. It stays on the job's money, marked voided, with why. - [Record expense](https://headhoncho.app/docs/api/record_expense): Record a cost on a job: parts, a rental, fuel. Paid by a technician, it is paid back to them on top of their share. - [Void expense](https://headhoncho.app/docs/api/void_expense): Stop an expense entered wrong from counting. It stays on the job's money, marked voided, with why. - [Book field report](https://headhoncho.app/docs/api/book_field_report): Book what a technician reported: the payment, the parts and the job's price, as sent or as you correct them. The job closes when nothing is missing. - [Dismiss field report](https://headhoncho.app/docs/api/dismiss_field_report): Not this: book nothing from a technician's report. What they said is kept on the job. - [Add expense type](https://headhoncho.app/docs/api/add_expense_type): Add a kind of cost the company records, such as Parts or Truck rental. A name already in use is refused, so sending it twice adds one. - [Update expense type](https://headhoncho.app/docs/api/update_expense_type): Rename an expense type, or retire it so new expenses cannot pick it. Old expenses keep it either way. ### Balances - [List balances](https://headhoncho.app/docs/api/list_balances): Who owes who, per technician: their cuts and paid-back parts against the cash they hold and what was already paid out. - [Get balance statement](https://headhoncho.app/docs/api/get_balance_statement): Every line on a technician's balance for a period, with the running balance: cuts, parts, cash held and each payout, voided ones marked. - [List closed balances](https://headhoncho.app/docs/api/list_closed_balances): Every balance close and payout, newest first, voided ones included, with the jobs each one covered. ### Balance commands - [Close balance](https://headhoncho.app/docs/api/close_balance): Close what a technician is owed for the jobs you name, or for everything open through a day, as one payout netted against the cash they hold. - [Record payout](https://headhoncho.app/docs/api/record_payout): Record money paid to a technician, or paid in by one, that names no jobs. It moves their balance and closes no particular job. - [Void closed balance](https://headhoncho.app/docs/api/void_closed_balance): Undo a balance close or a payout entered wrong. Its jobs open again, and it stays on the list, marked voided, with why. - [Hold back job](https://headhoncho.app/docs/api/hold_back_job): Keep one job out of a technician's balance closes until you put it back, with why. Its cut, parts and cash wait together. - [Put back job](https://headhoncho.app/docs/api/put_back_job): Let a held-back job count in the technician's next balance close again. - [Post monthly pay](https://headhoncho.app/docs/api/post_monthly_pay): Add a month of pay to the balance of every active technician on a monthly rate. A month is posted once, however often this is sent. ### Team - [List technicians](https://headhoncho.app/docs/api/list_technicians): Everyone the company sends jobs to: technicians and subcontractors, with contact details, the job types they take and the cut they work on. - [Get worker](https://headhoncho.app/docs/api/get_worker): One technician or subcontractor: contact details, role, monthly pay, cut, the job types they take and whether the person has claimed their card. ### Team commands - [Create worker](https://headhoncho.app/docs/api/create_worker): Add a technician or a subcontractor to the roster. Jobs can go to them at once; they can claim the card later. - [Update worker](https://headhoncho.app/docs/api/update_worker): Change a technician or subcontractor: name, contact, pay, cut, job types, or take them off the roster. Only the fields you send change. ### Statistics - [Get statistics summary](https://headhoncho.app/docs/api/get_statistics_summary): Jobs and leads for a range and the money they left: profit, lead cost, cost per lead, profit after leads, ad spend and profit after advertising. - [Get statistics areas](https://headhoncho.app/docs/api/get_statistics_areas): Every place the work happened, by postal code and city: jobs, closes, cancels, average ticket and profit, with a point to put on a map. - [List area jobs](https://headhoncho.app/docs/api/list_area_jobs): The jobs behind one area on the map, newest first, twenty-five a page, with status, price, profit and where they came from. - [List job pins](https://headhoncho.app/docs/api/list_job_pins): Each job in the range that has a point on the map, newest first, up to 400, with its status, price and profit. Narrow it with a box. ### Marketing - [List ad accounts](https://headhoncho.app/docs/api/list_ad_accounts): The ad accounts and call tracking each company has connected, and how each one is doing. - [List campaigns](https://headhoncho.app/docs/api/list_campaigns): Spend by campaign for a range, with the calls, leads, lead cost, revenue and profit each one produced, and the revenue that could not be placed. - [List agency jobs](https://headhoncho.app/docs/api/list_agency_jobs): The agency's jobs feed on a key: one row per job that opened or closed in the range, in the agency's sixteen columns, a page at a time. - [Get agency feed](https://headhoncho.app/docs/api/get_agency_feed): How the workspace sends closed jobs to its agency: the webhook address, the daily file, whether it is on, and the last tries. ### Raw data - [List tables](https://headhoncho.app/docs/api/list_tables): Every raw table, by the provider that produced it, with its columns, its grain and whether this company has it connected. - [Read table](https://headhoncho.app/docs/api/read_table): Rows of one raw table for one company and a date range, exactly as the provider reported them. No joins, no derived figures. - [Export table](https://headhoncho.app/docs/api/export_table): One raw table as a CSV file for a company and a date range, up to 50,000 rows, with its caveat in the last lines. ### Click IDs and conversions - [Get job conversion](https://headhoncho.app/docs/api/get_job_conversion): What this job told the ad platform it was worth: the click it came from, each conversion sent, its value and its basis, and what Google did with it. - [Get click id report](https://headhoncho.app/docs/api/get_click_id_report): The Google Click ID report: one row per job that opened or closed in the range, with its click id, its tracked call, its total and its profit. - [Export click id report](https://headhoncho.app/docs/api/export_click_id_report): The Google Click ID report as a file: the agency's sheet, or the Google Ads offline conversion upload file, ready to upload. ### Company settings - [Get settings](https://headhoncho.app/docs/api/get_settings): What each company is set up with: name, hours, service area, week and time zone, plus the job types and the statuses with their line. ### Settings commands - [Update company](https://headhoncho.app/docs/api/update_company): Change one company's own facts: name, service area, time zone, country, color, week, opening hours or service places. Only what you send changes. - [Create company](https://headhoncho.app/docs/api/create_company): Add another company to the workspace. It starts with the first company's time zone and country unless you send your own. - [Update organization](https://headhoncho.app/docs/api/update_organization): Rename the workspace. A company still carrying the old workspace name is renamed with it. - [Add job type](https://headhoncho.app/docs/api/add_job_type): Add a kind of work the business does, such as Local move or Roof repair. A name already in use is refused. - [Update job type](https://headhoncho.app/docs/api/update_job_type): Rename a job type, move it in the list, or retire it so new jobs cannot pick it. Old jobs keep it. - [Update job status](https://headhoncho.app/docs/api/update_job_status): Rename a status, change its look, move it in the list, or retire it. A rename shows on every job at once. Its slug and band stay. - [Set status band](https://headhoncho.app/docs/api/set_status_band): Put a status on the line (a step every job passes) or off it as a detour (a place a job gets stuck). The line closes up behind it. - [Replace job status](https://headhoncho.app/docs/api/replace_job_status): Let another status stand in for this one: move its jobs onto the new status, retire the old word, or both. Name an existing status or a new one. - [Add job status](https://headhoncho.app/docs/api/add_job_status): Add a status to the workspace's list, on the line or as a detour. It carries no role: it is a name and a color. - [Reorder line](https://headhoncho.app/docs/api/reorder_line): Set the order of the statuses on the line, the order every picker offers. Send every status on the line, once each. - [Update agency feed](https://headhoncho.app/docs/api/update_agency_feed): Change how closed jobs reach the agency: the webhook address, the daily file address and hour, or switch the feed on or off. Secrets are not touched. - [Sync callrail](https://headhoncho.app/docs/api/sync_callrail): Pull the company's new CallRail calls and forms now, match them to jobs, and say how many landed. The hourly sync does this on its own. - [Update callrail tracking](https://headhoncho.app/docs/api/update_callrail_tracking): Set the tracking phone numbers on a company's CallRail connection. They replace the list whole. The webhook signing key is set in the app. - [Refresh sources](https://headhoncho.app/docs/api/refresh_sources): Clear the Call center source stamped on a company's jobs, pull all its CallRail history again and re-read every call, so each job's source is worked out afresh. - [Sync ad platform](https://headhoncho.app/docs/api/sync_ad_platform): Pull a company's latest campaigns and spend from one ad platform now. The hourly sync does this on its own. ### Imports - [List import systems](https://headhoncho.app/docs/api/list_import_systems): The systems a book can be imported from, and for each the steps to get its file out, what the file cannot carry, and which one this workspace used last. - [Get import fields](https://headhoncho.app/docs/api/get_import_fields): Every field an import reads, for the jobs file and the money file: its label, its tier and what leaving it blank costs. - [Get import template](https://headhoncho.app/docs/api/get_import_template): A CSV to fill in, with every column the import reads and three example rows, for the jobs file, the money file or a payments list. - [Stage import](https://headhoncho.app/docs/api/stage_import): Send one export file (CSV or Excel) and get back what each column looks like and the mapping we propose. Nothing is imported yet. - [List import statuses](https://headhoncho.app/docs/api/list_import_statuses): The status words the staged files use, how many rows carry each, and which of our statuses each should land on. Nothing is written. - [List import job types](https://headhoncho.app/docs/api/list_import_job_types): The job-type words the staged files use, how many rows carry each, and which of our job types each should land on. Nothing is written. - [Preview import](https://headhoncho.app/docs/api/preview_import): Read the staged files against this workspace and say what an import would do, row by row: what lands, what is already here, what is refused and why. - [Rehearse import](https://headhoncho.app/docs/api/rehearse_import): Run the whole import for real inside one step that is then thrown away, and say what it would have landed and refused. Nothing is kept. - [Commit import](https://headhoncho.app/docs/api/commit_import): Import every clean row of the staged files: the jobs, then the money on them. Rows already here are skipped, so sending it twice adds nothing. ## Get a key Make a key in the app at [Automations, then API keys](https://app.headhoncho.app/automations/api). Choose the companies it reaches, the access it has per area, and whether personal details are hidden. The key is shown once. The full walk-through is on [API keys](https://headhoncho.app/docs/api/keys). Then make your first call. It tells you who the key acts as, which companies it reaches and the statuses, job types and technicians to use in commands: ```bash curl "https://api.headhoncho.app/api/v1/whoami" \ -H "Authorization: Bearer hh_live_..." ``` The answer is shown on [Whoami](https://headhoncho.app/docs/api/whoami). ## Connect an AI app Claude Code, Cursor and any other MCP client that sends a header can use the same 138 endpoints as tools, with the same names and arguments. Point the client at `https://api.headhoncho.app/mcp` and send your key as `Authorization: Bearer hh_live_...`. Setup for each client is on [the MCP server](https://headhoncho.app/docs/api/mcp). A key only ever reaches the companies and areas you gave it. ## The same records in the app Everything the API returns is something the app already shows. [The Jobs panel](https://headhoncho.app/docs/jobs) draws the jobs. [The Raw data board](https://headhoncho.app/docs/marketing/raw-data) draws the raw rows. [Offline conversion tracking](https://headhoncho.app/offline-conversion-tracking) explains why the click id matters. [Multiple companies](https://headhoncho.app/docs/companies) explains how one login holds many client businesses, which is what a key's company list is made of. ## Build with it - [Recipes](https://headhoncho.app/docs/api/recipes): a web form that makes a job, payments copied to your books, and a Zapier step. - [Building with HeadHoncho](https://headhoncho.app/docs/api/agents): short rules for a coding agent. - [Changelog and versioning](https://headhoncho.app/docs/api/changelog): what changed, and the promise that v1 does not break. - Every page has a search box at the top, and a try-it box that builds your call. ## What is coming A group of endpoints arrives when the owner approves it, and an endpoint is never built without appearing on [the roadmap](https://headhoncho.app/docs/api/roadmap) first. ## Machine-readable copies - Every page here has a Markdown twin: add `.md` to its address, for example [this page as Markdown](https://headhoncho.app/docs/api.md). - The whole surface as data: [catalog.json](https://headhoncho.app/docs/api/catalog.json). - An OpenAPI 3.1 file for code generators: [openapi.json](https://headhoncho.app/docs/api/openapi.json), or the same file as [openapi.yaml](https://headhoncho.app/docs/api/openapi.yaml). - All of these docs in one Markdown file, for an AI agent: [llms-full.txt](https://headhoncho.app/docs/api/llms-full.txt). - The search index the boxes use: [search.json](https://headhoncho.app/docs/api/search.json). - The site-wide guide for agents: [llms.txt](https://headhoncho.app/llms.txt). --- # API keys HeadHoncho API keys let your code reach the companies you pick, at the access you pick, and nothing else. Page: https://headhoncho.app/docs/api/keys | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## Make a key HeadHoncho API keys are made in the app, at Automations, then API keys: [https://app.headhoncho.app/automations/api](https://app.headhoncho.app/automations/api). Only a person signed in to the workspace can make one. 1. Open Automations, then API keys, and choose to make a key. 2. Name it for what will use it, such as "Reporting laptop". The name shows in the job history of anything it changes. 3. Pick the companies it reaches. It sees no others. 4. Set its access for each area, at read or do. 5. Under Advanced, turn on "hide personal details" if the key should not see who the customers are. It is off unless you turn it on. 6. Make the key and copy it. It looks like `hh_live_...` and is shown once. ## Access per area A key holds each area at **read** or **do**. Read lets it look. Do lets it change things as well. A call that needs do on an area the key holds only at read is refused with [`read_only`](https://headhoncho.app/docs/api/errors#read_only), and a call to an area the key does not hold is refused with [`no_access`](https://headhoncho.app/docs/api/errors#no_access). | Area | In the key as | Read lets it call | Do lets it call | | --- | --- | --- | --- | | **Jobs** | `jobs` | [List jobs](https://headhoncho.app/docs/api/list_jobs), [Get job](https://headhoncho.app/docs/api/get_job), [Get job history](https://headhoncho.app/docs/api/get_job_history), [Get job log](https://headhoncho.app/docs/api/get_job_log), [List situations](https://headhoncho.app/docs/api/list_situations), [List events](https://headhoncho.app/docs/api/list_events), [List event types](https://headhoncho.app/docs/api/list_event_types), [List job photos](https://headhoncho.app/docs/api/list_job_photos), [Get photo](https://headhoncho.app/docs/api/get_photo), [Get calendar](https://headhoncho.app/docs/api/get_calendar), [List unscheduled jobs](https://headhoncho.app/docs/api/list_unscheduled_jobs), [Export jobs](https://headhoncho.app/docs/api/export_jobs), [Search jobs](https://headhoncho.app/docs/api/search_jobs), [Get automatic status](https://headhoncho.app/docs/api/get_automatic_status), [Get job detour](https://headhoncho.app/docs/api/get_job_detour), [List job reassignments](https://headhoncho.app/docs/api/list_job_reassignments), [List calendar reassignments](https://headhoncho.app/docs/api/list_calendar_reassignments), [List import systems](https://headhoncho.app/docs/api/list_import_systems), [Get import fields](https://headhoncho.app/docs/api/get_import_fields), [Get import template](https://headhoncho.app/docs/api/get_import_template), [List import statuses](https://headhoncho.app/docs/api/list_import_statuses), [List import job types](https://headhoncho.app/docs/api/list_import_job_types), [Preview import](https://headhoncho.app/docs/api/preview_import), [Rehearse import](https://headhoncho.app/docs/api/rehearse_import), [List clients](https://headhoncho.app/docs/api/list_clients), [Get client](https://headhoncho.app/docs/api/get_client), [List needs you](https://headhoncho.app/docs/api/list_needs_you) | [Create job](https://headhoncho.app/docs/api/create_job), [Update job](https://headhoncho.app/docs/api/update_job), [Change job status](https://headhoncho.app/docs/api/change_job_status), [Assign worker](https://headhoncho.app/docs/api/assign_worker), [Unassign worker](https://headhoncho.app/docs/api/unassign_worker), [Add job note](https://headhoncho.app/docs/api/add_job_note), [Update job note](https://headhoncho.app/docs/api/update_job_note), [Delete job note](https://headhoncho.app/docs/api/delete_job_note), [Set job cut](https://headhoncho.app/docs/api/set_job_cut), [Release job status](https://headhoncho.app/docs/api/release_job_status), [Resolve job detour](https://headhoncho.app/docs/api/resolve_job_detour), [Archive job](https://headhoncho.app/docs/api/archive_job), [Unarchive job](https://headhoncho.app/docs/api/unarchive_job), [Trash job](https://headhoncho.app/docs/api/trash_job), [Restore job](https://headhoncho.app/docs/api/restore_job), [Upload photo](https://headhoncho.app/docs/api/upload_photo), [Delete photo](https://headhoncho.app/docs/api/delete_photo), [Bulk change status](https://headhoncho.app/docs/api/bulk_change_status), [Bulk assign worker](https://headhoncho.app/docs/api/bulk_assign_worker), [Bulk unassign worker](https://headhoncho.app/docs/api/bulk_unassign_worker), [Bulk add note](https://headhoncho.app/docs/api/bulk_add_note), [Bulk archive jobs](https://headhoncho.app/docs/api/bulk_archive_jobs), [Bulk unarchive jobs](https://headhoncho.app/docs/api/bulk_unarchive_jobs), [Bulk trash jobs](https://headhoncho.app/docs/api/bulk_trash_jobs), [Bulk restore jobs](https://headhoncho.app/docs/api/bulk_restore_jobs), [Stage import](https://headhoncho.app/docs/api/stage_import), [Commit import](https://headhoncho.app/docs/api/commit_import), [Create client](https://headhoncho.app/docs/api/create_client), [Update client](https://headhoncho.app/docs/api/update_client), [Delete client](https://headhoncho.app/docs/api/delete_client), [Schedule follow up](https://headhoncho.app/docs/api/schedule_follow_up), [Update follow up](https://headhoncho.app/docs/api/update_follow_up), [Resolve follow up](https://headhoncho.app/docs/api/resolve_follow_up), [Cancel follow up](https://headhoncho.app/docs/api/cancel_follow_up) | | **Money** | `money` | [Get job money](https://headhoncho.app/docs/api/get_job_money), [List field reports](https://headhoncho.app/docs/api/list_field_reports), [List balances](https://headhoncho.app/docs/api/list_balances), [Get balance statement](https://headhoncho.app/docs/api/get_balance_statement), [List closed balances](https://headhoncho.app/docs/api/list_closed_balances) | [Record payment](https://headhoncho.app/docs/api/record_payment), [Void payment](https://headhoncho.app/docs/api/void_payment), [Record expense](https://headhoncho.app/docs/api/record_expense), [Void expense](https://headhoncho.app/docs/api/void_expense), [Book field report](https://headhoncho.app/docs/api/book_field_report), [Dismiss field report](https://headhoncho.app/docs/api/dismiss_field_report), [Add expense type](https://headhoncho.app/docs/api/add_expense_type), [Update expense type](https://headhoncho.app/docs/api/update_expense_type), [Close balance](https://headhoncho.app/docs/api/close_balance), [Record payout](https://headhoncho.app/docs/api/record_payout), [Void closed balance](https://headhoncho.app/docs/api/void_closed_balance), [Hold back job](https://headhoncho.app/docs/api/hold_back_job), [Put back job](https://headhoncho.app/docs/api/put_back_job), [Post monthly pay](https://headhoncho.app/docs/api/post_monthly_pay) | | **Leads** | `leads` | [List leads](https://headhoncho.app/docs/api/list_leads), [Get lead](https://headhoncho.app/docs/api/get_lead), [List conversion reviews](https://headhoncho.app/docs/api/list_conversion_reviews) | [Create lead](https://headhoncho.app/docs/api/create_lead), [Update lead](https://headhoncho.app/docs/api/update_lead), [Mark lead lost](https://headhoncho.app/docs/api/mark_lead_lost), [Pass lead](https://headhoncho.app/docs/api/pass_lead), [Book lead](https://headhoncho.app/docs/api/book_lead), [Dismiss lead](https://headhoncho.app/docs/api/dismiss_lead), [Review conversion](https://headhoncho.app/docs/api/review_conversion) | | **Team** | `team` | [List technicians](https://headhoncho.app/docs/api/list_technicians), [Get worker](https://headhoncho.app/docs/api/get_worker) | [Create worker](https://headhoncho.app/docs/api/create_worker), [Update worker](https://headhoncho.app/docs/api/update_worker) | | **Statistics and marketing** | `stats` | [Get statistics summary](https://headhoncho.app/docs/api/get_statistics_summary), [Get statistics areas](https://headhoncho.app/docs/api/get_statistics_areas), [List area jobs](https://headhoncho.app/docs/api/list_area_jobs), [List job pins](https://headhoncho.app/docs/api/list_job_pins), [List ad accounts](https://headhoncho.app/docs/api/list_ad_accounts), [List campaigns](https://headhoncho.app/docs/api/list_campaigns), [List agency jobs](https://headhoncho.app/docs/api/list_agency_jobs) | Nothing in this area | | **Raw data** | `raw` | [List tables](https://headhoncho.app/docs/api/list_tables), [Read table](https://headhoncho.app/docs/api/read_table), [Export table](https://headhoncho.app/docs/api/export_table) | Nothing in this area | | **Click IDs and conversions** | `conv` | [Get job conversion](https://headhoncho.app/docs/api/get_job_conversion), [Get click id report](https://headhoncho.app/docs/api/get_click_id_report), [Export click id report](https://headhoncho.app/docs/api/export_click_id_report) | Nothing in this area | | **Company settings** | `settings` | [List webhooks](https://headhoncho.app/docs/api/list_webhooks), [Get webhook](https://headhoncho.app/docs/api/get_webhook), [List webhook deliveries](https://headhoncho.app/docs/api/list_webhook_deliveries), [Get settings](https://headhoncho.app/docs/api/get_settings), [Get agency feed](https://headhoncho.app/docs/api/get_agency_feed) | [Add webhook](https://headhoncho.app/docs/api/add_webhook), [Change webhook](https://headhoncho.app/docs/api/change_webhook), [Remove webhook](https://headhoncho.app/docs/api/remove_webhook), [Send webhook test](https://headhoncho.app/docs/api/send_webhook_test), [Redeliver webhook](https://headhoncho.app/docs/api/redeliver_webhook), [Update company](https://headhoncho.app/docs/api/update_company), [Create company](https://headhoncho.app/docs/api/create_company), [Update organization](https://headhoncho.app/docs/api/update_organization), [Add job type](https://headhoncho.app/docs/api/add_job_type), [Update job type](https://headhoncho.app/docs/api/update_job_type), [Update job status](https://headhoncho.app/docs/api/update_job_status), [Set status band](https://headhoncho.app/docs/api/set_status_band), [Replace job status](https://headhoncho.app/docs/api/replace_job_status), [Add job status](https://headhoncho.app/docs/api/add_job_status), [Reorder line](https://headhoncho.app/docs/api/reorder_line), [Update agency feed](https://headhoncho.app/docs/api/update_agency_feed), [Sync callrail](https://headhoncho.app/docs/api/sync_callrail), [Update callrail tracking](https://headhoncho.app/docs/api/update_callrail_tracking), [Refresh sources](https://headhoncho.app/docs/api/refresh_sources), [Sync ad platform](https://headhoncho.app/docs/api/sync_ad_platform) | These endpoints need no particular area, so any key can call them: [Whoami](https://headhoncho.app/docs/api/whoami), [List companies](https://headhoncho.app/docs/api/list_companies), [Get company](https://headhoncho.app/docs/api/get_company), [Get usage](https://headhoncho.app/docs/api/get_usage), [Get credits](https://headhoncho.app/docs/api/get_credits), [List plans](https://headhoncho.app/docs/api/list_plans). ## Companies A key reaches only the companies you choose when you make it. Asking for any other company answers [`out_of_scope`](https://headhoncho.app/docs/api/errors#out_of_scope), and a record in another company answers [`not_found`](https://headhoncho.app/docs/api/errors#not_found), as if it did not exist. The first call to make is [Whoami](https://headhoncho.app/docs/api/whoami): it lists the companies the key reaches, with their ids and time zones. How one login holds many client businesses is explained on [multiple companies](https://headhoncho.app/docs/companies). ## Hide personal details A key sees customers' names, phones and street addresses unless you hide them. Turn on "hide personal details", under Advanced when you make the key, for a key that reports to a team, or for a key given to an AI client that does not need to know who the customers are. Details about a person, such as a name or a phone number, are then kept out of what the key can see. [Whoami](https://headhoncho.app/docs/api/whoami) shows the setting back to your code as `hide_personal_details`, so a program can tell. ## Use the key Send the key on every call in the `Authorization` header: ```http Authorization: Bearer hh_live_... ``` A call without it answers [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key). A key we did not issue, or one that was revoked, answers [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key). ## Shown once, rotated, revoked - **Shown once.** The app shows the key at the moment you make it and never again. Store it where only the program that needs it can read it. - **Rotate.** If a key is lost or might have leaked, rotate it in the app. You get a new secret, and your code takes the new one. - **Revoke.** Revoke a key to stop it for good. Every call made with it afterwards answers `unknown_key`. There is no limit on how often a key may call. Each answered call costs 1 credit from the workspace's balance; see [credits](https://headhoncho.app/docs/api/errors#credits). For the rest of how calls work, read [the model](https://headhoncho.app/docs/api/model). To use a key from an AI client such as Claude Code or Cursor, see [the MCP server](https://headhoncho.app/docs/api/mcp). --- # The model: reads, commands and idempotency The HeadHoncho API model is the app's own: reads over its read models, commands through its command names, and every command safe to repeat. Page: https://headhoncho.app/docs/api/model | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## Reads and commands The HeadHoncho API model is the app's own, in two halves. A **read** is a `GET` over a read model the app already draws, so a number in the API is the number on the screen. A **command** is a `POST` that runs one of the app's own commands and answers with an acknowledgement. Nothing is computed in the API that the app does not compute. Commands are posted to `/api/v1/commands/`, where the verb is the app's own command name: | Verb | Endpoint | Call | | --- | --- | --- | | `create-job` | [Create job](https://headhoncho.app/docs/api/create_job) | `POST /api/v1/commands/create-job` | | `update-job` | [Update job](https://headhoncho.app/docs/api/update_job) | `POST /api/v1/commands/update-job` | | `change-job-status` | [Change job status](https://headhoncho.app/docs/api/change_job_status) | `POST /api/v1/commands/change-job-status` | | `assign-worker` | [Assign worker](https://headhoncho.app/docs/api/assign_worker) | `POST /api/v1/commands/assign-worker` | | `unassign-worker` | [Unassign worker](https://headhoncho.app/docs/api/unassign_worker) | `POST /api/v1/commands/unassign-worker` | | `add-job-note` | [Add job note](https://headhoncho.app/docs/api/add_job_note) | `POST /api/v1/commands/add-job-note` | | `update-job-note` | [Update job note](https://headhoncho.app/docs/api/update_job_note) | `POST /api/v1/commands/update-job-note` | | `delete-job-note` | [Delete job note](https://headhoncho.app/docs/api/delete_job_note) | `POST /api/v1/commands/delete-job-note` | | `set-job-cut` | [Set job cut](https://headhoncho.app/docs/api/set_job_cut) | `POST /api/v1/commands/set-job-cut` | | `release-job-status` | [Release job status](https://headhoncho.app/docs/api/release_job_status) | `POST /api/v1/commands/release-job-status` | | `resolve-job-detour` | [Resolve job detour](https://headhoncho.app/docs/api/resolve_job_detour) | `POST /api/v1/commands/resolve-job-detour` | | `archive-job` | [Archive job](https://headhoncho.app/docs/api/archive_job) | `POST /api/v1/commands/archive-job` | | `unarchive-job` | [Unarchive job](https://headhoncho.app/docs/api/unarchive_job) | `POST /api/v1/commands/unarchive-job` | | `trash-job` | [Trash job](https://headhoncho.app/docs/api/trash_job) | `POST /api/v1/commands/trash-job` | | `restore-job` | [Restore job](https://headhoncho.app/docs/api/restore_job) | `POST /api/v1/commands/restore-job` | | `record-payment` | [Record payment](https://headhoncho.app/docs/api/record_payment) | `POST /api/v1/commands/record-payment` | | `void-payment` | [Void payment](https://headhoncho.app/docs/api/void_payment) | `POST /api/v1/commands/void-payment` | | `record-expense` | [Record expense](https://headhoncho.app/docs/api/record_expense) | `POST /api/v1/commands/record-expense` | | `void-expense` | [Void expense](https://headhoncho.app/docs/api/void_expense) | `POST /api/v1/commands/void-expense` | | `book-field-report` | [Book field report](https://headhoncho.app/docs/api/book_field_report) | `POST /api/v1/commands/book-field-report` | | `dismiss-field-report` | [Dismiss field report](https://headhoncho.app/docs/api/dismiss_field_report) | `POST /api/v1/commands/dismiss-field-report` | | `add-expense-type` | [Add expense type](https://headhoncho.app/docs/api/add_expense_type) | `POST /api/v1/commands/add-expense-type` | | `update-expense-type` | [Update expense type](https://headhoncho.app/docs/api/update_expense_type) | `POST /api/v1/commands/update-expense-type` | | `close-balance` | [Close balance](https://headhoncho.app/docs/api/close_balance) | `POST /api/v1/commands/close-balance` | | `record-payout` | [Record payout](https://headhoncho.app/docs/api/record_payout) | `POST /api/v1/commands/record-payout` | | `void-closed-balance` | [Void closed balance](https://headhoncho.app/docs/api/void_closed_balance) | `POST /api/v1/commands/void-closed-balance` | | `hold-back-job` | [Hold back job](https://headhoncho.app/docs/api/hold_back_job) | `POST /api/v1/commands/hold-back-job` | | `put-back-job` | [Put back job](https://headhoncho.app/docs/api/put_back_job) | `POST /api/v1/commands/put-back-job` | | `post-monthly-pay` | [Post monthly pay](https://headhoncho.app/docs/api/post_monthly_pay) | `POST /api/v1/commands/post-monthly-pay` | | `create-worker` | [Create worker](https://headhoncho.app/docs/api/create_worker) | `POST /api/v1/commands/create-worker` | | `update-worker` | [Update worker](https://headhoncho.app/docs/api/update_worker) | `POST /api/v1/commands/update-worker` | | `add-webhook` | [Add webhook](https://headhoncho.app/docs/api/add_webhook) | `POST /api/v1/commands/add-webhook` | | `change-webhook` | [Change webhook](https://headhoncho.app/docs/api/change_webhook) | `POST /api/v1/commands/change-webhook` | | `remove-webhook` | [Remove webhook](https://headhoncho.app/docs/api/remove_webhook) | `POST /api/v1/commands/remove-webhook` | | `test-webhook` | [Send webhook test](https://headhoncho.app/docs/api/send_webhook_test) | `POST /api/v1/commands/test-webhook` | | `redeliver-webhook` | [Redeliver webhook](https://headhoncho.app/docs/api/redeliver_webhook) | `POST /api/v1/commands/redeliver-webhook` | | `request-job-photo` | [Upload photo](https://headhoncho.app/docs/api/upload_photo) | `POST /api/v1/commands/request-job-photo` | | `delete-job-photo` | [Delete photo](https://headhoncho.app/docs/api/delete_photo) | `POST /api/v1/commands/delete-job-photo` | | `bulk-change-job-status` | [Bulk change status](https://headhoncho.app/docs/api/bulk_change_status) | `POST /api/v1/commands/bulk-change-job-status` | | `bulk-assign-worker` | [Bulk assign worker](https://headhoncho.app/docs/api/bulk_assign_worker) | `POST /api/v1/commands/bulk-assign-worker` | | `bulk-unassign-worker` | [Bulk unassign worker](https://headhoncho.app/docs/api/bulk_unassign_worker) | `POST /api/v1/commands/bulk-unassign-worker` | | `bulk-add-job-note` | [Bulk add note](https://headhoncho.app/docs/api/bulk_add_note) | `POST /api/v1/commands/bulk-add-job-note` | | `bulk-archive-jobs` | [Bulk archive jobs](https://headhoncho.app/docs/api/bulk_archive_jobs) | `POST /api/v1/commands/bulk-archive-jobs` | | `bulk-unarchive-jobs` | [Bulk unarchive jobs](https://headhoncho.app/docs/api/bulk_unarchive_jobs) | `POST /api/v1/commands/bulk-unarchive-jobs` | | `bulk-trash-jobs` | [Bulk trash jobs](https://headhoncho.app/docs/api/bulk_trash_jobs) | `POST /api/v1/commands/bulk-trash-jobs` | | `bulk-restore-jobs` | [Bulk restore jobs](https://headhoncho.app/docs/api/bulk_restore_jobs) | `POST /api/v1/commands/bulk-restore-jobs` | | `update-company` | [Update company](https://headhoncho.app/docs/api/update_company) | `POST /api/v1/commands/update-company` | | `create-company` | [Create company](https://headhoncho.app/docs/api/create_company) | `POST /api/v1/commands/create-company` | | `update-organization` | [Update organization](https://headhoncho.app/docs/api/update_organization) | `POST /api/v1/commands/update-organization` | | `add-job-type` | [Add job type](https://headhoncho.app/docs/api/add_job_type) | `POST /api/v1/commands/add-job-type` | | `update-job-type` | [Update job type](https://headhoncho.app/docs/api/update_job_type) | `POST /api/v1/commands/update-job-type` | | `update-job-status` | [Update job status](https://headhoncho.app/docs/api/update_job_status) | `POST /api/v1/commands/update-job-status` | | `set-status-band` | [Set status band](https://headhoncho.app/docs/api/set_status_band) | `POST /api/v1/commands/set-status-band` | | `replace-job-status` | [Replace job status](https://headhoncho.app/docs/api/replace_job_status) | `POST /api/v1/commands/replace-job-status` | | `add-job-status` | [Add job status](https://headhoncho.app/docs/api/add_job_status) | `POST /api/v1/commands/add-job-status` | | `reorder-line` | [Reorder line](https://headhoncho.app/docs/api/reorder_line) | `POST /api/v1/commands/reorder-line` | | `stage-import` | [Stage import](https://headhoncho.app/docs/api/stage_import) | `POST /api/v1/commands/stage-import` | | `preview-import` | [Preview import](https://headhoncho.app/docs/api/preview_import) | `POST /api/v1/commands/preview-import` | | `rehearse-import` | [Rehearse import](https://headhoncho.app/docs/api/rehearse_import) | `POST /api/v1/commands/rehearse-import` | | `commit-import` | [Commit import](https://headhoncho.app/docs/api/commit_import) | `POST /api/v1/commands/commit-import` | | `create-client` | [Create client](https://headhoncho.app/docs/api/create_client) | `POST /api/v1/commands/create-client` | | `update-client` | [Update client](https://headhoncho.app/docs/api/update_client) | `POST /api/v1/commands/update-client` | | `delete-client` | [Delete client](https://headhoncho.app/docs/api/delete_client) | `POST /api/v1/commands/delete-client` | | `create-lead` | [Create lead](https://headhoncho.app/docs/api/create_lead) | `POST /api/v1/commands/create-lead` | | `update-lead` | [Update lead](https://headhoncho.app/docs/api/update_lead) | `POST /api/v1/commands/update-lead` | | `mark-lead-lost` | [Mark lead lost](https://headhoncho.app/docs/api/mark_lead_lost) | `POST /api/v1/commands/mark-lead-lost` | | `pass-lead` | [Pass lead](https://headhoncho.app/docs/api/pass_lead) | `POST /api/v1/commands/pass-lead` | | `make-job-from-lead` | [Book lead](https://headhoncho.app/docs/api/book_lead) | `POST /api/v1/commands/make-job-from-lead` | | `trash-leads` | [Dismiss lead](https://headhoncho.app/docs/api/dismiss_lead) | `POST /api/v1/commands/trash-leads` | | `review-conversion` | [Review conversion](https://headhoncho.app/docs/api/review_conversion) | `POST /api/v1/commands/review-conversion` | | `schedule-follow-up` | [Schedule follow up](https://headhoncho.app/docs/api/schedule_follow_up) | `POST /api/v1/commands/schedule-follow-up` | | `update-follow-up` | [Update follow up](https://headhoncho.app/docs/api/update_follow_up) | `POST /api/v1/commands/update-follow-up` | | `resolve-follow-up` | [Resolve follow up](https://headhoncho.app/docs/api/resolve_follow_up) | `POST /api/v1/commands/resolve-follow-up` | | `cancel-follow-up` | [Cancel follow up](https://headhoncho.app/docs/api/cancel_follow_up) | `POST /api/v1/commands/cancel-follow-up` | | `update-agency-feed` | [Update agency feed](https://headhoncho.app/docs/api/update_agency_feed) | `POST /api/v1/commands/update-agency-feed` | | `sync-callrail` | [Sync callrail](https://headhoncho.app/docs/api/sync_callrail) | `POST /api/v1/commands/sync-callrail` | | `update-callrail-tracking` | [Update callrail tracking](https://headhoncho.app/docs/api/update_callrail_tracking) | `POST /api/v1/commands/update-callrail-tracking` | | `refresh-sources` | [Refresh sources](https://headhoncho.app/docs/api/refresh_sources) | `POST /api/v1/commands/refresh-sources` | | `sync-ad-platform` | [Sync ad platform](https://headhoncho.app/docs/api/sync_ad_platform) | `POST /api/v1/commands/sync-ad-platform` | ## Every command needs an Idempotency-Key Send an `Idempotency-Key` header with every command. Any unique string works, and a new random UUID per intended action is the usual choice. - The same key with the same body returns the first answer and runs nothing twice. A retry after a dropped connection is safe. - The same key with a different body is refused with status 409 and [`idempotency_mismatch`](https://headhoncho.app/docs/api/errors#idempotency_mismatch). - No key at all is refused with status 400 and [`missing_idempotency_key`](https://headhoncho.app/docs/api/errors#missing_idempotency_key). ## See your own write Every command answer carries a `position`: where the change landed in the event log. A read accepts `?after=` and waits up to two seconds for the read model to catch up, so the next read shows what you just wrote. [Get job history](https://headhoncho.app/docs/api/get_job_history) returns the same positions beside each event. ```bash curl -X POST ".../commands/add-job-note" ... # answer: {"accepted": true, "job_id": "job_1203", "position": 88411, ...} curl ".../jobs/job_1203?after=88411" ... ``` ## Lists, cursors and counts A list answers `{items, next, count}`. `items` is the page, `count` is how many match in all, and `next` is an opaque cursor for the following page, or `null` at the end. Pass the cursor back as `cursor` and change nothing else. Do not read inside it: it is not a promise about how paging works. [List jobs](https://headhoncho.app/docs/api/list_jobs) is the example; [Read table](https://headhoncho.app/docs/api/read_table) pages with `limit` and `offset` instead, because a raw table has a stable order. ## Ids, dates and money - Ids are opaque text such as `cmp_14f5` or `job_1138`. Keep them exactly as given. - Dates and times are ISO 8601. A date range is read in the company's time zone. - Money is a plain number in the company's currency, and the answer says which currency. ## Building blocks, never the app The API offers records, raw rows and single commands. It never offers a board, a question, a dashboard, a widget, a layout or an automation. The purpose is to let you build your own tool on top of the same facts, not to rebuild HeadHoncho from outside. The one report in the API, the Google Click ID report, is there because the customer hands its file to Google and it must exist outside the app. The [roadmap](https://headhoncho.app/docs/api/roadmap) lists what is planned and what is never offered. Next: [API keys](https://headhoncho.app/docs/api/keys) for access, [errors and credits](https://headhoncho.app/docs/api/errors) for what a refusal looks like, and [the MCP server](https://headhoncho.app/docs/api/mcp) for AI apps. The records themselves are described on [the Jobs panel](https://headhoncho.app/docs/jobs) and [the Raw data board](https://headhoncho.app/docs/marketing/raw-data). --- # Errors and credits HeadHoncho API errors share one envelope and name their reason, and every call tells you what it cost in credits and what is left. Page: https://headhoncho.app/docs/api/errors | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The error envelope HeadHoncho API errors all have one shape. The HTTP status says the class of refusal, and the body names the reason: ```json { "error": { "code": "invalid", "message": "Some fields were refused. See fields.", "fields": { "client_phone": "This is required." }, "docs": "https://headhoncho.app/docs/api/errors#invalid" } } ``` - `code` is the stable name to branch on. - `message` is the sentence to show a person. - `fields` names each refused field, on a 422 only. - `docs` links to the entry for the code on this page. The MCP server prints the same code. A refusal always names its reason. ## Every error code Each code is an anchor, so `https://headhoncho.app/docs/api/errors#invalid` goes straight to its entry. ### missing_key **Status 401.** Send your key as Authorization: Bearer hh_live_... Every endpoint can return it. ### unknown_key **Status 401.** That key is not one we issued, or it was revoked. Every endpoint can return it. ### no_access **Status 403.** This credential does not reach that. Ask the person who made it for access. Returned by 132 of the 138 endpoints. ### read_only **Status 403.** This credential may read this area but not change it. Returned by 77 of the 138 endpoints. ### not_found **Status 404.** No such record in the companies this credential reaches. Returned by 101 of the 138 endpoints. ### out_of_scope **Status 404.** No such company in the companies this credential reaches. Returned by 36 of the 138 endpoints. ### unknown_endpoint **Status 404.** No such endpoint. GET /api/v1/ lists every one. Returned by 0 of the 138 endpoints. ### unknown_command **Status 404.** No such command. GET /api/v1/ lists every one. Returned by 0 of the 138 endpoints. ### invalid **Status 422.** Some fields were refused. See fields. Returned by 128 of the 138 endpoints. ### missing_idempotency_key **Status 400.** Send an Idempotency-Key header on every command. Returned by 79 of the 138 endpoints. ### idempotency_mismatch **Status 409.** This Idempotency-Key was used with a different body. Returned by 79 of the 138 endpoints. ### idempotency_in_progress **Status 409.** A command with this Idempotency-Key is still running. Wait a moment and send it again. Returned by 79 of the 138 endpoints. ### no_credits **Status 402.** Out of credits. Top up on Settings › Credits, or turn on auto top-up. Every endpoint can return it. ### plan_limit **Status 402.** Your plan does not include this. Upgrade on Settings › Plan. Returned by 0 of the 138 endpoints. ### not_connected **Status 409.** This company has not connected that provider yet. Returned by 3 of the 138 endpoints. ### report_off **Status 409.** This report is turned off. Turn it on in Statistics › Reports. Returned by 2 of the 138 endpoints. ## Credits, not rate limits There is no rate limit and no monthly quota: call as often as your work needs. Each answered call costs 1 credit from the workspace's balance, the same credits the automations spend. A refused call costs nothing, and a command resent with the same `Idempotency-Key` gets its first answer back and costs nothing again. Every answer carries the headers that tell you where you stand: - `X-HH-Credits-Charged`: what this call cost. - `X-HH-Credits-Left`: the balance after it. - `X-Request-Id`: the call's id. Send your own and it is echoed back; quote it when you write to us. At zero credits a call is refused with status 402 and [`no_credits`](#no_credits), and nothing runs. Top up on Settings › Credits, or turn on auto top-up, and send it again. [Who am I](https://headhoncho.app/docs/api/whoami) prints the balance in `credits`. Keys and their access are on [API keys](https://headhoncho.app/docs/api/keys). --- # The MCP server The HeadHoncho MCP server lets Claude Code, Cursor and other MCP clients use your jobs and raw data as tools, with the access your key holds. Page: https://headhoncho.app/docs/api/mcp | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## Connect an AI app The HeadHoncho MCP server is at `https://api.headhoncho.app/mcp`. Every client connects with an API key, sent as `Authorization: Bearer hh_live_...`. It speaks MCP over Streamable HTTP and answers JSON only. It offers the same 138 endpoints as tools, with the same names and the same arguments as the [REST API](https://headhoncho.app/docs/api), so what one can do the other can do. ## Claude.ai and ChatGPT The Claude.ai and ChatGPT web connectors need a sign-in screen, which HeadHoncho does not offer. Use Claude Code, Cursor or another client that sends a header. ## Claude Code Add the server with a key from [API keys](https://headhoncho.app/docs/api/keys): ```bash claude mcp add --transport http headhoncho https://api.headhoncho.app/mcp \ --header "Authorization: Bearer hh_live_..." ``` ## Cursor Put this in `.cursor/mcp.json`: ```json { "mcpServers": { "headhoncho": { "url": "https://api.headhoncho.app/mcp", "headers": { "Authorization": "Bearer hh_live_..." } } } } ``` ## The tools Each tool is documented on its own page, with its arguments, its answer and an example prompt on the "Your AI" tab. A tool tells the app whether it only reads, whether it can destroy anything (none can), and whether it is safe to repeat (all are). | Tool | Group | Needs | Effect | | --- | --- | --- | --- | | [`whoami`](https://headhoncho.app/docs/api/whoami) | Account | any key | Reads only | | [`list_companies`](https://headhoncho.app/docs/api/list_companies) | Account | any key | Reads only | | [`get_company`](https://headhoncho.app/docs/api/get_company) | Account | any key | Reads only | | [`get_usage`](https://headhoncho.app/docs/api/get_usage) | Account | any key | Reads only | | [`get_credits`](https://headhoncho.app/docs/api/get_credits) | Account | any key | Reads only | | [`list_plans`](https://headhoncho.app/docs/api/list_plans) | Account | any key | Reads only | | [`list_events`](https://headhoncho.app/docs/api/list_events) | Changes | read on Jobs | Reads only | | [`list_event_types`](https://headhoncho.app/docs/api/list_event_types) | Changes | read on Jobs | Reads only | | [`list_webhooks`](https://headhoncho.app/docs/api/list_webhooks) | Webhooks | read on Company settings | Reads only | | [`get_webhook`](https://headhoncho.app/docs/api/get_webhook) | Webhooks | read on Company settings | Reads only | | [`list_webhook_deliveries`](https://headhoncho.app/docs/api/list_webhook_deliveries) | Webhooks | read on Company settings | Reads only | | [`add_webhook`](https://headhoncho.app/docs/api/add_webhook) | Webhook commands | do on Company settings | Changes a job | | [`change_webhook`](https://headhoncho.app/docs/api/change_webhook) | Webhook commands | do on Company settings | Changes a job | | [`remove_webhook`](https://headhoncho.app/docs/api/remove_webhook) | Webhook commands | do on Company settings | Changes a job | | [`send_webhook_test`](https://headhoncho.app/docs/api/send_webhook_test) | Webhook commands | do on Company settings | Changes a job | | [`redeliver_webhook`](https://headhoncho.app/docs/api/redeliver_webhook) | Webhook commands | do on Company settings | Changes a job | | [`list_jobs`](https://headhoncho.app/docs/api/list_jobs) | Jobs | read on Jobs | Reads only | | [`get_job`](https://headhoncho.app/docs/api/get_job) | Jobs | read on Jobs | Reads only | | [`get_job_history`](https://headhoncho.app/docs/api/get_job_history) | Jobs | read on Jobs | Reads only | | [`get_job_log`](https://headhoncho.app/docs/api/get_job_log) | Jobs | read on Jobs | Reads only | | [`list_situations`](https://headhoncho.app/docs/api/list_situations) | Jobs | read on Jobs | Reads only | | [`list_job_photos`](https://headhoncho.app/docs/api/list_job_photos) | Jobs | read on Jobs | Reads only | | [`get_photo`](https://headhoncho.app/docs/api/get_photo) | Jobs | read on Jobs | Reads only | | [`get_calendar`](https://headhoncho.app/docs/api/get_calendar) | Jobs | read on Jobs | Reads only | | [`list_unscheduled_jobs`](https://headhoncho.app/docs/api/list_unscheduled_jobs) | Jobs | read on Jobs | Reads only | | [`export_jobs`](https://headhoncho.app/docs/api/export_jobs) | Jobs | read on Jobs | Reads only | | [`search_jobs`](https://headhoncho.app/docs/api/search_jobs) | Jobs | read on Jobs | Reads only | | [`get_automatic_status`](https://headhoncho.app/docs/api/get_automatic_status) | Jobs | read on Jobs | Reads only | | [`get_job_detour`](https://headhoncho.app/docs/api/get_job_detour) | Jobs | read on Jobs | Reads only | | [`list_job_reassignments`](https://headhoncho.app/docs/api/list_job_reassignments) | Jobs | read on Jobs | Reads only | | [`list_calendar_reassignments`](https://headhoncho.app/docs/api/list_calendar_reassignments) | Jobs | read on Jobs | Reads only | | [`create_job`](https://headhoncho.app/docs/api/create_job) | Job commands | do on Jobs | Changes a job | | [`update_job`](https://headhoncho.app/docs/api/update_job) | Job commands | do on Jobs | Changes a job | | [`change_job_status`](https://headhoncho.app/docs/api/change_job_status) | Job commands | do on Jobs | Changes a job | | [`assign_worker`](https://headhoncho.app/docs/api/assign_worker) | Job commands | do on Jobs | Changes a job | | [`unassign_worker`](https://headhoncho.app/docs/api/unassign_worker) | Job commands | do on Jobs | Changes a job | | [`add_job_note`](https://headhoncho.app/docs/api/add_job_note) | Job commands | do on Jobs | Changes a job | | [`update_job_note`](https://headhoncho.app/docs/api/update_job_note) | Job commands | do on Jobs | Changes a job | | [`delete_job_note`](https://headhoncho.app/docs/api/delete_job_note) | Job commands | do on Jobs | Changes a job | | [`set_job_cut`](https://headhoncho.app/docs/api/set_job_cut) | Job commands | do on Jobs | Changes a job | | [`release_job_status`](https://headhoncho.app/docs/api/release_job_status) | Job commands | do on Jobs | Changes a job | | [`resolve_job_detour`](https://headhoncho.app/docs/api/resolve_job_detour) | Job commands | do on Jobs | Changes a job | | [`archive_job`](https://headhoncho.app/docs/api/archive_job) | Job commands | do on Jobs | Changes a job | | [`unarchive_job`](https://headhoncho.app/docs/api/unarchive_job) | Job commands | do on Jobs | Changes a job | | [`trash_job`](https://headhoncho.app/docs/api/trash_job) | Job commands | do on Jobs | Changes a job | | [`restore_job`](https://headhoncho.app/docs/api/restore_job) | Job commands | do on Jobs | Changes a job | | [`upload_photo`](https://headhoncho.app/docs/api/upload_photo) | Job commands | do on Jobs | Changes a job | | [`delete_photo`](https://headhoncho.app/docs/api/delete_photo) | Job commands | do on Jobs | Changes a job | | [`bulk_change_status`](https://headhoncho.app/docs/api/bulk_change_status) | Many jobs at once | do on Jobs | Changes a job | | [`bulk_assign_worker`](https://headhoncho.app/docs/api/bulk_assign_worker) | Many jobs at once | do on Jobs | Changes a job | | [`bulk_unassign_worker`](https://headhoncho.app/docs/api/bulk_unassign_worker) | Many jobs at once | do on Jobs | Changes a job | | [`bulk_add_note`](https://headhoncho.app/docs/api/bulk_add_note) | Many jobs at once | do on Jobs | Changes a job | | [`bulk_archive_jobs`](https://headhoncho.app/docs/api/bulk_archive_jobs) | Many jobs at once | do on Jobs | Changes a job | | [`bulk_unarchive_jobs`](https://headhoncho.app/docs/api/bulk_unarchive_jobs) | Many jobs at once | do on Jobs | Changes a job | | [`bulk_trash_jobs`](https://headhoncho.app/docs/api/bulk_trash_jobs) | Many jobs at once | do on Jobs | Changes a job | | [`bulk_restore_jobs`](https://headhoncho.app/docs/api/bulk_restore_jobs) | Many jobs at once | do on Jobs | Changes a job | | [`list_clients`](https://headhoncho.app/docs/api/list_clients) | Clients | read on Jobs | Reads only | | [`get_client`](https://headhoncho.app/docs/api/get_client) | Clients | read on Jobs | Reads only | | [`create_client`](https://headhoncho.app/docs/api/create_client) | Client commands | do on Jobs | Changes a job | | [`update_client`](https://headhoncho.app/docs/api/update_client) | Client commands | do on Jobs | Changes a job | | [`delete_client`](https://headhoncho.app/docs/api/delete_client) | Client commands | do on Jobs | Changes a job | | [`list_leads`](https://headhoncho.app/docs/api/list_leads) | Leads | read on Leads | Reads only | | [`get_lead`](https://headhoncho.app/docs/api/get_lead) | Leads | read on Leads | Reads only | | [`list_needs_you`](https://headhoncho.app/docs/api/list_needs_you) | Leads | read on Jobs | Reads only | | [`list_conversion_reviews`](https://headhoncho.app/docs/api/list_conversion_reviews) | Leads | read on Leads | Reads only | | [`create_lead`](https://headhoncho.app/docs/api/create_lead) | Lead commands | do on Leads | Changes a job | | [`update_lead`](https://headhoncho.app/docs/api/update_lead) | Lead commands | do on Leads | Changes a job | | [`mark_lead_lost`](https://headhoncho.app/docs/api/mark_lead_lost) | Lead commands | do on Leads | Changes a job | | [`pass_lead`](https://headhoncho.app/docs/api/pass_lead) | Lead commands | do on Leads | Changes a job | | [`book_lead`](https://headhoncho.app/docs/api/book_lead) | Lead commands | do on Leads | Changes a job | | [`dismiss_lead`](https://headhoncho.app/docs/api/dismiss_lead) | Lead commands | do on Leads | Changes a job | | [`review_conversion`](https://headhoncho.app/docs/api/review_conversion) | Lead commands | do on Leads | Changes a job | | [`schedule_follow_up`](https://headhoncho.app/docs/api/schedule_follow_up) | Lead commands | do on Jobs | Changes a job | | [`update_follow_up`](https://headhoncho.app/docs/api/update_follow_up) | Lead commands | do on Jobs | Changes a job | | [`resolve_follow_up`](https://headhoncho.app/docs/api/resolve_follow_up) | Lead commands | do on Jobs | Changes a job | | [`cancel_follow_up`](https://headhoncho.app/docs/api/cancel_follow_up) | Lead commands | do on Jobs | Changes a job | | [`get_job_money`](https://headhoncho.app/docs/api/get_job_money) | Job money | read on Money | Reads only | | [`list_field_reports`](https://headhoncho.app/docs/api/list_field_reports) | Job money | read on Money | Reads only | | [`record_payment`](https://headhoncho.app/docs/api/record_payment) | Money commands | do on Money | Changes a job | | [`void_payment`](https://headhoncho.app/docs/api/void_payment) | Money commands | do on Money | Changes a job | | [`record_expense`](https://headhoncho.app/docs/api/record_expense) | Money commands | do on Money | Changes a job | | [`void_expense`](https://headhoncho.app/docs/api/void_expense) | Money commands | do on Money | Changes a job | | [`book_field_report`](https://headhoncho.app/docs/api/book_field_report) | Money commands | do on Money | Changes a job | | [`dismiss_field_report`](https://headhoncho.app/docs/api/dismiss_field_report) | Money commands | do on Money | Changes a job | | [`add_expense_type`](https://headhoncho.app/docs/api/add_expense_type) | Money commands | do on Money | Changes a job | | [`update_expense_type`](https://headhoncho.app/docs/api/update_expense_type) | Money commands | do on Money | Changes a job | | [`list_balances`](https://headhoncho.app/docs/api/list_balances) | Balances | read on Money | Reads only | | [`get_balance_statement`](https://headhoncho.app/docs/api/get_balance_statement) | Balances | read on Money | Reads only | | [`list_closed_balances`](https://headhoncho.app/docs/api/list_closed_balances) | Balances | read on Money | Reads only | | [`close_balance`](https://headhoncho.app/docs/api/close_balance) | Balance commands | do on Money | Changes a job | | [`record_payout`](https://headhoncho.app/docs/api/record_payout) | Balance commands | do on Money | Changes a job | | [`void_closed_balance`](https://headhoncho.app/docs/api/void_closed_balance) | Balance commands | do on Money | Changes a job | | [`hold_back_job`](https://headhoncho.app/docs/api/hold_back_job) | Balance commands | do on Money | Changes a job | | [`put_back_job`](https://headhoncho.app/docs/api/put_back_job) | Balance commands | do on Money | Changes a job | | [`post_monthly_pay`](https://headhoncho.app/docs/api/post_monthly_pay) | Balance commands | do on Money | Changes a job | | [`list_technicians`](https://headhoncho.app/docs/api/list_technicians) | Team | read on Team | Reads only | | [`get_worker`](https://headhoncho.app/docs/api/get_worker) | Team | read on Team | Reads only | | [`create_worker`](https://headhoncho.app/docs/api/create_worker) | Team commands | do on Team | Changes a job | | [`update_worker`](https://headhoncho.app/docs/api/update_worker) | Team commands | do on Team | Changes a job | | [`get_statistics_summary`](https://headhoncho.app/docs/api/get_statistics_summary) | Statistics | read on Statistics and marketing | Reads only | | [`get_statistics_areas`](https://headhoncho.app/docs/api/get_statistics_areas) | Statistics | read on Statistics and marketing | Reads only | | [`list_area_jobs`](https://headhoncho.app/docs/api/list_area_jobs) | Statistics | read on Statistics and marketing | Reads only | | [`list_job_pins`](https://headhoncho.app/docs/api/list_job_pins) | Statistics | read on Statistics and marketing | Reads only | | [`list_ad_accounts`](https://headhoncho.app/docs/api/list_ad_accounts) | Marketing | read on Statistics and marketing | Reads only | | [`list_campaigns`](https://headhoncho.app/docs/api/list_campaigns) | Marketing | read on Statistics and marketing | Reads only | | [`list_agency_jobs`](https://headhoncho.app/docs/api/list_agency_jobs) | Marketing | read on Statistics and marketing | Reads only | | [`get_agency_feed`](https://headhoncho.app/docs/api/get_agency_feed) | Marketing | read on Company settings | Reads only | | [`list_tables`](https://headhoncho.app/docs/api/list_tables) | Raw data | read on Raw data | Reads only | | [`read_table`](https://headhoncho.app/docs/api/read_table) | Raw data | read on Raw data | Reads only | | [`export_table`](https://headhoncho.app/docs/api/export_table) | Raw data | read on Raw data | Reads only | | [`get_job_conversion`](https://headhoncho.app/docs/api/get_job_conversion) | Click IDs and conversions | read on Click IDs and conversions | Reads only | | [`get_click_id_report`](https://headhoncho.app/docs/api/get_click_id_report) | Click IDs and conversions | read on Click IDs and conversions | Reads only | | [`export_click_id_report`](https://headhoncho.app/docs/api/export_click_id_report) | Click IDs and conversions | read on Click IDs and conversions | Reads only | | [`get_settings`](https://headhoncho.app/docs/api/get_settings) | Company settings | read on Company settings | Reads only | | [`update_company`](https://headhoncho.app/docs/api/update_company) | Settings commands | do on Company settings | Changes a job | | [`create_company`](https://headhoncho.app/docs/api/create_company) | Settings commands | do on Company settings | Changes a job | | [`update_organization`](https://headhoncho.app/docs/api/update_organization) | Settings commands | do on Company settings | Changes a job | | [`add_job_type`](https://headhoncho.app/docs/api/add_job_type) | Settings commands | do on Company settings | Changes a job | | [`update_job_type`](https://headhoncho.app/docs/api/update_job_type) | Settings commands | do on Company settings | Changes a job | | [`update_job_status`](https://headhoncho.app/docs/api/update_job_status) | Settings commands | do on Company settings | Changes a job | | [`set_status_band`](https://headhoncho.app/docs/api/set_status_band) | Settings commands | do on Company settings | Changes a job | | [`replace_job_status`](https://headhoncho.app/docs/api/replace_job_status) | Settings commands | do on Company settings | Changes a job | | [`add_job_status`](https://headhoncho.app/docs/api/add_job_status) | Settings commands | do on Company settings | Changes a job | | [`reorder_line`](https://headhoncho.app/docs/api/reorder_line) | Settings commands | do on Company settings | Changes a job | | [`update_agency_feed`](https://headhoncho.app/docs/api/update_agency_feed) | Settings commands | do on Company settings | Changes a job | | [`sync_callrail`](https://headhoncho.app/docs/api/sync_callrail) | Settings commands | do on Company settings | Changes a job | | [`update_callrail_tracking`](https://headhoncho.app/docs/api/update_callrail_tracking) | Settings commands | do on Company settings | Changes a job | | [`refresh_sources`](https://headhoncho.app/docs/api/refresh_sources) | Settings commands | do on Company settings | Changes a job | | [`sync_ad_platform`](https://headhoncho.app/docs/api/sync_ad_platform) | Settings commands | do on Company settings | Changes a job | | [`list_import_systems`](https://headhoncho.app/docs/api/list_import_systems) | Imports | read on Jobs | Reads only | | [`get_import_fields`](https://headhoncho.app/docs/api/get_import_fields) | Imports | read on Jobs | Reads only | | [`get_import_template`](https://headhoncho.app/docs/api/get_import_template) | Imports | read on Jobs | Reads only | | [`stage_import`](https://headhoncho.app/docs/api/stage_import) | Imports | do on Jobs | Changes a job | | [`list_import_statuses`](https://headhoncho.app/docs/api/list_import_statuses) | Imports | read on Jobs | Reads only | | [`list_import_job_types`](https://headhoncho.app/docs/api/list_import_job_types) | Imports | read on Jobs | Reads only | | [`preview_import`](https://headhoncho.app/docs/api/preview_import) | Imports | read on Jobs | Changes a job | | [`rehearse_import`](https://headhoncho.app/docs/api/rehearse_import) | Imports | read on Jobs | Changes a job | | [`commit_import`](https://headhoncho.app/docs/api/commit_import) | Imports | do on Jobs | Changes a job | ## The docs, inside the connection The reference is also offered as MCP resources, so an agent can read it without leaving the connection. `resources/list` names the overview, the guides (keys, the model, errors and credits, this page, recipes, rules for coding agents and the changelog) and the page of every tool. `resources/read` returns one as Markdown. Start with the errors guide when a call is refused. ## Answers a model can use Every tool answer starts with one line that says what came back, then the full answer as text, and carries the same answer as structured content. A refusal names its `error.code` and the fix. ## Downloads come back as a link [Export table](https://headhoncho.app/docs/api/export_table) and [Export click id report](https://headhoncho.app/docs/api/export_click_id_report) return a file. Over MCP the answer is a one-time download link that works for five minutes, so the file never passes through the AI. Open the link yourself, or have your own code fetch it. ## Who did it When an AI client changes a job with a key, the job's history records it as the key's name, then "for" and the member the key acts as, for example "Reporting laptop, for Ariel T.". [Get job history](https://headhoncho.app/docs/api/get_job_history) returns that name in `by`. A tool call costs the same credit a REST call does; see [credits](https://headhoncho.app/docs/api/errors#credits). ## Safe to retry Every tool that changes something takes an optional `idempotency_key`. When an app is not sure a call went through, it sends the same key again and gets the first answer back; nothing runs twice and nothing is charged twice. Tools that take something out of the books or out of sight, such as Delete a job or Void a payment, are marked destructive, so the app asks the person first. To understand what the tools do before you let an app use them, start with [the model](https://headhoncho.app/docs/api/model). Keys are on [API keys](https://headhoncho.app/docs/api/keys). --- # Recipes Three walkthroughs for the HeadHoncho API: a web form that makes a job, payments copied to your books, and a Zapier step that makes jobs or starts on a webhook. Page: https://headhoncho.app/docs/api/recipes | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## How to read these Three walkthroughs for the jobs people build first. Each one uses only calls that are in the [reference](https://headhoncho.app/docs/api), with the same parameters. Every answered call costs 1 credit, a refusal costs nothing, and there is no rate limit; see [credits](https://headhoncho.app/docs/api/errors#credits). Replace `hh_live_...` with your own key from [API keys](https://headhoncho.app/docs/api/keys). Before any of them, call [Whoami](https://headhoncho.app/docs/api/whoami) once: it gives you the `company_id`, `job_type_id` and technician ids the examples use. ## Recipe 1: a web form becomes a job Goal: when a customer fills in the form on a client's website, a job appears in HeadHoncho. You need a key with **do** on the Jobs area. 1. Call [Whoami](https://headhoncho.app/docs/api/whoami) and keep the client's `company_id` and the `job_type_id` for the kind of work the form is for. 2. When the form is submitted, your server calls [Create job](https://headhoncho.app/docs/api/create_job). Use `"intent": "draft"` to open a lead, or leave it out to open a booked job. 3. Send the form's own submission id as the `Idempotency-Key`. If the customer presses the button twice, or your server retries after a dropped connection, HeadHoncho returns the first answer and makes one job. See [the model](https://headhoncho.app/docs/api/model#idempotency). 4. If the answer is a 422, the `error.fields` object names each field to fix. Show those to the customer. Any other error carries a `code` you can look up on [errors](https://headhoncho.app/docs/api/errors). 5. To show a confirmation, read the job back with [Get job](https://headhoncho.app/docs/api/get_job) and `?after=` from the first answer: the read waits until the new job is there. See [see your own write](https://headhoncho.app/docs/api/model#position). ```python import requests API = "https://api.headhoncho.app/api/v1" KEY = "hh_live_..." # keep it on your server, never in the page def job_from_form(form): """Called once for each form submission your site receives.""" response = requests.post( f"{API}/commands/create-job", headers={ "Authorization": f"Bearer {KEY}", # The form's own submission id: a double submit makes one job. "Idempotency-Key": f"web-form-{form['submission_id']}", }, json={ "company_id": "cmp_14f5", "client_name": form["name"], "client_phone": form["phone"], "address": { "line1": form["street"], "city": form["city"], "state": form["state"], "postal_code": form["zip"], }, "job_type_id": "jt_02", "notes": form["message"], "intent": "draft", # a lead, until someone books it }, ) if response.status_code == 422: return {"ok": False, "fields": response.json()["error"]["fields"]} response.raise_for_status() return {"ok": True, "job_id": response.json()["job_id"]} ``` Do the call from your server, not from the visitor's browser. A key in a web page is a key anyone can copy. ## Recipe 2: payments to bookkeeping Goal: every month, copy what was paid, charged and spent on closed jobs into your books. You need a key with **read** on Jobs and on Money. 1. Page through the closed jobs for the month with [List jobs](https://headhoncho.app/docs/api/list_jobs): `status=closed`, a `from` date and `limit=200`. `from` and `to` pick jobs by the day they were created, so start earlier than the month. Each answer has `items` and a `next` cursor. Pass `next` back as `cursor` until it is `null`. 2. For each job, call [Get job money](https://headhoncho.app/docs/api/get_job_money). Its `lines` hold every payment, fee and expense on the job, and its `currency` names the money. 3. Skip any line with `voided: true`. A voided line counts in no figure. 4. Keep only the lines whose `on` date is inside the month. Write one row per line. `amount` is a plain number: keep it as a decimal in your books, not text. `on` is a date in the company's time zone. 5. Going the other way, when your books show a payment that HeadHoncho does not, record it with [Record payment](https://headhoncho.app/docs/api/record_payment). Send an `Idempotency-Key` built from your own payment id, so running the job twice never records it twice. ```python import requests API = "https://api.headhoncho.app/api/v1" HEADERS = {"Authorization": "Bearer hh_live_..."} def closed_jobs(created_from): cursor = None while True: params = {"status": "closed", "from": created_from, "limit": 200} if cursor: params["cursor"] = cursor page = requests.get(f"{API}/jobs", headers=HEADERS, params=params).json() yield from page["items"] cursor = page["next"] if cursor is None: return def ledger_rows(first_day, last_day): # "from" picks jobs by the day they were created, so start earlier than the # month and keep only the lines whose own date is inside it. for job in closed_jobs("2026-01-01"): money = requests.get(f"{API}/jobs/{job['id']}/money", headers=HEADERS).json() for line in money["lines"]: if line["voided"]: continue # a voided line counts in no figure if not first_day <= line["on"] <= last_day: continue # dates are YYYY-MM-DD, so text order works yield { "job": money["job"]["number"], "date": line["on"], "kind": line["kind"], # payment, fee, expense or cut "amount": line["amount"], # a number, in money["currency"] "memo": line["memo"], } ``` This walk costs one credit for each page of jobs and one for each job. For a large month, run it once, not on a timer. ## Recipe 3: Zapier Goal: a new row in a spreadsheet, or a form your client already uses, creates a job without code. You need a key with **do** on Jobs. Zapier's menus change; what matters is the URL, the three headers and the JSON body. 1. Step 1, the trigger: pick the app that holds the lead, such as a new spreadsheet row or a new form response. 2. Step 2, the action: add **Webhooks by Zapier** and choose the **Custom Request** event. It calls [Create job](https://headhoncho.app/docs/api/create_job). Fill it in as the table says. 3. Use the trigger's row id as the `Idempotency-Key`. If Zapier replays the step, HeadHoncho makes one job. 4. Test the step. The answer has `accepted: true` and the new `job_id`. Add a third step that writes `job_id` back to the row if you want a link between them. | Zapier field | Value | | --- | --- | | Event | Custom Request (Webhooks by Zapier) | | Method | `POST` | | URL | `https://api.headhoncho.app/api/v1/commands/create-job` | | Headers | `Authorization` = `Bearer hh_live_...`, `Content-Type` = `application/json`, `Idempotency-Key` = the sheet row id from step 1 | | Data | The JSON body below, with the row's columns dragged in | ```json { "company_id": "cmp_14f5", "client_name": "", "client_phone": "", "address": { "line1": "", "city": "", "state": "", "postal_code": "" }, "notes": "", "intent": "draft" } ``` The same pattern works for any command: change the URL to the command's page, and send the parameters that page lists. Recording a payment from another app is [Record payment](https://headhoncho.app/docs/api/record_payment) in the same way. To start a Zap when something changes in HeadHoncho, do not poll. Use a webhook: 1. Make a Zap whose trigger is **Webhooks by Zapier** and the event **Catch Hook**. Zapier gives you an address that starts with `https://hooks.zapier.com/`. 2. Add that address as a webhook, in the app or with [Add webhook](https://headhoncho.app/docs/api/add_webhook), and pick the kinds of change that should start the Zap, such as `job.created` or `job.status_changed`. 3. Send a test with [Send webhook test](https://headhoncho.app/docs/api/send_webhook_test) so Zapier learns the fields, then build the rest of the Zap from them. 4. Zapier does not check our signature; it only needs the address. The address is the secret, so keep it private. Each change is one run of the Zap, and costs one credit. Read [webhooks](https://headhoncho.app/docs/api/webhooks) for what is sent and how retries work. Next: [the model](https://headhoncho.app/docs/api/model) for the rules every call follows, [errors](https://headhoncho.app/docs/api/errors) for what a refusal says, and [building with HeadHoncho](https://headhoncho.app/docs/api/agents) if a coding agent is writing the code. --- # Webhooks A HeadHoncho webhook calls your address with each job or lead change you ask for, signed and retried. Page: https://headhoncho.app/docs/api/webhooks | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## What we send A webhook is an address you give us once. After that, each time a job or a lead changes in a way you asked for, we send one signed `POST` to it, so Zapier, n8n or your own code never has to keep asking. It is the same change that [List events](https://headhoncho.app/docs/api/list_events) would show you, pushed instead of polled, with the same facts and the same rules about who may see what: a webhook only ever carries what the key that made it can read. Each request has one change in a JSON body: ```json { "id": "88402", "event": "job.status_changed", "at": "2026-10-26T14:02:11Z", "by": "Reporting laptop, for Ariel T.", "job": { "id": "job_1138", "number": 1138, "company_id": "cmp_14f5" }, "data": { "status": "Dispatched", "status_slug": "dispatched", "previous_status": "Scheduled" } } ``` `id` is the change's id. `event` is its kind. `job` says which job, and `data` holds a few plain facts about the change. Money amounts, customer details and message text are never in it: read the job for those with [Get job](https://headhoncho.app/docs/api/get_job). Changes start from the moment you add the webhook; the past is not sent. ## The headers | Header | What it holds | | --- | --- | | `Content-Type` | `application/json` | | `User-Agent` | `HeadHoncho-Webhooks/1` | | `X-HeadHoncho-Event` | The kind of change, such as `job.status_changed`. | | `X-HeadHoncho-Event-Id` | The id of this change. The same change always has the same id, on every retry and every resend. Drop a repeat by it. | | `X-HeadHoncho-Timestamp` | Seconds since 1970 when this try was signed. | | `X-HeadHoncho-Signature` | `sha256=` and the hex HMAC-SHA256 of the timestamp, a dot, and the raw body, made with your signing secret. | ## Add a webhook In the app, open Automations, then API keys, then Webhooks, and choose Add webhook. Or call [Add webhook](https://headhoncho.app/docs/api/add_webhook) with a key that has **do** on Company settings and **read** on Jobs. Give it an address, the kinds of change you want, and, if you like, the companies. The answer carries the signing secret, `whsec_...`, **shown once**. Lose it and use [Change webhook](https://headhoncho.app/docs/api/change_webhook) with `rotate_secret` to get a new one. [Send webhook test](https://headhoncho.app/docs/api/send_webhook_test) sends a signed test event named `webhook.test` to one webhook and says what your address answered, so you can check your code before a real change arrives. A test is not retried and costs no delivery credit. ## Check the signature Anyone can post to a public address, so check that a call really came from HeadHoncho before you act on it. The signature is `sha256=` and the hex HMAC-SHA256 of the timestamp header, a dot, and the **raw** body, made with your signing secret. Use the body as it arrived: parsing it and printing it again changes the bytes and breaks the match. Refuse a timestamp more than five minutes old, and compare in constant time. With cURL and openssl. This is a worked example; the digest is the real one for this secret, timestamp and body: ```bash # The secret is the one shown when you added the webhook. SECRET="whsec_example_secret" TIMESTAMP="1798380131" # the X-HeadHoncho-Timestamp header BODY='{"id":"88402","event":"job.status_changed","at":"2026-10-26T14:02:11Z","by":"Reporting laptop, for Ariel T.","job":{"id":"job_1138","number":1138,"company_id":"cmp_14f5"},"data":{"status":"Dispatched","status_slug":"dispatched","previous_status":"Scheduled"}}' # the raw body, exactly as received printf '%s.%s' "$TIMESTAMP" "$BODY" \ | openssl dgst -sha256 -hmac "$SECRET" -hex \ | sed 's/^.* //' # 6f37ea5413a1815b0d707ddbe5145aa449e5480e6189470232694e1c2d1b307f # Put sha256= in front and compare it with the X-HeadHoncho-Signature header. ``` In Python: ```python import hashlib import hmac import time def is_from_headhoncho(secret: str, headers, raw_body: bytes) -> bool: """`raw_body` is the request body exactly as received, before any JSON parsing.""" stamp = headers["X-HeadHoncho-Timestamp"] if abs(time.time() - int(stamp)) > 300: # older than five minutes: refuse return False signed = stamp.encode() + b"." + raw_body expected = "sha256=" + hmac.new(secret.encode(), signed, hashlib.sha256).hexdigest() return hmac.compare_digest(expected, headers["X-HeadHoncho-Signature"]) ``` In JavaScript: ```javascript import crypto from "node:crypto"; // `rawBody` is the request body exactly as received, a Buffer or a string, // before any JSON parsing. In Express use express.raw({ type: "application/json" }). export function isFromHeadHoncho(secret, headers, rawBody) { const stamp = headers["x-headhoncho-timestamp"]; if (Math.abs(Date.now() / 1000 - Number(stamp)) > 300) return false; // older than five minutes const expected = "sha256=" + crypto .createHmac("sha256", secret) .update(`${stamp}.`) .update(rawBody) .digest("hex"); const given = Buffer.from(headers["x-headhoncho-signature"] || ""); const wanted = Buffer.from(expected); return given.length === wanted.length && crypto.timingSafeEqual(given, wanted); } ``` ## What to answer Answer with any `2xx` status within eight seconds, and do the work after answering. Anything else counts as a failure and is tried again: a `4xx` or `5xx`, no answer, a slow answer, an invalid certificate, and a redirect, which we do not follow. ## Retries, pausing and resending - A failed change is tried again after 30 seconds, then after a minute, then twice as long each time, up to four hours between tries, for 24 hours. After that it is marked failed and left alone. - Every try is kept with its time, the answer code and how long it took. Read them with [List webhook deliveries](https://headhoncho.app/docs/api/list_webhook_deliveries), or on the Webhooks tab. - [Redeliver webhook](https://headhoncho.app/docs/api/redeliver_webhook) sends one delivery again within a minute. - A webhook that has failed for two hours, with at least ten failed tries, is paused, and the person who made it is told in the app and on their phone. Fix the address, then resume it with [Change webhook](https://headhoncho.app/docs/api/change_webhook) and `paused` set to false. What it missed is sent, in order. - Delivery is at least once. A change can arrive twice, and two changes can arrive out of order. Drop repeats by `X-HeadHoncho-Event-Id`, and order by `at`. ## Credits and plans Webhooks come with every plan, Free included, like keys. Each change delivered costs **one credit**, however many tries it takes; a failed try costs nothing, and a change is never charged twice. The calls that manage webhooks cost a credit each, like any call. At zero credits we send nothing: the webhook is paused with the reason `no_credits`, the changes wait, and it carries on by itself when credits are back. The balance is in [Get credits](https://headhoncho.app/docs/api/get_credits). ## Which addresses we call - Only `https`, on port 443 or a port from 1024 up, with no user name or password in the address. - Only public addresses. We refuse a name that points at a private network, the machine itself, a link-local or cloud metadata address, or the 100.64.0.0/10 range. We check when you add the webhook and again before every send, after looking the name up, because a name can be re-pointed. - We connect to the address we checked, verify the certificate against the name, follow no redirects, and read at most 16 KB of your answer. ## Kinds of change Choose from these when you add a webhook. They are the same kinds the [List event types](https://headhoncho.app/docs/api/list_event_types) lists, and the same ones [List events](https://headhoncho.app/docs/api/list_events) returns. | Kind | When it is sent | What `data` holds | | --- | --- | --- | | [`job.created`](https://headhoncho.app/docs/api/list_event_types) | A job or a lead was opened. | `status`, `job_type`, `quoted`, `scheduled_start`, `scheduled_end`, `source` | | [`job.details_changed`](https://headhoncho.app/docs/api/list_event_types) | A job's facts changed: the customer, the address, the schedule, the price, the type or the notes. | `job_type`, `quoted`, `scheduled_start`, `scheduled_end` | | [`job.status_changed`](https://headhoncho.app/docs/api/list_event_types) | A job moved to another status. | `status`, `status_slug`, `previous_status` | | [`job.assigned`](https://headhoncho.app/docs/api/list_event_types) | A technician or subcontractor was put on a job. | `technician_id`, `technician` | | [`job.unassigned`](https://headhoncho.app/docs/api/list_event_types) | A technician or subcontractor was taken off a job. | `technician_id`, `technician` | | [`job.archived`](https://headhoncho.app/docs/api/list_event_types) | A job was archived. | Nothing more | | [`job.unarchived`](https://headhoncho.app/docs/api/list_event_types) | A job was taken out of the archive. | Nothing more | | [`job.restored`](https://headhoncho.app/docs/api/list_event_types) | A job came back from Trash. | Nothing more | | [`job_note.added`](https://headhoncho.app/docs/api/list_event_types) | A note was added to a job. Read the job's history for the words. | Nothing more | | [`job_payment.recorded`](https://headhoncho.app/docs/api/list_event_types) | A payment was recorded on a job. Read the job's money for the amount. | Nothing more | ## The calls - [Add webhook](https://headhoncho.app/docs/api/add_webhook), [Change webhook](https://headhoncho.app/docs/api/change_webhook) and [Remove webhook](https://headhoncho.app/docs/api/remove_webhook) manage an address. - [List webhooks](https://headhoncho.app/docs/api/list_webhooks) and [Get webhook](https://headhoncho.app/docs/api/get_webhook) read them. A key sees the webhooks it made. - [List webhook deliveries](https://headhoncho.app/docs/api/list_webhook_deliveries), [Redeliver webhook](https://headhoncho.app/docs/api/redeliver_webhook) and [Send webhook test](https://headhoncho.app/docs/api/send_webhook_test) show what was sent and send again. Next: [errors](https://headhoncho.app/docs/api/errors) for what a refusal says, and [recipes](https://headhoncho.app/docs/api/recipes#zapier) for a Zapier trigger that uses a webhook. --- # Building with HeadHoncho Short rules for a coding agent writing against the HeadHoncho API: auth, idempotency, pages, errors and which endpoint does which job. Page: https://headhoncho.app/docs/api/agents | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## Rules for a coding agent This page is written for the coding agent that is about to write code against the HeadHoncho API, and for the person who gave it the task. It is short on purpose. Every rule is the same on every endpoint. The facts about one endpoint are on its own page, and the whole surface is one file: [catalog.json](https://headhoncho.app/docs/api/catalog.json). The [OpenAPI file](https://headhoncho.app/docs/api/openapi.json) ([YAML](https://headhoncho.app/docs/api/openapi.yaml)) generates a client. All the docs are also one Markdown file: [llms-full.txt](https://headhoncho.app/docs/api/llms-full.txt). If the agent is connected over MCP, it can read these pages as resources. ## Paste this into AGENTS.md Put this block in the AGENTS.md, CLAUDE.md or rules file of the repository that calls HeadHoncho. It is generated from the same catalog as the reference, so it stays true. ```markdown ## HeadHoncho API - Base: https://api.headhoncho.app/api/v1. Docs: https://headhoncho.app/docs/api. Whole surface: https://headhoncho.app/docs/api/catalog.json. - Auth: send `Authorization: Bearer hh_live_...` on every call. Never put the key in code that ships to a browser or a repo. A key reaches only the companies and areas it was given. - Start with GET /whoami. It lists the companies, the access per area, and the status, job type and technician ids that commands take. - Every POST /commands/ needs an `Idempotency-Key` header. Make one per intended action and send the same one when you retry. A different body with the same key is refused. - Lists answer {items, next, count}. Pass `next` back as `cursor` until it is null. - After a command, read with `?after=` to see your own write. - Money is a number in the company currency. Times carry an offset. Ids are opaque text. - Branch on `error.code`. A refused field is named in `error.fields`. Do not retry a 4xx. - Each answered call costs 1 credit. There is no rate limit. Do not poll in a loop. ``` ## Auth and reach - One header on every call: `Authorization: Bearer hh_live_...`. Keys are made in the app; see [API keys](https://headhoncho.app/docs/api/keys). - A key holds each area at **read** or **do**. A read-only key calling a command is refused with [`read_only`](https://headhoncho.app/docs/api/errors#read_only). An area the key lacks is [`no_access`](https://headhoncho.app/docs/api/errors#no_access). - A key reaches only the companies it was given. When it reaches several, pass `company_id` on every call that takes one. A company outside the key answers [`out_of_scope`](https://headhoncho.app/docs/api/errors#out_of_scope). - When personal details are hidden, names, phones and streets come back masked. Do not try to work around it. ## Idempotency - Every command needs an `Idempotency-Key` header. Make one for each intended action, and send the same one when you retry that action. - Build the key from something stable, such as your own record id. A random key made inside the retry loop defeats the point. - The same key with a different body is a 409, [`idempotency_mismatch`](https://headhoncho.app/docs/api/errors#idempotency_mismatch). No key is a 400. - Reads need no key. Retry a read freely, but each answered call costs a credit. ## Pages and your own writes - A list answers `{items, next, count}`. Pass `next` back as `cursor` and change nothing else. Stop when `next` is `null`. Never build a cursor yourself. - A raw table pages with `limit` and `offset` instead, because its order is fixed. - A command answers `accepted` and a `position`. Pass `?after=` to the next read and it waits up to two seconds for the read model to catch up. ## Values - Ids are opaque text. Keep them exactly as given. - Money is a plain number in the company's currency, named by `currency` on the answer. A command answer may print an amount as decimal text. Read the Fields table on each page. - Times are ISO 8601 with an offset. A date range is read in the company's time zone. ## Errors - Branch on `error.code`, never on the message. Every code is on [errors](https://headhoncho.app/docs/api/errors) with what causes it and how to fix it. - A 422 [`invalid`](https://headhoncho.app/docs/api/errors#invalid) names each refused field in `error.fields`. Fix the field. Do not resend unchanged. - A 402 [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) means the workspace is out of credits. Stop and tell the person. Retrying does not help. - A 4xx is the caller's to fix. Resend only after a change, and a command only with the same `Idempotency-Key`. ## Which endpoint for which job | To do this | Call | | --- | --- | | See who the key is, its companies and the ids commands take | [Whoami](https://headhoncho.app/docs/api/whoami) | | List jobs and leads, newest first, a page at a time | [List jobs](https://headhoncho.app/docs/api/list_jobs) | | Read one job by id or number | [Get job](https://headhoncho.app/docs/api/get_job) | | Open a job or a lead | [Create job](https://headhoncho.app/docs/api/create_job) | | Move a job to another status | [Change job status](https://headhoncho.app/docs/api/change_job_status) | | Put a technician on a job | [Assign worker](https://headhoncho.app/docs/api/assign_worker) | | Add a note to a job | [Add job note](https://headhoncho.app/docs/api/add_job_note) | | See what a job quoted, collected and left as profit | [Get job money](https://headhoncho.app/docs/api/get_job_money) | | Record a payment on a job | [Record payment](https://headhoncho.app/docs/api/record_payment) | | See what each technician is owed | [List balances](https://headhoncho.app/docs/api/list_balances) | | Read the raw rows an ad platform or call tracker reported | [Read table](https://headhoncho.app/docs/api/read_table) | | Get the file Google Ads needs to credit the jobs | [Export click id report](https://headhoncho.app/docs/api/export_click_id_report) | Every endpoint, by group. Each id is a page at `/docs/api/` and, over MCP, a tool of the same name: - **Account**: `whoami`, `list_companies`, `get_company`, `get_usage`, `get_credits`, `list_plans` - **Changes**: `list_events`, `list_event_types` - **Webhooks**: `list_webhooks`, `get_webhook`, `list_webhook_deliveries` - **Webhook commands**: `add_webhook`, `change_webhook`, `remove_webhook`, `send_webhook_test`, `redeliver_webhook` - **Jobs**: `list_jobs`, `get_job`, `get_job_history`, `get_job_log`, `list_situations`, `list_job_photos`, `get_photo`, `get_calendar`, `list_unscheduled_jobs`, `export_jobs`, `search_jobs`, `get_automatic_status`, `get_job_detour`, `list_job_reassignments`, `list_calendar_reassignments` - **Job commands**: `create_job`, `update_job`, `change_job_status`, `assign_worker`, `unassign_worker`, `add_job_note`, `update_job_note`, `delete_job_note`, `set_job_cut`, `release_job_status`, `resolve_job_detour`, `archive_job`, `unarchive_job`, `trash_job`, `restore_job`, `upload_photo`, `delete_photo` - **Many jobs at once**: `bulk_change_status`, `bulk_assign_worker`, `bulk_unassign_worker`, `bulk_add_note`, `bulk_archive_jobs`, `bulk_unarchive_jobs`, `bulk_trash_jobs`, `bulk_restore_jobs` - **Clients**: `list_clients`, `get_client` - **Client commands**: `create_client`, `update_client`, `delete_client` - **Leads**: `list_leads`, `get_lead`, `list_needs_you`, `list_conversion_reviews` - **Lead commands**: `create_lead`, `update_lead`, `mark_lead_lost`, `pass_lead`, `book_lead`, `dismiss_lead`, `review_conversion`, `schedule_follow_up`, `update_follow_up`, `resolve_follow_up`, `cancel_follow_up` - **Job money**: `get_job_money`, `list_field_reports` - **Money commands**: `record_payment`, `void_payment`, `record_expense`, `void_expense`, `book_field_report`, `dismiss_field_report`, `add_expense_type`, `update_expense_type` - **Balances**: `list_balances`, `get_balance_statement`, `list_closed_balances` - **Balance commands**: `close_balance`, `record_payout`, `void_closed_balance`, `hold_back_job`, `put_back_job`, `post_monthly_pay` - **Team**: `list_technicians`, `get_worker` - **Team commands**: `create_worker`, `update_worker` - **Statistics**: `get_statistics_summary`, `get_statistics_areas`, `list_area_jobs`, `list_job_pins` - **Marketing**: `list_ad_accounts`, `list_campaigns`, `list_agency_jobs`, `get_agency_feed` - **Raw data**: `list_tables`, `read_table`, `export_table` - **Click IDs and conversions**: `get_job_conversion`, `get_click_id_report`, `export_click_id_report` - **Company settings**: `get_settings` - **Settings commands**: `update_company`, `create_company`, `update_organization`, `add_job_type`, `update_job_type`, `update_job_status`, `set_status_band`, `replace_job_status`, `add_job_status`, `reorder_line`, `update_agency_feed`, `sync_callrail`, `update_callrail_tracking`, `refresh_sources`, `sync_ad_platform` - **Imports**: `list_import_systems`, `get_import_fields`, `get_import_template`, `stage_import`, `list_import_statuses`, `list_import_job_types`, `preview_import`, `rehearse_import`, `commit_import` ## Do not - Do not scrape the app or call its own routes. The API is the supported door. - Do not poll in a tight loop. Every answered call costs a credit. Read only what changed, for example the job log with `since`, instead of everything again. - Do not ask for a board, a dashboard or a layout. The API gives records, raw rows and single commands; see [the model](https://headhoncho.app/docs/api/model#building-blocks). - Do not store the key in a repository, a log or a page a browser loads. See also: [recipes](https://headhoncho.app/docs/api/recipes), [the MCP server](https://headhoncho.app/docs/api/mcp) and the [changelog](https://headhoncho.app/docs/api/changelog). --- # Changelog and versioning What changed in the HeadHoncho API and when, and the promise that v1 keeps working as documented. Page: https://headhoncho.app/docs/api/changelog | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The promise: v1 does not break Every address on this site starts with `/api/v1`. That `v1` is a promise. Code that works against v1 today keeps working. ## What we will not do in v1 - Remove or rename an endpoint, a parameter, an answer field or an error code. - Change what a field, a parameter or an error code means, or its type. - Make an optional parameter required. - Change who may call an endpoint to make it stricter for a key that could before. ## What we may do in v1 - Add endpoints, groups and MCP tools. - Add optional parameters, and new fields to an answer. Ignore fields you do not know: your code should not fail on them. - Add values to a list of choices, such as a new status or method. Do not fail on a value you have not seen. - Add error codes. Branch on the codes you know and treat any other as a failure of its HTTP status class. - Fix a bug so that the API does what its page already said. ## If something has to break A change that would break v1 ships as a new version, `/api/v2`, beside it. The notice goes on this page first, and v1 keeps its documented behaviour until then. Nothing changes for your code unless you move it. Each change is listed here with its date, newest first. The reference pages are always the current truth; this page says when it moved. ## What changed ### 2026-10-28: Keys and webhooks on every plan - API keys and webhooks come with every plan now, Free included. Calls still cost a credit each, and a change delivered still costs one credit. ### 2026-10-27: Webhooks: we call your address when a job changes - Webhooks: give us an address and the kinds of change you want, and we send each one as a signed `POST`, retried for 24 hours. A guide shows how to check the signature in cURL, Python and JavaScript. - Eight new calls: add, change, list, get and remove a webhook, send a test event, list a webhook's deliveries and send one again. - One credit per change delivered, however many tries it takes. Webhooks come with Core and up, like keys. ### 2026-10-26: Jobs from start to finish, job money, and credits instead of limits - Jobs have their whole life: change a job, move it between statuses, assign and take off technicians, add, change and remove notes, archive and unarchive, move to Trash and restore. - Job money: read what a job quoted, collected and left as profit; record and void payments and expenses; set a technician's cut; manage expense types. - Balances: see what each technician is owed, read a statement, close a balance, and record or void a payout. - Field reports: list what technicians reported and book or dismiss each one. - There is no rate limit. Each answered call costs 1 credit; a refusal costs nothing. Answers carry `X-HH-Credits-Charged`, `X-HH-Credits-Left` and `X-Request-Id`. At zero credits a call is refused with `no_credits`. - MCP tools that change something take an optional `idempotency_key`. Tools that take something out of the books or out of sight are marked destructive. - MCP tool answers start with a one-line summary, then the full answer, and carry the answer as structured content. The reference, the guides and the error catalog can be read as MCP resources. - The docs gained a table of every field in each answer, a try-it box that builds your call, search, recipes, a page for coding agents and this changelog. - Account: list your companies and read one, your usage, your credits and the plans. - Changes: a feed of what changed on your jobs since a cursor, and the list of change types. - Jobs: photos, the calendar, unscheduled jobs, a jobs file, search, and where a status, a detour or a hand-off stands. - Job commands: back to automatic, resolve a detour, upload and delete a photo. - Many jobs at once: status, assign, unassign, note, archive, unarchive, Trash and restore, up to 200 jobs a call. - Clients: list, read, create, change and delete the people jobs are for. - Leads: list and read leads, send one in, change it, book it as a job, mark it lost, pass on it or dismiss it, review a conversion, and schedule, change, resolve or cancel follow-ups. What needs a person, as a list of jobs and why. - Team: list technicians, read one, add one and change one. - Statistics and marketing: booked jobs and profit for a range, jobs by area, map pins, ad accounts, campaigns and the agency jobs feed. - Company settings: read them, change a company and the workspace, job types, statuses and the status line, and syncs for CallRail and the ad platforms. - Imports: bring jobs over from another system: stage a file, match statuses and job types, preview, rehearse and commit. ### 2026-10-14: The starter - The API opened with sixteen endpoints in five groups: Account, Jobs, Job commands, Raw data, and Click IDs and conversions. - Reads are `GET` over the records the app draws. Commands are `POST` to `/commands/` with an `Idempotency-Key`. - Keys are made in the app, with companies and access per area. Missing something you need? Tell [support](https://headhoncho.app/support). The plan for what comes next is on [the roadmap](https://headhoncho.app/docs/api/roadmap). --- # The API roadmap The HeadHoncho API roadmap lists what is planned by group, and what the API will never offer. Page: https://headhoncho.app/docs/api/roadmap | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## What is there now The HeadHoncho API roadmap starts from what exists: 138 endpoints in 24 groups, **Account**, **Changes**, **Webhooks**, **Webhook commands**, **Jobs**, **Job commands**, **Many jobs at once**, **Clients**, **Client commands**, **Leads**, **Lead commands**, **Job money**, **Money commands**, **Balances**, **Balance commands**, **Team**, **Team commands**, **Statistics**, **Marketing**, **Raw data**, **Click IDs and conversions**, **Company settings**, **Settings commands**, **Imports**. They are on the [overview](https://headhoncho.app/docs/api). ## How a group gets added A group arrives when the owner approves it. An endpoint is never built without appearing on this page first, so nothing in the API is a surprise. We plan by group, never one endpoint at a time. ## Next - **Hand-offs**: passing a job from one technician to the next. - **Claims**: a person claiming their own technician card. ## Later - **Notifications**: the app's own notices, once they carry no customer messages. - **A live try-it box**: calling the API from these pages with your key. ## Never These follow from the building-blocks rule on [the model](https://headhoncho.app/docs/api/model#building-blocks): the API gives records, raw rows and single commands, and does not let anyone rebuild the app from outside. - **Boards**: screens the app draws. - **Board questions**: the questions a board answers. - **Dashboards and widgets**: charts and the layouts that hold them. - **Layouts and saved views**: how the app arranges a screen. - **Drawn reports**: report files and statements with their totals, except the Click ID file. - **Automations**: rules that act for you. - **Communications**: the texts and messages. - **Members**: who has a login. Something you need is not here? Tell [support](https://headhoncho.app/support). For what you can call today, see [the overview](https://headhoncho.app/docs/api), [API keys](https://headhoncho.app/docs/api/keys) and [the MCP server](https://headhoncho.app/docs/api/mcp). --- # Whoami Whoami is a read in the HeadHoncho API. Who this key or app acts as, which companies it reaches, what it may do, and the words to use in commands: statuses, job types and technicians. Page: https://headhoncho.app/docs/api/whoami | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **Whoami**, HeadHoncho API v1. It is a read, sent to the base address `https://api.headhoncho.app`. `GET /api/v1/whoami` Any key can call it. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). Send your key as `Authorization: Bearer hh_live_...`. See [API keys](https://headhoncho.app/docs/api/keys). ## Parameters This call takes no parameters. ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back The workspace, the credential, the companies it may name, its access per area, the credits left, and the lookups a command needs: every status, job type and technician, with ids, and with Money access the expense types and payment methods. Lookups are carried here so a client never has to guess a name. For a website: intake.address, when present, is where its forms, phone taps and visits go instead of this API; it takes them even while the API is down. It never changes a record. It only reads the companies the key reaches. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `workspace` | object | The workspace. | | `workspace.id` | id (text) | The id of this record. Ids are opaque text: keep them exactly as given. | | `workspace.name` | text | The name, as the app shows it. | | `credential` | object | The credential. | | `credential.kind` | text | What sort of thing this is. | | `credential.name` | text | The name, as the app shows it. | | `credential.acts_as` | text | The member this key acts for. History shows their name. | | `credential.hide_personal_details` | true or false | True when this key hides customers' names, phones and streets. | | `companies` | list of objects | The companies. | | `companies[].id` | id (text) | The id of this record. Ids are opaque text: keep them exactly as given. | | `companies[].name` | text | The name, as the app shows it. | | `companies[].time_zone` | text | The company's time zone name, such as America/Chicago. | | `access` | object | The access. | | `access.jobs` | text | The access this key holds on this area: `read` or `do`. | | `access.money` | text | The access this key holds on this area: `read` or `do`. | | `access.raw` | text | The access this key holds on this area: `read` or `do`. | | `access.conv` | text | The access this key holds on this area: `read` or `do`. | | `credits` | object | The credits. | | `credits.left` | number | Credits left in the workspace. | | `credits.per_call` | number | Credits one answered call costs. | | `statuses` | list of objects | The statuses. | | `statuses[].id` | id (text) | The id of this record. Ids are opaque text: keep them exactly as given. | | `statuses[].name` | text | The name, as the app shows it. | | `statuses[].slug` | text | The same name as a lowercase code word. Match on this, not on the name. | | `job_types` | list of objects | The job types. | | `job_types[].id` | id (text) | The id of this record. Ids are opaque text: keep them exactly as given. | | `job_types[].name` | text | The name, as the app shows it. | | `technicians` | list of objects | The technicians. | | `technicians[].id` | id (text) | The id of this record. Ids are opaque text: keep them exactly as given. | | `technicians[].name` | text | The name, as the app shows it. | | `technicians[].role` | text | The role: what this person does on a job. | | `expense_types` | list of objects | The expense types. | | `expense_types[].id` | id (text) | The id of this record. Ids are opaque text: keep them exactly as given. | | `expense_types[].name` | text | The name, as the app shows it. | | `payment_methods` | list of text | The payment methods. | ## Call this first Everything a command needs by id is here: the company, the status, the job type, the technician. A name works too where the docs say so, and the answer tells you which name it understood. ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [List companies](https://headhoncho.app/docs/api/list_companies): The companies this credential reaches, each with its name, time zone, country and service area. The same ids every other call takes as company_id. - [Get company](https://headhoncho.app/docs/api/get_company): One company this credential reaches: its name, time zone, country and service area. - [Get usage](https://headhoncho.app/docs/api/get_usage): What the plan has used, what API calls cost and what this credential called, by day or by endpoint, with the credits left. - [Get credits](https://headhoncho.app/docs/api/get_credits): This month's credits: the plan's grant, what rolled over, what was bought, what was used and what is left. - [List plans](https://headhoncho.app/docs/api/list_plans): The plans on offer, with price and what each includes, and which one this workspace is on. - The same records in the app: [Multiple companies](https://headhoncho.app/docs/companies). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "workspace": { "id": "org_2c7d", "name": "Northwind Ads" }, "credential": { "kind": "key", "name": "Reporting laptop", "acts_as": "Ariel T.", "hide_personal_details": false }, "companies": [ { "id": "cmp_14f5", "name": "Sunrise Moving", "time_zone": "America/Chicago" }, { "id": "cmp_8a21", "name": "Capital Roofing", "time_zone": "America/New_York" } ], "access": { "jobs": "do", "money": "do", "raw": "read", "conv": "read" }, "credits": { "left": 1418.0, "per_call": 1.0 }, "statuses": [ { "id": "st_01", "name": "Draft", "slug": "draft" }, { "id": "st_02", "name": "Scheduled", "slug": "scheduled" }, { "id": "st_03", "name": "Dispatched", "slug": "dispatched" }, { "id": "st_06", "name": "Closed", "slug": "closed" } ], "job_types": [ { "id": "jt_02", "name": "Local move" }, { "id": "jt_05", "name": "Roof repair" } ], "technicians": [ { "id": "wrk_3b90", "name": "Dana R.", "role": "technician" }, { "id": "wrk_7a12", "name": "Omar S.", "role": "subcontractor" } ], "expense_types": [ { "id": "ext_01", "name": "Parts" }, { "id": "ext_02", "name": "Fuel" } ], "payment_methods": [ "cash", "card", "zelle", "check", "other" ] } ``` ### cURL ```bash curl "https://api.headhoncho.app/api/v1/whoami" \ -H "Authorization: Bearer hh_live_..." ``` ### Python ```python import requests response = requests.get( "https://api.headhoncho.app/api/v1/whoami", headers={"Authorization": "Bearer hh_live_..."}, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/whoami", { headers: { Authorization: "Bearer hh_live_..." }, }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: whoami Arguments: none Access: any key Hints: readOnly=true, destructive=false, idempotent=true, openWorld=false Try asking: "Using HeadHoncho, whoami." ``` --- # List jobs List jobs is a read in the HeadHoncho API. Jobs and leads in the companies this credential reaches, newest first, with status, technician, schedule, money and the ad click each came from. Page: https://headhoncho.app/docs/api/list_jobs | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **List jobs**, HeadHoncho API v1. It is a read, sent to the base address `https://api.headhoncho.app`. `GET /api/v1/jobs` The key needs the **Jobs** area at **read**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). Send your key as `Authorization: Bearer hh_live_...`. See [API keys](https://headhoncho.app/docs/api/keys). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `company_id` | id, in the query | No | One company. Default: every company the credential reaches. | `cmp_14f5` | | `status` | text, in the query | No | A status name or slug from Who am I. | `scheduled` | | `worker_id` | id, in the query | No | Jobs this technician or subcontractor is on. | `wrk_3b90` | | `from` | date, in the query | No | Created on or after this day, in the company's time zone. | `2026-10-01` | | `to` | date, in the query | No | Created on or before this day. | `2026-10-31` | | `leads` | text, in the query | No | include (default), only, or exclude. One of `include`, `only`, `exclude`. | `include` | | `bin` | text, in the query | No | Which jobs: open (default: everything not in Trash), active, archived, or trash. One of `open`, `active`, `archived`, `trash`. | `open` | | `limit` | number, in the query | No | 1 to 200. Default 50. | `50` | | `cursor` | text, in the query | No | From the previous answer's next. | `eyJhZnRlciI6...` | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back items, one job each in the Get a job shape; next, a cursor for the following page or null; count, how many match in all. Trashed jobs are listed only with bin=trash, so a client can find what it may restore. It never changes a record. It only reads the companies the key reaches. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `items` | list of objects | The rows on this page. | | `items[].id` | id (text) | The id of this record. Ids are opaque text: keep them exactly as given. | | `items[].number` | whole number | The number people say out loud, such as the job number. | | `items[].company` | object | The company. | | `items[].company.id` | id (text) | The id of this record. Ids are opaque text: keep them exactly as given. | | `items[].company.name` | text | The name, as the app shows it. | | `items[].client` | object | The client. | | `items[].client.id` | id (text) | The id of this record. Ids are opaque text: keep them exactly as given. | | `items[].client.name` | text | The name, as the app shows it. | | `items[].client.phone` | text | A phone number. Hidden when the key hides personal details. | | `items[].client.second_phone` | text | A second phone number. Hidden when the key hides personal details. | | `items[].address` | object | The address. | | `items[].address.line1` | text | The street address. Hidden when the key hides personal details. | | `items[].address.line2` | text | The apartment or suite line. Hidden when the key hides personal details. | | `items[].address.city` | text | The city. | | `items[].address.state` | text | The state or region. | | `items[].address.postal_code` | text | The postal code. | | `items[].address.one_line` | text | The whole address on one line. Hidden when the key hides personal details. | | `items[].job_type` | object | The job type. | | `items[].job_type.id` | id (text) | The id of this record. Ids are opaque text: keep them exactly as given. | | `items[].job_type.name` | text | The name, as the app shows it. | | `items[].status` | object | The job status. | | `items[].status.id` | id (text) | The id of this record. Ids are opaque text: keep them exactly as given. | | `items[].status.name` | text | The name, as the app shows it. | | `items[].status.slug` | text | The same name as a lowercase code word. Match on this, not on the name. | | `items[].status.since` | time (ISO 8601, with offset) | From when this has been true. Carries its offset from UTC; `Z` is UTC. | | `items[].technicians` | list of objects | The technicians. | | `items[].technicians[].id` | id (text) | The id of this record. Ids are opaque text: keep them exactly as given. | | `items[].technicians[].name` | text | The name, as the app shows it. | | `items[].scheduled_start` | time (ISO 8601, with offset) | When the visit is planned to start. Carries its offset from UTC; `Z` is UTC. | | `items[].scheduled_end` | time (ISO 8601, with offset) | When the visit is planned to end. Carries its offset from UTC; `Z` is UTC. | | `items[].collected` | money (number) | The money received on the job so far. In the company's currency. | | `items[].profit` | money (number) | The job's profit, worked out the way the app works it out. In the company's currency. | | `items[].currency` | text | The three-letter currency code (ISO 4217). Every money value in the answer is in it. | | `items[].source` | object | The source. | | `items[].source.label` | text | The name the app shows for it. | | `items[].source.filled_by` | text | How the job source was filled in: `call`, `form` or by hand. | | `items[].source.click_id` | id (text) | The Google click id (gclid) the call or visit carried. | | `items[].source.call_id` | id (text) | The id of the call. | | `items[].source.call_at` | time (ISO 8601, with offset) | When the call happened. Carries its offset from UTC; `Z` is UTC. | | `items[].source.campaign` | text | The ad campaign's name. | | `items[].is_lead` | true or false | True while the job is still a lead. | | `items[].notes` | text | Free-text notes. | | `items[].created_at` | time (ISO 8601, with offset) | When it was created. Carries its offset from UTC; `Z` is UTC. | | `items[].closed_at` | time or null | When it was closed. | | `items[].canceled_at` | time or null | When it was canceled. | | `items[].archived_at` | time or null | When it was archived. | | `items[].trashed_at` | time or null | When it was trashed. | | `next` | text | The cursor for the next page, or null on the last page. Pass it back as `cursor`. | | `count` | whole number | How many match in all, across every page. | ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`not_found`](https://headhoncho.app/docs/api/errors#not_found) | 404 | No such record in the companies this credential reaches. | | [`out_of_scope`](https://headhoncho.app/docs/api/errors#out_of_scope) | 404 | No such company in the companies this credential reaches. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [Get job](https://headhoncho.app/docs/api/get_job): One job or lead: who, where, when, which status, which technicians, the money on it and the ad click it came from. - [Get job history](https://headhoncho.app/docs/api/get_job_history): Everything that happened to a job, in order, with who did it: created, moved, assigned, noted, paid. The same log the job page shows. - [Get job log](https://headhoncho.app/docs/api/get_job_log): A job's timeline in plain words, one line per thing that happened: notes, moves, texts, money, the rules and the AI, each with who did it. - [List situations](https://headhoncho.app/docs/api/list_situations): The situations the AI dispatcher is working on jobs now: what came up, the plan, and which step it is on. - [List job photos](https://headhoncho.app/docs/api/list_job_photos): The photos stored on a job, oldest first, each with a link that opens it for one minute. - [Get photo](https://headhoncho.app/docs/api/get_photo): One stored photo and a fresh link to its file. The link works for one minute. - [Get calendar](https://headhoncho.app/docs/api/get_calendar): Every job with a booked time between two days, earliest first. Canceled and closed jobs are left out, as on the app's calendar. - [List unscheduled jobs](https://headhoncho.app/docs/api/list_unscheduled_jobs): Open jobs and leads that have no booked time yet, the ones that waited longest first. - [Export jobs](https://headhoncho.app/docs/api/export_jobs): Jobs as a CSV file, newest first, up to 10,000 rows: ticket, technicians, status, dates, address, customer and price. - [Search jobs](https://headhoncho.app/docs/api/search_jobs): Find jobs by ticket number, customer, address or technician name, and technicians by name. - [Get automatic status](https://headhoncho.app/docs/api/get_automatic_status): Whether a person set this job's status by hand, why its facts do not hold it, and where Back to automatic would put it. - [Get job detour](https://headhoncho.app/docs/api/get_job_detour): Whether a job is on a detour, such as Waiting on parts, and where Resolve would put it. - [List job reassignments](https://headhoncho.app/docs/api/list_job_reassignments): The times this job was handed from one technician to another, oldest first, and how far each one got. - [List calendar reassignments](https://headhoncho.app/docs/api/list_calendar_reassignments): Every reassignment on a job booked in a window: open ones, and ones that closed today. - The same records in the app: [the Jobs panel](https://headhoncho.app/docs/jobs). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "items": [ { "id": "job_1138", "number": 1138, "company": { "id": "cmp_14f5", "name": "Sunrise Moving" }, "client": { "id": "cli_77a0", "name": "R. Azoulay", "phone": "+12175550142", "second_phone": "" }, "address": { "line1": "2590 Main St", "line2": "", "city": "Bloomington", "state": "IL", "postal_code": "61701", "one_line": "2590 Main St, Bloomington, IL 61701" }, "job_type": { "id": "jt_02", "name": "Local move" }, "status": { "id": "st_02", "name": "Scheduled", "slug": "scheduled", "since": "2026-10-12T15:04:10Z" }, "technicians": [ { "id": "wrk_3b90", "name": "Dana R." } ], "scheduled_start": "2026-10-16T09:00:00-05:00", "scheduled_end": "2026-10-16T11:00:00-05:00", "collected": 0.0, "profit": 0.0, "currency": "USD", "source": { "label": "Google Ads", "filled_by": "call", "click_id": "Cj0KCQjw...", "call_id": "CAL8f2e1", "call_at": "2026-10-11T18:22:03Z", "campaign": "Moving - Bloomington" }, "is_lead": false, "notes": "Two flights of stairs", "created_at": "2026-10-11T18:25:40Z", "closed_at": null, "canceled_at": null, "archived_at": null, "trashed_at": null } ], "next": "eyJhZnRlciI6IjIwMjYtMTAtMTFUMTg6MjU6NDBaIn0", "count": 128 } ``` ### cURL ```bash curl "https://api.headhoncho.app/api/v1/jobs?company_id=cmp_14f5&status=scheduled" \ -H "Authorization: Bearer hh_live_..." ``` ### Python ```python import requests response = requests.get( "https://api.headhoncho.app/api/v1/jobs", headers={"Authorization": "Bearer hh_live_..."}, params={ "company_id": "cmp_14f5", "status": "scheduled", }, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/jobs?company_id=cmp_14f5&status=scheduled", { headers: { Authorization: "Bearer hh_live_..." }, }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: list_jobs Arguments: company_id (id, optional), status (text, optional), worker_id (id, optional), from (date, optional), to (date, optional), leads (text, optional), bin (text, optional), limit (number, optional), cursor (text, optional) Access: read on Jobs Hints: readOnly=true, destructive=false, idempotent=true, openWorld=false Try asking: "Using HeadHoncho, list jobs with company_id cmp_14f5." ``` --- # Get job Get job is a read in the HeadHoncho API. One job or lead: who, where, when, which status, which technicians, the money on it and the ad click it came from. Page: https://headhoncho.app/docs/api/get_job | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **Get job**, HeadHoncho API v1. It is a read, sent to the base address `https://api.headhoncho.app`. `GET /api/v1/jobs/{job_id}` The key needs the **Jobs** area at **read**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). Send your key as `Authorization: Bearer hh_live_...`. See [API keys](https://headhoncho.app/docs/api/keys). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `job_id` | id, in the path | Yes | The job id, or its number. | `job_1138` | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back The job. Money is what was collected and the profit after the subcontractor, each as a number in the company's currency. source is how the job was attributed: filled_by says whether the click came off a tracked call or the job's own record. It never changes a record. It only reads the companies the key reaches. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `id` | id (text) | The id of this record. Ids are opaque text: keep them exactly as given. | | `number` | whole number | The number people say out loud, such as the job number. | | `company` | object | The company. | | `company.id` | id (text) | The id of this record. Ids are opaque text: keep them exactly as given. | | `company.name` | text | The name, as the app shows it. | | `client` | object | The client. | | `client.id` | id (text) | The id of this record. Ids are opaque text: keep them exactly as given. | | `client.name` | text | The name, as the app shows it. | | `client.phone` | text | A phone number. Hidden when the key hides personal details. | | `client.second_phone` | text | A second phone number. Hidden when the key hides personal details. | | `address` | object | The address. | | `address.line1` | text | The street address. Hidden when the key hides personal details. | | `address.line2` | text | The apartment or suite line. Hidden when the key hides personal details. | | `address.city` | text | The city. | | `address.state` | text | The state or region. | | `address.postal_code` | text | The postal code. | | `address.one_line` | text | The whole address on one line. Hidden when the key hides personal details. | | `job_type` | object | The job type. | | `job_type.id` | id (text) | The id of this record. Ids are opaque text: keep them exactly as given. | | `job_type.name` | text | The name, as the app shows it. | | `status` | object | The job status. | | `status.id` | id (text) | The id of this record. Ids are opaque text: keep them exactly as given. | | `status.name` | text | The name, as the app shows it. | | `status.slug` | text | The same name as a lowercase code word. Match on this, not on the name. | | `status.since` | time (ISO 8601, with offset) | From when this has been true. Carries its offset from UTC; `Z` is UTC. | | `technicians` | list of objects | The technicians. | | `technicians[].id` | id (text) | The id of this record. Ids are opaque text: keep them exactly as given. | | `technicians[].name` | text | The name, as the app shows it. | | `scheduled_start` | time (ISO 8601, with offset) | When the visit is planned to start. Carries its offset from UTC; `Z` is UTC. | | `scheduled_end` | time (ISO 8601, with offset) | When the visit is planned to end. Carries its offset from UTC; `Z` is UTC. | | `collected` | money (number) | The money received on the job so far. In the company's currency. | | `profit` | money (number) | The job's profit, worked out the way the app works it out. In the company's currency. | | `currency` | text | The three-letter currency code (ISO 4217). Every money value in the answer is in it. | | `source` | object | The source. | | `source.label` | text | The name the app shows for it. | | `source.filled_by` | text | How the job source was filled in: `call`, `form` or by hand. | | `source.click_id` | id (text) | The Google click id (gclid) the call or visit carried. | | `source.call_id` | id (text) | The id of the call. | | `source.call_at` | time (ISO 8601, with offset) | When the call happened. Carries its offset from UTC; `Z` is UTC. | | `source.campaign` | text | The ad campaign's name. | | `is_lead` | true or false | True while the job is still a lead. | | `notes` | text | Free-text notes. | | `created_at` | time (ISO 8601, with offset) | When it was created. Carries its offset from UTC; `Z` is UTC. | | `closed_at` | time or null | When it was closed. | | `canceled_at` | time or null | When it was canceled. | | `archived_at` | time or null | When it was archived. | | `trashed_at` | time or null | When it was trashed. | ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`not_found`](https://headhoncho.app/docs/api/errors#not_found) | 404 | No such record in the companies this credential reaches. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [List jobs](https://headhoncho.app/docs/api/list_jobs): Jobs and leads in the companies this credential reaches, newest first, with status, technician, schedule, money and the ad click each came from. - [Get job history](https://headhoncho.app/docs/api/get_job_history): Everything that happened to a job, in order, with who did it: created, moved, assigned, noted, paid. The same log the job page shows. - [Get job log](https://headhoncho.app/docs/api/get_job_log): A job's timeline in plain words, one line per thing that happened: notes, moves, texts, money, the rules and the AI, each with who did it. - [List situations](https://headhoncho.app/docs/api/list_situations): The situations the AI dispatcher is working on jobs now: what came up, the plan, and which step it is on. - [List job photos](https://headhoncho.app/docs/api/list_job_photos): The photos stored on a job, oldest first, each with a link that opens it for one minute. - [Get photo](https://headhoncho.app/docs/api/get_photo): One stored photo and a fresh link to its file. The link works for one minute. - [Get calendar](https://headhoncho.app/docs/api/get_calendar): Every job with a booked time between two days, earliest first. Canceled and closed jobs are left out, as on the app's calendar. - [List unscheduled jobs](https://headhoncho.app/docs/api/list_unscheduled_jobs): Open jobs and leads that have no booked time yet, the ones that waited longest first. - [Export jobs](https://headhoncho.app/docs/api/export_jobs): Jobs as a CSV file, newest first, up to 10,000 rows: ticket, technicians, status, dates, address, customer and price. - [Search jobs](https://headhoncho.app/docs/api/search_jobs): Find jobs by ticket number, customer, address or technician name, and technicians by name. - [Get automatic status](https://headhoncho.app/docs/api/get_automatic_status): Whether a person set this job's status by hand, why its facts do not hold it, and where Back to automatic would put it. - [Get job detour](https://headhoncho.app/docs/api/get_job_detour): Whether a job is on a detour, such as Waiting on parts, and where Resolve would put it. - [List job reassignments](https://headhoncho.app/docs/api/list_job_reassignments): The times this job was handed from one technician to another, oldest first, and how far each one got. - [List calendar reassignments](https://headhoncho.app/docs/api/list_calendar_reassignments): Every reassignment on a job booked in a window: open ones, and ones that closed today. - The same records in the app: [the Jobs panel](https://headhoncho.app/docs/jobs). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "id": "job_1138", "number": 1138, "company": { "id": "cmp_14f5", "name": "Sunrise Moving" }, "client": { "id": "cli_77a0", "name": "R. Azoulay", "phone": "+12175550142", "second_phone": "" }, "address": { "line1": "2590 Main St", "line2": "", "city": "Bloomington", "state": "IL", "postal_code": "61701", "one_line": "2590 Main St, Bloomington, IL 61701" }, "job_type": { "id": "jt_02", "name": "Local move" }, "status": { "id": "st_02", "name": "Scheduled", "slug": "scheduled", "since": "2026-10-12T15:04:10Z" }, "technicians": [ { "id": "wrk_3b90", "name": "Dana R." } ], "scheduled_start": "2026-10-16T09:00:00-05:00", "scheduled_end": "2026-10-16T11:00:00-05:00", "collected": 0.0, "profit": 0.0, "currency": "USD", "source": { "label": "Google Ads", "filled_by": "call", "click_id": "Cj0KCQjw...", "call_id": "CAL8f2e1", "call_at": "2026-10-11T18:22:03Z", "campaign": "Moving - Bloomington" }, "is_lead": false, "notes": "Two flights of stairs", "created_at": "2026-10-11T18:25:40Z", "closed_at": null, "canceled_at": null, "archived_at": null, "trashed_at": null } ``` ### cURL ```bash curl "https://api.headhoncho.app/api/v1/jobs/job_1138" \ -H "Authorization: Bearer hh_live_..." ``` ### Python ```python import requests response = requests.get( "https://api.headhoncho.app/api/v1/jobs/job_1138", headers={"Authorization": "Bearer hh_live_..."}, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/jobs/job_1138", { headers: { Authorization: "Bearer hh_live_..." }, }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: get_job Arguments: job_id (id, required) Access: read on Jobs Hints: readOnly=true, destructive=false, idempotent=true, openWorld=false Try asking: "Using HeadHoncho, get job with job_id job_1138." ``` --- # Get job history Get job history is a read in the HeadHoncho API. Everything that happened to a job, in order, with who did it: created, moved, assigned, noted, paid. The same log the job page shows. Page: https://headhoncho.app/docs/api/get_job_history | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **Get job history**, HeadHoncho API v1. It is a read, sent to the base address `https://api.headhoncho.app`. `GET /api/v1/jobs/{job_id}/history` The key needs the **Jobs** area at **read**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). Send your key as `Authorization: Bearer hh_live_...`. See [API keys](https://headhoncho.app/docs/api/keys). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `job_id` | id, in the path | Yes | The job id, or its number. | `job_1138` | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back items, oldest first: position (the event position, usable as after= on a read), event, at, by (a person's name, or "Reporting laptop, for Ariel T." when a key acted), and the event's own facts. It never changes a record. It only reads the companies the key reaches. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `items` | list of objects | The rows on this page. | | `items[].position` | whole number | Where the change landed in the event log. Pass it as `after` on a read to see your own write. | | `items[].event` | text | The kind of event, as a code. | | `items[].at` | time (ISO 8601, with offset) | The moment it happened. Carries its offset from UTC; `Z` is UTC. | | `items[].by` | text | Who did it. A key shows as its name, then "for" and the member it acts as. | | `items[].facts` | object | The facts. | | `items[].facts.client_name` | text | The customer's name. Hidden when the key hides personal details. | | `items[].facts.intent` | text | What the command was asked to do. | ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`not_found`](https://headhoncho.app/docs/api/errors#not_found) | 404 | No such record in the companies this credential reaches. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [List jobs](https://headhoncho.app/docs/api/list_jobs): Jobs and leads in the companies this credential reaches, newest first, with status, technician, schedule, money and the ad click each came from. - [Get job](https://headhoncho.app/docs/api/get_job): One job or lead: who, where, when, which status, which technicians, the money on it and the ad click it came from. - [Get job log](https://headhoncho.app/docs/api/get_job_log): A job's timeline in plain words, one line per thing that happened: notes, moves, texts, money, the rules and the AI, each with who did it. - [List situations](https://headhoncho.app/docs/api/list_situations): The situations the AI dispatcher is working on jobs now: what came up, the plan, and which step it is on. - [List job photos](https://headhoncho.app/docs/api/list_job_photos): The photos stored on a job, oldest first, each with a link that opens it for one minute. - [Get photo](https://headhoncho.app/docs/api/get_photo): One stored photo and a fresh link to its file. The link works for one minute. - [Get calendar](https://headhoncho.app/docs/api/get_calendar): Every job with a booked time between two days, earliest first. Canceled and closed jobs are left out, as on the app's calendar. - [List unscheduled jobs](https://headhoncho.app/docs/api/list_unscheduled_jobs): Open jobs and leads that have no booked time yet, the ones that waited longest first. - [Export jobs](https://headhoncho.app/docs/api/export_jobs): Jobs as a CSV file, newest first, up to 10,000 rows: ticket, technicians, status, dates, address, customer and price. - [Search jobs](https://headhoncho.app/docs/api/search_jobs): Find jobs by ticket number, customer, address or technician name, and technicians by name. - [Get automatic status](https://headhoncho.app/docs/api/get_automatic_status): Whether a person set this job's status by hand, why its facts do not hold it, and where Back to automatic would put it. - [Get job detour](https://headhoncho.app/docs/api/get_job_detour): Whether a job is on a detour, such as Waiting on parts, and where Resolve would put it. - [List job reassignments](https://headhoncho.app/docs/api/list_job_reassignments): The times this job was handed from one technician to another, oldest first, and how far each one got. - [List calendar reassignments](https://headhoncho.app/docs/api/list_calendar_reassignments): Every reassignment on a job booked in a window: open ones, and ones that closed today. - The same records in the app: [the Jobs panel](https://headhoncho.app/docs/jobs). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "items": [ { "position": 88120, "event": "job.created", "at": "2026-10-11T18:25:40Z", "by": "Ariel T.", "facts": { "client_name": "R. Azoulay", "intent": "create" } }, { "position": 88131, "event": "job.assigned", "at": "2026-10-11T18:26:02Z", "by": "Ariel T.", "facts": { "worker_id": "wrk_3b90" } }, { "position": 88402, "event": "job.note_added", "at": "2026-10-12T15:04:10Z", "by": "Reporting laptop, for Ariel T.", "facts": { "body": "Gate code 4410" } } ] } ``` ### cURL ```bash curl "https://api.headhoncho.app/api/v1/jobs/job_1138/history" \ -H "Authorization: Bearer hh_live_..." ``` ### Python ```python import requests response = requests.get( "https://api.headhoncho.app/api/v1/jobs/job_1138/history", headers={"Authorization": "Bearer hh_live_..."}, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/jobs/job_1138/history", { headers: { Authorization: "Bearer hh_live_..." }, }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: get_job_history Arguments: job_id (id, required) Access: read on Jobs Hints: readOnly=true, destructive=false, idempotent=true, openWorld=false Try asking: "Using HeadHoncho, get job history with job_id job_1138." ``` --- # Get job log Get job log is a read in the HeadHoncho API. A job's timeline in plain words, one line per thing that happened: notes, moves, texts, money, the rules and the AI, each with who did it. Page: https://headhoncho.app/docs/api/get_job_log | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **Get job log**, HeadHoncho API v1. It is a read, sent to the base address `https://api.headhoncho.app`. `GET /api/v1/jobs/{job_id}/log` The key needs the **Jobs** area at **read**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). Send your key as `Authorization: Bearer hh_live_...`. See [API keys](https://headhoncho.app/docs/api/keys). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `job_id` | id, in the path | Yes | The job id, or its number. | `job_1138` | | `since` | number, in the query | No | Only lines after this seq, from the previous answer's next or the last line you hold. Default 0, the start. | `0` | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back entries, oldest first: seq (dense per job, the cursor), at, kind (comment, status, schedule, assignment, money, detail, customer_text, tech_message, rule, ai_action, situation, plan, step, recommendation or created), actor (kind: person, customer, tech, rule or ai; label: who, in words), body (the line, or the words a customer or a tech wrote) and ref (what the line points at). next: the since for the following page, or null. With personal details hidden, a customer's own words are left out. It never changes a record. It only reads the companies the key reaches. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `job` | object | The job. | | `job.id` | id (text) | The id of this record. Ids are opaque text: keep them exactly as given. | | `job.number` | whole number | The number people say out loud, such as the job number. | | `entries` | list of objects | The entries. | | `entries[].seq` | whole number | The order in the list. 1 is the first. | | `entries[].at` | time (ISO 8601, with offset) | The moment it happened. Carries its offset from UTC; `Z` is UTC. | | `entries[].kind` | text | What sort of thing this is. | | `entries[].actor` | object | The actor. | | `entries[].actor.kind` | text | What sort of thing this is. | | `entries[].actor.label` | text | The name the app shows for it. | | `entries[].body` | text | The text, as written. | | `entries[].ref` | object | The ref. | | `entries[].ref.kind` | text | What sort of thing this is. | | `entries[].ref.id` | id (text) | The id of this record. Ids are opaque text: keep them exactly as given. | | `next` | value or null | The cursor for the next page, or null on the last page. Pass it back as `cursor`. | ## Reading new lines Keep the seq of the last line you hold and pass it as since: the answer holds only what happened after it. A line never changes once written. ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`not_found`](https://headhoncho.app/docs/api/errors#not_found) | 404 | No such record in the companies this credential reaches. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [List jobs](https://headhoncho.app/docs/api/list_jobs): Jobs and leads in the companies this credential reaches, newest first, with status, technician, schedule, money and the ad click each came from. - [Get job](https://headhoncho.app/docs/api/get_job): One job or lead: who, where, when, which status, which technicians, the money on it and the ad click it came from. - [Get job history](https://headhoncho.app/docs/api/get_job_history): Everything that happened to a job, in order, with who did it: created, moved, assigned, noted, paid. The same log the job page shows. - [List situations](https://headhoncho.app/docs/api/list_situations): The situations the AI dispatcher is working on jobs now: what came up, the plan, and which step it is on. - [List job photos](https://headhoncho.app/docs/api/list_job_photos): The photos stored on a job, oldest first, each with a link that opens it for one minute. - [Get photo](https://headhoncho.app/docs/api/get_photo): One stored photo and a fresh link to its file. The link works for one minute. - [Get calendar](https://headhoncho.app/docs/api/get_calendar): Every job with a booked time between two days, earliest first. Canceled and closed jobs are left out, as on the app's calendar. - [List unscheduled jobs](https://headhoncho.app/docs/api/list_unscheduled_jobs): Open jobs and leads that have no booked time yet, the ones that waited longest first. - [Export jobs](https://headhoncho.app/docs/api/export_jobs): Jobs as a CSV file, newest first, up to 10,000 rows: ticket, technicians, status, dates, address, customer and price. - [Search jobs](https://headhoncho.app/docs/api/search_jobs): Find jobs by ticket number, customer, address or technician name, and technicians by name. - [Get automatic status](https://headhoncho.app/docs/api/get_automatic_status): Whether a person set this job's status by hand, why its facts do not hold it, and where Back to automatic would put it. - [Get job detour](https://headhoncho.app/docs/api/get_job_detour): Whether a job is on a detour, such as Waiting on parts, and where Resolve would put it. - [List job reassignments](https://headhoncho.app/docs/api/list_job_reassignments): The times this job was handed from one technician to another, oldest first, and how far each one got. - [List calendar reassignments](https://headhoncho.app/docs/api/list_calendar_reassignments): Every reassignment on a job booked in a window: open ones, and ones that closed today. - The same records in the app: [the Jobs panel](https://headhoncho.app/docs/jobs). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "job": { "id": "job_1138", "number": 1138 }, "entries": [ { "seq": 1, "at": "2026-10-11T18:25:40Z", "kind": "created", "actor": { "kind": "person", "label": "Ariel T." }, "body": "Job #1138 opened. Type: Local move. Status: Scheduled.", "ref": { "kind": "job", "id": "job_1138" } }, { "seq": 2, "at": "2026-10-11T18:26:02Z", "kind": "assignment", "actor": { "kind": "person", "label": "Ariel T." }, "body": "Dana R. assigned.", "ref": { "kind": "worker", "id": "wrk_3b90" } }, { "seq": 3, "at": "2026-10-16T08:41:17Z", "kind": "tech_message", "actor": { "kind": "tech", "label": "Dana R." }, "body": "Running 40 min late, truck won't start", "ref": { "kind": "dispatch_message", "id": "dm_51c0" } }, { "seq": 4, "at": "2026-10-16T08:41:30Z", "kind": "plan", "actor": { "kind": "ai", "label": "AI dispatcher · plan" }, "body": "Plan 1, 2 steps. Tell the customer, then wait for the tech.", "ref": { "kind": "plan", "id": "pln_02aa" } } ], "next": null } ``` ### cURL ```bash curl "https://api.headhoncho.app/api/v1/jobs/job_1138/log?since=0" \ -H "Authorization: Bearer hh_live_..." ``` ### Python ```python import requests response = requests.get( "https://api.headhoncho.app/api/v1/jobs/job_1138/log", headers={"Authorization": "Bearer hh_live_..."}, params={ "since": "0", }, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/jobs/job_1138/log?since=0", { headers: { Authorization: "Bearer hh_live_..." }, }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: get_job_log Arguments: job_id (id, required), since (number, optional) Access: read on Jobs Hints: readOnly=true, destructive=false, idempotent=true, openWorld=false Try asking: "Using HeadHoncho, get job log with job_id job_1138 and since 0." ``` --- # List situations List situations is a read in the HeadHoncho API. The situations the AI dispatcher is working on jobs now: what came up, the plan, and which step it is on. Page: https://headhoncho.app/docs/api/list_situations | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **List situations**, HeadHoncho API v1. It is a read, sent to the base address `https://api.headhoncho.app`. `GET /api/v1/situations` The key needs the **Jobs** area at **read**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). Send your key as `Authorization: Bearer hh_live_...`. See [API keys](https://headhoncho.app/docs/api/keys). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `company_id` | id, in the query | No | One company. Default: every company the credential reaches. | `cmp_14f5` | | `job_id` | id, in the query | No | One job's situations, by id or number. | `job_1138` | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back items, one open situation each: id, job (id and number), kind (key and name), state (raised, open, waiting or recommended), raised_by, raised_at, opened_at, and plan (version, rationale, and its steps in order, each with its action, words and state), or null before the first plan. Closed and dropped situations are in the job's log. It never changes a record. It only reads the companies the key reaches. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `items` | list of objects | The rows on this page. | | `items[].id` | id (text) | The id of this record. Ids are opaque text: keep them exactly as given. | | `items[].job` | object | The job. | | `items[].job.id` | id (text) | The id of this record. Ids are opaque text: keep them exactly as given. | | `items[].job.number` | whole number | The number people say out loud, such as the job number. | | `items[].kind` | object | What sort of thing this is. | | `items[].kind.key` | text | A short code for this item. Match on it in code. | | `items[].kind.name` | text | The name, as the app shows it. | | `items[].state` | text | The state or region. | | `items[].raised_by` | text | The raised by. | | `items[].raised_at` | time (ISO 8601, with offset) | When it was raised. Carries its offset from UTC; `Z` is UTC. | | `items[].opened_at` | time (ISO 8601, with offset) | When it was opened. Carries its offset from UTC; `Z` is UTC. | | `items[].plan` | object | The plan. | | `items[].plan.version` | whole number | The version of this record. It goes up each time it changes. | | `items[].plan.rationale` | text | Why, in one sentence. | | `items[].plan.steps` | list of objects | The steps. | | `items[].plan.steps[].position` | whole number | Where the change landed in the event log. Pass it as `after` on a read to see your own write. | | `items[].plan.steps[].action` | text | The action, as a code. | | `items[].plan.steps[].words` | text | The text, as a person would say it. | | `items[].plan.steps[].state` | text | The state or region. | ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`not_found`](https://headhoncho.app/docs/api/errors#not_found) | 404 | No such record in the companies this credential reaches. | | [`out_of_scope`](https://headhoncho.app/docs/api/errors#out_of_scope) | 404 | No such company in the companies this credential reaches. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [List jobs](https://headhoncho.app/docs/api/list_jobs): Jobs and leads in the companies this credential reaches, newest first, with status, technician, schedule, money and the ad click each came from. - [Get job](https://headhoncho.app/docs/api/get_job): One job or lead: who, where, when, which status, which technicians, the money on it and the ad click it came from. - [Get job history](https://headhoncho.app/docs/api/get_job_history): Everything that happened to a job, in order, with who did it: created, moved, assigned, noted, paid. The same log the job page shows. - [Get job log](https://headhoncho.app/docs/api/get_job_log): A job's timeline in plain words, one line per thing that happened: notes, moves, texts, money, the rules and the AI, each with who did it. - [List job photos](https://headhoncho.app/docs/api/list_job_photos): The photos stored on a job, oldest first, each with a link that opens it for one minute. - [Get photo](https://headhoncho.app/docs/api/get_photo): One stored photo and a fresh link to its file. The link works for one minute. - [Get calendar](https://headhoncho.app/docs/api/get_calendar): Every job with a booked time between two days, earliest first. Canceled and closed jobs are left out, as on the app's calendar. - [List unscheduled jobs](https://headhoncho.app/docs/api/list_unscheduled_jobs): Open jobs and leads that have no booked time yet, the ones that waited longest first. - [Export jobs](https://headhoncho.app/docs/api/export_jobs): Jobs as a CSV file, newest first, up to 10,000 rows: ticket, technicians, status, dates, address, customer and price. - [Search jobs](https://headhoncho.app/docs/api/search_jobs): Find jobs by ticket number, customer, address or technician name, and technicians by name. - [Get automatic status](https://headhoncho.app/docs/api/get_automatic_status): Whether a person set this job's status by hand, why its facts do not hold it, and where Back to automatic would put it. - [Get job detour](https://headhoncho.app/docs/api/get_job_detour): Whether a job is on a detour, such as Waiting on parts, and where Resolve would put it. - [List job reassignments](https://headhoncho.app/docs/api/list_job_reassignments): The times this job was handed from one technician to another, oldest first, and how far each one got. - [List calendar reassignments](https://headhoncho.app/docs/api/list_calendar_reassignments): Every reassignment on a job booked in a window: open ones, and ones that closed today. - The same records in the app: [the Jobs panel](https://headhoncho.app/docs/jobs). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "items": [ { "id": "sit_7c11", "job": { "id": "job_1138", "number": 1138 }, "kind": { "key": "tech_late", "name": "Tech running late" }, "state": "waiting", "raised_by": "tech_message", "raised_at": "2026-10-16T08:41:17Z", "opened_at": "2026-10-16T08:41:21Z", "plan": { "version": 1, "rationale": "Tell the customer, then wait for the tech.", "steps": [ { "position": 1, "action": "message_customer", "words": "Tell them the tech is about 40 minutes late.", "state": "done" }, { "position": 2, "action": "wait_for", "words": "Wait 2 hours for the tech.", "state": "asked" } ] } } ] } ``` ### cURL ```bash curl "https://api.headhoncho.app/api/v1/situations?company_id=cmp_14f5&job_id=job_1138" \ -H "Authorization: Bearer hh_live_..." ``` ### Python ```python import requests response = requests.get( "https://api.headhoncho.app/api/v1/situations", headers={"Authorization": "Bearer hh_live_..."}, params={ "company_id": "cmp_14f5", "job_id": "job_1138", }, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/situations?company_id=cmp_14f5&job_id=job_1138", { headers: { Authorization: "Bearer hh_live_..." }, }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: list_situations Arguments: company_id (id, optional), job_id (id, optional) Access: read on Jobs Hints: readOnly=true, destructive=false, idempotent=true, openWorld=false Try asking: "Using HeadHoncho, list situations with company_id cmp_14f5." ``` --- # Create job Create job is a command in the HeadHoncho API. Open a job or a lead in one company: the customer, the address, and optionally the job type, the time window and the technician. Page: https://headhoncho.app/docs/api/create_job | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **Create job**, HeadHoncho API v1. It is a command, sent to the base address `https://api.headhoncho.app`. `POST /api/v1/commands/create-job` The key needs the **Jobs** area at **do**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). It runs the app's own command `create-job`. Send an `Idempotency-Key` header with every call: the same key with the same body returns the first answer and runs nothing twice. See [the model](https://headhoncho.app/docs/api/model#idempotency). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `company_id` | id, in the JSON body | Yes | From Who am I. | `cmp_14f5` | | `client_name` | text, in the JSON body | Yes | The customer, as they gave it. | `R. Azoulay` | | `client_phone` | text, in the JSON body | Yes | Any format; stored as E.164. | `+12175550142` | | `address` | object, in the JSON body | Yes | line1, city, state and postal_code. line2 is optional. | `{"line1": "2590 Main St", "city": "Bloomington", "state": "IL", "postal_code": "61701"}` | | `job_type_id` | id, in the JSON body | No | From Who am I. | `jt_02` | | `scheduled_start` | datetime, in the JSON body | No | ISO 8601, with scheduled_end. | `2026-10-16T09:00:00-05:00` | | `scheduled_end` | datetime, in the JSON body | No | ISO 8601. The end of the window. | `2026-10-16T11:00:00-05:00` | | `worker_id` | id, in the JSON body | No | Assigns the technician now. | `wrk_3b90` | | `notes` | text, in the JSON body | No | Anything the crew should know. | `Two flights of stairs` | | `intent` | text, in the JSON body | No | create (default) opens a job; draft opens a lead; dispatch opens it and sends the ticket to the technician. One of `create`, `draft`, `dispatch`. | `create` | | `utm_source` | text, in the JSON body | No | Where the customer came from, as the page's UTM tag said. Sets the job's Source: google reads Google Ads. | `google` | | `utm_medium` | text, in the JSON body | No | The UTM medium. | `cpc` | | `utm_campaign` | text, in the JSON body | No | The UTM campaign. | `Spring Repairs` | | `utm_term` | text, in the JSON body | No | The UTM term: the keyword. | `garage door repair` | | `utm_content` | text, in the JSON body | No | The UTM content. | `ad-2` | | `gclid` | text, in the JSON body | No | Google's click ID, off the landing page's address. When the client's conversions are on, the booked job goes back to Google Ads with it. | `Cj0KCQiA…` | | `gbraid` | text, in the JSON body | No | Google's click ID on iOS, when the page had no gclid. Kept with the job. | None | | `wbraid` | text, in the JSON body | No | Google's web click ID on iOS. Kept with the job. | None | | `msclkid` | text, in the JSON body | No | Microsoft Advertising's click ID. Kept with the job. | None | | `fbclid` | text, in the JSON body | No | Meta's click ID. Kept with the job. | None | | `landing_page` | text, in the JSON body | No | The page the visitor first landed on. | `https://example.com/garage-door-repair?gclid=Cj0KCQiA…` | | `form_name` | text, in the JSON body | No | The form the customer sent. | `Request service` | | `form_id` | text, in the JSON body | No | Your id for this form, so a retry never lands it twice. | `cf7-118-2026-11-06T14:02:11Z` | | `submitted_at` | datetime, in the JSON body | No | When the customer sent the form, when that is not now: a form you held and are sending late keeps its own time. | `2026-11-06T14:02:11Z` | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back accepted, job_id, number, and position: the event position, usable as after= on the next read so you see your own write. A missing fact the app would hold on Draft is refused here with 422 naming the field. It never deletes anything. It changes only what the command names, and it writes the change to the job's history with who asked for it. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `accepted` | true or false | True when the command ran. A command that cannot run is an error instead. | | `job_id` | id (text) | The id of the job. | | `number` | whole number | The number people say out loud, such as the job number. | | `position` | whole number | Where the change landed in the event log. Pass it as `after` on a read to see your own write. | | `status` | object | The job status. | | `status.id` | id (text) | The id of this record. Ids are opaque text: keep them exactly as given. | | `status.name` | text | The name, as the app shows it. | | `status.slug` | text | The same name as a lowercase code word. Match on this, not on the name. | ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`read_only`](https://headhoncho.app/docs/api/errors#read_only) | 403 | This credential may read this area but not change it. | | [`not_found`](https://headhoncho.app/docs/api/errors#not_found) | 404 | No such record in the companies this credential reaches. | | [`out_of_scope`](https://headhoncho.app/docs/api/errors#out_of_scope) | 404 | No such company in the companies this credential reaches. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`missing_idempotency_key`](https://headhoncho.app/docs/api/errors#missing_idempotency_key) | 400 | Send an Idempotency-Key header on every command. | | [`idempotency_mismatch`](https://headhoncho.app/docs/api/errors#idempotency_mismatch) | 409 | This Idempotency-Key was used with a different body. | | [`idempotency_in_progress`](https://headhoncho.app/docs/api/errors#idempotency_in_progress) | 409 | A command with this Idempotency-Key is still running. Wait a moment and send it again. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [Update job](https://headhoncho.app/docs/api/update_job): Change a job's facts: the customer, the address, the schedule, the job type or the notes. Only the fields you send change. - [Change job status](https://headhoncho.app/docs/api/change_job_status): Move a job to another status by its name, slug or id. The move lands in the job's history with who asked for it. - [Assign worker](https://headhoncho.app/docs/api/assign_worker): Put a technician or subcontractor on a job. If Job follow-up is on, the automation acts on it at once, as it would from the app. - [Unassign worker](https://headhoncho.app/docs/api/unassign_worker): Take a technician or subcontractor off a job. The ticket's cancellation reaches them the way it does from the app. - [Add job note](https://headhoncho.app/docs/api/add_job_note): Add a note to a job. It appends to the job's log and never overwrites. - [Update job note](https://headhoncho.app/docs/api/update_job_note): Fix what a note says. Only the person who wrote it may change it; the old text stays in the job's history. - [Delete job note](https://headhoncho.app/docs/api/delete_job_note): Take a note off a job. Its author or an owner may. The removal is in the job's history. - [Set job cut](https://headhoncho.app/docs/api/set_job_cut): What one technician or subcontractor on a job is paid on this job: a percent of the total, a percent of the profit, or a flat amount. - [Release job status](https://headhoncho.app/docs/api/release_job_status): Hand a status set by hand back to the automation. The job moves at once to the status its facts hold, and History says why. - [Resolve job detour](https://headhoncho.app/docs/api/resolve_job_detour): Close a job's detour, such as Waiting on parts. The job goes back to the status it left, then on to where its facts put it. - [Archive job](https://headhoncho.app/docs/api/archive_job): File a finished job away, off the boards. It keeps its money and counts in every figure; Unarchive brings it back. - [Unarchive job](https://headhoncho.app/docs/api/unarchive_job): Bring an archived job back onto the boards, as it was. - [Trash job](https://headhoncho.app/docs/api/trash_job): Move a job to Trash, with why. It leaves every list and every figure, and can be restored for 30 days. - [Restore job](https://headhoncho.app/docs/api/restore_job): Bring a job back from Trash, whole: its money, its history and its technicians. - [Upload photo](https://headhoncho.app/docs/api/upload_photo): Put one photo on a job. Send the picture as base64 text; it is stored and confirmed in one call. - [Delete photo](https://headhoncho.app/docs/api/delete_photo): Remove one photo from a job, for good: its record and its file. - The same records in the app: [the Jobs panel](https://headhoncho.app/docs/jobs). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "accepted": true, "job_id": "job_1203", "number": 1203, "position": 88411, "status": { "id": "st_02", "name": "Scheduled", "slug": "scheduled" } } ``` ### cURL ```bash curl -X POST "https://api.headhoncho.app/api/v1/commands/create-job" \ -H "Authorization: Bearer hh_live_..." \ -H "Idempotency-Key: 6f1d2c9e-1b7a-4c1e-9a52-0d3f8e4b7a10" \ -H "Content-Type: application/json" \ -d '{ "company_id": "cmp_14f5", "client_name": "R. Azoulay", "client_phone": "+12175550142", "address": { "line1": "2590 Main St", "city": "Bloomington", "state": "IL", "postal_code": "61701" }, "job_type_id": "jt_02", "scheduled_start": "2026-10-16T09:00:00-05:00", "scheduled_end": "2026-10-16T11:00:00-05:00", "worker_id": "wrk_3b90", "notes": "Two flights of stairs", "intent": "create", "utm_source": "google", "utm_medium": "cpc", "utm_campaign": "Spring Repairs", "utm_term": "garage door repair", "utm_content": "ad-2", "gclid": "Cj0KCQiA…", "landing_page": "https://example.com/garage-door-repair?gclid=Cj0KCQiA…", "form_name": "Request service", "form_id": "cf7-118-2026-11-06T14:02:11Z", "submitted_at": "2026-11-06T14:02:11Z" }' ``` ### Python ```python import requests import uuid response = requests.post( "https://api.headhoncho.app/api/v1/commands/create-job", headers={ "Authorization": "Bearer hh_live_...", "Idempotency-Key": str(uuid.uuid4()), }, json={ "company_id": "cmp_14f5", "client_name": "R. Azoulay", "client_phone": "+12175550142", "address": { "line1": "2590 Main St", "city": "Bloomington", "state": "IL", "postal_code": "61701", }, "job_type_id": "jt_02", "scheduled_start": "2026-10-16T09:00:00-05:00", "scheduled_end": "2026-10-16T11:00:00-05:00", "worker_id": "wrk_3b90", "notes": "Two flights of stairs", "intent": "create", "utm_source": "google", "utm_medium": "cpc", "utm_campaign": "Spring Repairs", "utm_term": "garage door repair", "utm_content": "ad-2", "gclid": "Cj0KCQiA…", "landing_page": "https://example.com/garage-door-repair?gclid=Cj0KCQiA…", "form_name": "Request service", "form_id": "cf7-118-2026-11-06T14:02:11Z", "submitted_at": "2026-11-06T14:02:11Z", }, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/commands/create-job", { method: "POST", headers: { Authorization: "Bearer hh_live_...", "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "company_id": "cmp_14f5", "client_name": "R. Azoulay", "client_phone": "+12175550142", "address": { "line1": "2590 Main St", "city": "Bloomington", "state": "IL", "postal_code": "61701" }, "job_type_id": "jt_02", "scheduled_start": "2026-10-16T09:00:00-05:00", "scheduled_end": "2026-10-16T11:00:00-05:00", "worker_id": "wrk_3b90", "notes": "Two flights of stairs", "intent": "create", "utm_source": "google", "utm_medium": "cpc", "utm_campaign": "Spring Repairs", "utm_term": "garage door repair", "utm_content": "ad-2", "gclid": "Cj0KCQiA…", "landing_page": "https://example.com/garage-door-repair?gclid=Cj0KCQiA…", "form_name": "Request service", "form_id": "cf7-118-2026-11-06T14:02:11Z", "submitted_at": "2026-11-06T14:02:11Z" }), }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: create_job Arguments: company_id (id, required), client_name (text, required), client_phone (text, required), address (object, required), job_type_id (id, optional), scheduled_start (datetime, optional), scheduled_end (datetime, optional), worker_id (id, optional), notes (text, optional), intent (text, optional), utm_source (text, optional), utm_medium (text, optional), utm_campaign (text, optional), utm_term (text, optional), utm_content (text, optional), gclid (text, optional), gbraid (text, optional), wbraid (text, optional), msclkid (text, optional), fbclid (text, optional), landing_page (text, optional), form_name (text, optional), form_id (text, optional), submitted_at (datetime, optional) Access: do on Jobs Hints: readOnly=false, destructive=false, idempotent=false, openWorld=false Try asking: "Using HeadHoncho, create job with company_id cmp_14f5 and client_name R. Azoulay and client_phone +12175550142 and address {"line1": "2590 Main St", "city": "Bloomington", "state": "IL", "postal_code": "61701"} and job_type_id jt_02." ``` --- # Update job Update job is a command in the HeadHoncho API. Change a job's facts: the customer, the address, the schedule, the job type or the notes. Only the fields you send change. Page: https://headhoncho.app/docs/api/update_job | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **Update job**, HeadHoncho API v1. It is a command, sent to the base address `https://api.headhoncho.app`. `POST /api/v1/commands/update-job` The key needs the **Jobs** area at **do**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). It runs the app's own command `update-job`. Send an `Idempotency-Key` header with every call: the same key with the same body returns the first answer and runs nothing twice. See [the model](https://headhoncho.app/docs/api/model#idempotency). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `job_id` | id, in the JSON body | Yes | The job id, or its number. | `job_1203` | | `client_name` | text, in the JSON body | No | The customer. | None | | `client_phone` | text, in the JSON body | No | Any format; stored as E.164. | None | | `client_secondary_phone` | text, in the JSON body | No | A second phone, or empty to clear it. | None | | `address` | object, in the JSON body | No | All four parts, as for Create a job. | None | | `job_type_id` | id, in the JSON body | No | From Who am I. | None | | `scheduled_start` | datetime, in the JSON body | No | ISO 8601. Send null to clear the window. | `2026-10-16T14:00:00-05:00` | | `scheduled_end` | datetime, in the JSON body | No | The end of the window. | `2026-10-16T17:00:00-05:00` | | `notes` | text, in the JSON body | No | Replaces the notes. | None | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back accepted, job_id, number, position, and changed: the fields that moved. It never deletes anything. It changes only what the command names, and it writes the change to the job's history with who asked for it. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `accepted` | true or false | True when the command ran. A command that cannot run is an error instead. | | `job_id` | id (text) | The id of the job. | | `number` | whole number | The number people say out loud, such as the job number. | | `position` | whole number | Where the change landed in the event log. Pass it as `after` on a read to see your own write. | | `changed` | list of text | The changed. | ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`read_only`](https://headhoncho.app/docs/api/errors#read_only) | 403 | This credential may read this area but not change it. | | [`not_found`](https://headhoncho.app/docs/api/errors#not_found) | 404 | No such record in the companies this credential reaches. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`missing_idempotency_key`](https://headhoncho.app/docs/api/errors#missing_idempotency_key) | 400 | Send an Idempotency-Key header on every command. | | [`idempotency_mismatch`](https://headhoncho.app/docs/api/errors#idempotency_mismatch) | 409 | This Idempotency-Key was used with a different body. | | [`idempotency_in_progress`](https://headhoncho.app/docs/api/errors#idempotency_in_progress) | 409 | A command with this Idempotency-Key is still running. Wait a moment and send it again. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [Create job](https://headhoncho.app/docs/api/create_job): Open a job or a lead in one company: the customer, the address, and optionally the job type, the time window and the technician. - [Change job status](https://headhoncho.app/docs/api/change_job_status): Move a job to another status by its name, slug or id. The move lands in the job's history with who asked for it. - [Assign worker](https://headhoncho.app/docs/api/assign_worker): Put a technician or subcontractor on a job. If Job follow-up is on, the automation acts on it at once, as it would from the app. - [Unassign worker](https://headhoncho.app/docs/api/unassign_worker): Take a technician or subcontractor off a job. The ticket's cancellation reaches them the way it does from the app. - [Add job note](https://headhoncho.app/docs/api/add_job_note): Add a note to a job. It appends to the job's log and never overwrites. - [Update job note](https://headhoncho.app/docs/api/update_job_note): Fix what a note says. Only the person who wrote it may change it; the old text stays in the job's history. - [Delete job note](https://headhoncho.app/docs/api/delete_job_note): Take a note off a job. Its author or an owner may. The removal is in the job's history. - [Set job cut](https://headhoncho.app/docs/api/set_job_cut): What one technician or subcontractor on a job is paid on this job: a percent of the total, a percent of the profit, or a flat amount. - [Release job status](https://headhoncho.app/docs/api/release_job_status): Hand a status set by hand back to the automation. The job moves at once to the status its facts hold, and History says why. - [Resolve job detour](https://headhoncho.app/docs/api/resolve_job_detour): Close a job's detour, such as Waiting on parts. The job goes back to the status it left, then on to where its facts put it. - [Archive job](https://headhoncho.app/docs/api/archive_job): File a finished job away, off the boards. It keeps its money and counts in every figure; Unarchive brings it back. - [Unarchive job](https://headhoncho.app/docs/api/unarchive_job): Bring an archived job back onto the boards, as it was. - [Trash job](https://headhoncho.app/docs/api/trash_job): Move a job to Trash, with why. It leaves every list and every figure, and can be restored for 30 days. - [Restore job](https://headhoncho.app/docs/api/restore_job): Bring a job back from Trash, whole: its money, its history and its technicians. - [Upload photo](https://headhoncho.app/docs/api/upload_photo): Put one photo on a job. Send the picture as base64 text; it is stored and confirmed in one call. - [Delete photo](https://headhoncho.app/docs/api/delete_photo): Remove one photo from a job, for good: its record and its file. - The same records in the app: [the Jobs panel](https://headhoncho.app/docs/jobs). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "accepted": true, "job_id": "job_1203", "number": 1203, "position": 88411, "changed": [ "scheduled_start", "scheduled_end" ] } ``` ### cURL ```bash curl -X POST "https://api.headhoncho.app/api/v1/commands/update-job" \ -H "Authorization: Bearer hh_live_..." \ -H "Idempotency-Key: 6f1d2c9e-1b7a-4c1e-9a52-0d3f8e4b7a10" \ -H "Content-Type: application/json" \ -d '{ "job_id": "job_1203", "scheduled_start": "2026-10-16T14:00:00-05:00", "scheduled_end": "2026-10-16T17:00:00-05:00" }' ``` ### Python ```python import requests import uuid response = requests.post( "https://api.headhoncho.app/api/v1/commands/update-job", headers={ "Authorization": "Bearer hh_live_...", "Idempotency-Key": str(uuid.uuid4()), }, json={ "job_id": "job_1203", "scheduled_start": "2026-10-16T14:00:00-05:00", "scheduled_end": "2026-10-16T17:00:00-05:00", }, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/commands/update-job", { method: "POST", headers: { Authorization: "Bearer hh_live_...", "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "job_id": "job_1203", "scheduled_start": "2026-10-16T14:00:00-05:00", "scheduled_end": "2026-10-16T17:00:00-05:00" }), }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: update_job Arguments: job_id (id, required), client_name (text, optional), client_phone (text, optional), client_secondary_phone (text, optional), address (object, optional), job_type_id (id, optional), scheduled_start (datetime, optional), scheduled_end (datetime, optional), notes (text, optional) Access: do on Jobs Hints: readOnly=false, destructive=false, idempotent=true, openWorld=false Try asking: "Using HeadHoncho, update job with job_id job_1203 and scheduled_start 2026-10-16T14:00:00-05:00." ``` --- # Change job status Change job status is a command in the HeadHoncho API. Move a job to another status by its name, slug or id. The move lands in the job's history with who asked for it. Page: https://headhoncho.app/docs/api/change_job_status | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **Change job status**, HeadHoncho API v1. It is a command, sent to the base address `https://api.headhoncho.app`. `POST /api/v1/commands/change-job-status` The key needs the **Jobs** area at **do**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). It runs the app's own command `change-job-status`. Send an `Idempotency-Key` header with every call: the same key with the same body returns the first answer and runs nothing twice. See [the model](https://headhoncho.app/docs/api/model#idempotency). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `job_id` | id, in the JSON body | Yes | The job id, or its number. | `job_1203` | | `status` | text, in the JSON body | Yes | A status name or slug from Who am I. status_id works too. | `Dispatched` | | `reason` | text, in the JSON body | No | Read on a move into Canceled: why. | `Customer found another mover` | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back accepted, job_id, number, position, and status: where the job now stands. It never deletes anything. It changes only what the command names, and it writes the change to the job's history with who asked for it. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `accepted` | true or false | True when the command ran. A command that cannot run is an error instead. | | `job_id` | id (text) | The id of the job. | | `number` | whole number | The number people say out loud, such as the job number. | | `position` | whole number | Where the change landed in the event log. Pass it as `after` on a read to see your own write. | | `status` | object | The job status. | | `status.id` | id (text) | The id of this record. Ids are opaque text: keep them exactly as given. | | `status.name` | text | The name, as the app shows it. | | `status.slug` | text | The same name as a lowercase code word. Match on this, not on the name. | ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`read_only`](https://headhoncho.app/docs/api/errors#read_only) | 403 | This credential may read this area but not change it. | | [`not_found`](https://headhoncho.app/docs/api/errors#not_found) | 404 | No such record in the companies this credential reaches. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`missing_idempotency_key`](https://headhoncho.app/docs/api/errors#missing_idempotency_key) | 400 | Send an Idempotency-Key header on every command. | | [`idempotency_mismatch`](https://headhoncho.app/docs/api/errors#idempotency_mismatch) | 409 | This Idempotency-Key was used with a different body. | | [`idempotency_in_progress`](https://headhoncho.app/docs/api/errors#idempotency_in_progress) | 409 | A command with this Idempotency-Key is still running. Wait a moment and send it again. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [Create job](https://headhoncho.app/docs/api/create_job): Open a job or a lead in one company: the customer, the address, and optionally the job type, the time window and the technician. - [Update job](https://headhoncho.app/docs/api/update_job): Change a job's facts: the customer, the address, the schedule, the job type or the notes. Only the fields you send change. - [Assign worker](https://headhoncho.app/docs/api/assign_worker): Put a technician or subcontractor on a job. If Job follow-up is on, the automation acts on it at once, as it would from the app. - [Unassign worker](https://headhoncho.app/docs/api/unassign_worker): Take a technician or subcontractor off a job. The ticket's cancellation reaches them the way it does from the app. - [Add job note](https://headhoncho.app/docs/api/add_job_note): Add a note to a job. It appends to the job's log and never overwrites. - [Update job note](https://headhoncho.app/docs/api/update_job_note): Fix what a note says. Only the person who wrote it may change it; the old text stays in the job's history. - [Delete job note](https://headhoncho.app/docs/api/delete_job_note): Take a note off a job. Its author or an owner may. The removal is in the job's history. - [Set job cut](https://headhoncho.app/docs/api/set_job_cut): What one technician or subcontractor on a job is paid on this job: a percent of the total, a percent of the profit, or a flat amount. - [Release job status](https://headhoncho.app/docs/api/release_job_status): Hand a status set by hand back to the automation. The job moves at once to the status its facts hold, and History says why. - [Resolve job detour](https://headhoncho.app/docs/api/resolve_job_detour): Close a job's detour, such as Waiting on parts. The job goes back to the status it left, then on to where its facts put it. - [Archive job](https://headhoncho.app/docs/api/archive_job): File a finished job away, off the boards. It keeps its money and counts in every figure; Unarchive brings it back. - [Unarchive job](https://headhoncho.app/docs/api/unarchive_job): Bring an archived job back onto the boards, as it was. - [Trash job](https://headhoncho.app/docs/api/trash_job): Move a job to Trash, with why. It leaves every list and every figure, and can be restored for 30 days. - [Restore job](https://headhoncho.app/docs/api/restore_job): Bring a job back from Trash, whole: its money, its history and its technicians. - [Upload photo](https://headhoncho.app/docs/api/upload_photo): Put one photo on a job. Send the picture as base64 text; it is stored and confirmed in one call. - [Delete photo](https://headhoncho.app/docs/api/delete_photo): Remove one photo from a job, for good: its record and its file. - The same records in the app: [the Jobs panel](https://headhoncho.app/docs/jobs). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "accepted": true, "job_id": "job_1203", "number": 1203, "position": 88411, "status": { "id": "st_03", "name": "Dispatched", "slug": "dispatched" } } ``` ### cURL ```bash curl -X POST "https://api.headhoncho.app/api/v1/commands/change-job-status" \ -H "Authorization: Bearer hh_live_..." \ -H "Idempotency-Key: 6f1d2c9e-1b7a-4c1e-9a52-0d3f8e4b7a10" \ -H "Content-Type: application/json" \ -d '{ "job_id": "job_1203", "status": "Dispatched", "reason": "Customer found another mover" }' ``` ### Python ```python import requests import uuid response = requests.post( "https://api.headhoncho.app/api/v1/commands/change-job-status", headers={ "Authorization": "Bearer hh_live_...", "Idempotency-Key": str(uuid.uuid4()), }, json={ "job_id": "job_1203", "status": "Dispatched", "reason": "Customer found another mover", }, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/commands/change-job-status", { method: "POST", headers: { Authorization: "Bearer hh_live_...", "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "job_id": "job_1203", "status": "Dispatched", "reason": "Customer found another mover" }), }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: change_job_status Arguments: job_id (id, required), status (text, required), reason (text, optional) Access: do on Jobs Hints: readOnly=false, destructive=false, idempotent=true, openWorld=false Try asking: "Using HeadHoncho, change job status with job_id job_1203 and status Dispatched and reason Customer found another mover." ``` --- # Assign worker Assign worker is a command in the HeadHoncho API. Put a technician or subcontractor on a job. If Job follow-up is on, the automation acts on it at once, as it would from the app. Page: https://headhoncho.app/docs/api/assign_worker | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **Assign worker**, HeadHoncho API v1. It is a command, sent to the base address `https://api.headhoncho.app`. `POST /api/v1/commands/assign-worker` The key needs the **Jobs** area at **do**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). It runs the app's own command `assign-worker`. Send an `Idempotency-Key` header with every call: the same key with the same body returns the first answer and runs nothing twice. See [the model](https://headhoncho.app/docs/api/model#idempotency). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `job_id` | id, in the JSON body | Yes | The job id, or its number. | `job_1203` | | `worker_id` | id, in the JSON body | Yes | From Who am I. | `wrk_7a12` | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back accepted, job_id, number, position, technicians now on the job, and automation: one sentence on what the automation did, or empty. It never deletes anything. It changes only what the command names, and it writes the change to the job's history with who asked for it. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `accepted` | true or false | True when the command ran. A command that cannot run is an error instead. | | `job_id` | id (text) | The id of the job. | | `number` | whole number | The number people say out loud, such as the job number. | | `position` | whole number | Where the change landed in the event log. Pass it as `after` on a read to see your own write. | | `technicians` | list of objects | The technicians. | | `technicians[].id` | id (text) | The id of this record. Ids are opaque text: keep them exactly as given. | | `technicians[].name` | text | The name, as the app shows it. | | `automation` | text | One sentence on what an automation did because of this change, or empty. | ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`read_only`](https://headhoncho.app/docs/api/errors#read_only) | 403 | This credential may read this area but not change it. | | [`not_found`](https://headhoncho.app/docs/api/errors#not_found) | 404 | No such record in the companies this credential reaches. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`missing_idempotency_key`](https://headhoncho.app/docs/api/errors#missing_idempotency_key) | 400 | Send an Idempotency-Key header on every command. | | [`idempotency_mismatch`](https://headhoncho.app/docs/api/errors#idempotency_mismatch) | 409 | This Idempotency-Key was used with a different body. | | [`idempotency_in_progress`](https://headhoncho.app/docs/api/errors#idempotency_in_progress) | 409 | A command with this Idempotency-Key is still running. Wait a moment and send it again. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [Create job](https://headhoncho.app/docs/api/create_job): Open a job or a lead in one company: the customer, the address, and optionally the job type, the time window and the technician. - [Update job](https://headhoncho.app/docs/api/update_job): Change a job's facts: the customer, the address, the schedule, the job type or the notes. Only the fields you send change. - [Change job status](https://headhoncho.app/docs/api/change_job_status): Move a job to another status by its name, slug or id. The move lands in the job's history with who asked for it. - [Unassign worker](https://headhoncho.app/docs/api/unassign_worker): Take a technician or subcontractor off a job. The ticket's cancellation reaches them the way it does from the app. - [Add job note](https://headhoncho.app/docs/api/add_job_note): Add a note to a job. It appends to the job's log and never overwrites. - [Update job note](https://headhoncho.app/docs/api/update_job_note): Fix what a note says. Only the person who wrote it may change it; the old text stays in the job's history. - [Delete job note](https://headhoncho.app/docs/api/delete_job_note): Take a note off a job. Its author or an owner may. The removal is in the job's history. - [Set job cut](https://headhoncho.app/docs/api/set_job_cut): What one technician or subcontractor on a job is paid on this job: a percent of the total, a percent of the profit, or a flat amount. - [Release job status](https://headhoncho.app/docs/api/release_job_status): Hand a status set by hand back to the automation. The job moves at once to the status its facts hold, and History says why. - [Resolve job detour](https://headhoncho.app/docs/api/resolve_job_detour): Close a job's detour, such as Waiting on parts. The job goes back to the status it left, then on to where its facts put it. - [Archive job](https://headhoncho.app/docs/api/archive_job): File a finished job away, off the boards. It keeps its money and counts in every figure; Unarchive brings it back. - [Unarchive job](https://headhoncho.app/docs/api/unarchive_job): Bring an archived job back onto the boards, as it was. - [Trash job](https://headhoncho.app/docs/api/trash_job): Move a job to Trash, with why. It leaves every list and every figure, and can be restored for 30 days. - [Restore job](https://headhoncho.app/docs/api/restore_job): Bring a job back from Trash, whole: its money, its history and its technicians. - [Upload photo](https://headhoncho.app/docs/api/upload_photo): Put one photo on a job. Send the picture as base64 text; it is stored and confirmed in one call. - [Delete photo](https://headhoncho.app/docs/api/delete_photo): Remove one photo from a job, for good: its record and its file. - The same records in the app: [the Jobs panel](https://headhoncho.app/docs/jobs). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "accepted": true, "job_id": "job_1203", "number": 1203, "position": 88411, "technicians": [ { "id": "wrk_7a12", "name": "Omar S." } ], "automation": "Ticket sent to Omar S." } ``` ### cURL ```bash curl -X POST "https://api.headhoncho.app/api/v1/commands/assign-worker" \ -H "Authorization: Bearer hh_live_..." \ -H "Idempotency-Key: 6f1d2c9e-1b7a-4c1e-9a52-0d3f8e4b7a10" \ -H "Content-Type: application/json" \ -d '{ "job_id": "job_1203", "worker_id": "wrk_7a12" }' ``` ### Python ```python import requests import uuid response = requests.post( "https://api.headhoncho.app/api/v1/commands/assign-worker", headers={ "Authorization": "Bearer hh_live_...", "Idempotency-Key": str(uuid.uuid4()), }, json={ "job_id": "job_1203", "worker_id": "wrk_7a12", }, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/commands/assign-worker", { method: "POST", headers: { Authorization: "Bearer hh_live_...", "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "job_id": "job_1203", "worker_id": "wrk_7a12" }), }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: assign_worker Arguments: job_id (id, required), worker_id (id, required) Access: do on Jobs Hints: readOnly=false, destructive=false, idempotent=true, openWorld=false Try asking: "Using HeadHoncho, assign worker with job_id job_1203 and worker_id wrk_7a12." ``` --- # Unassign worker Unassign worker is a command in the HeadHoncho API. Take a technician or subcontractor off a job. The ticket's cancellation reaches them the way it does from the app. Page: https://headhoncho.app/docs/api/unassign_worker | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **Unassign worker**, HeadHoncho API v1. It is a command, sent to the base address `https://api.headhoncho.app`. `POST /api/v1/commands/unassign-worker` The key needs the **Jobs** area at **do**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). It runs the app's own command `unassign-worker`. Send an `Idempotency-Key` header with every call: the same key with the same body returns the first answer and runs nothing twice. See [the model](https://headhoncho.app/docs/api/model#idempotency). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `job_id` | id, in the JSON body | Yes | The job id, or its number. | `job_1203` | | `worker_id` | id, in the JSON body | Yes | From Who am I. | `wrk_7a12` | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back accepted, job_id, number, position, and technicians still on the job. It never deletes anything. It changes only what the command names, and it writes the change to the job's history with who asked for it. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `accepted` | true or false | True when the command ran. A command that cannot run is an error instead. | | `job_id` | id (text) | The id of the job. | | `number` | whole number | The number people say out loud, such as the job number. | | `position` | whole number | Where the change landed in the event log. Pass it as `after` on a read to see your own write. | | `technicians` | list | The technicians. | ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`read_only`](https://headhoncho.app/docs/api/errors#read_only) | 403 | This credential may read this area but not change it. | | [`not_found`](https://headhoncho.app/docs/api/errors#not_found) | 404 | No such record in the companies this credential reaches. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`missing_idempotency_key`](https://headhoncho.app/docs/api/errors#missing_idempotency_key) | 400 | Send an Idempotency-Key header on every command. | | [`idempotency_mismatch`](https://headhoncho.app/docs/api/errors#idempotency_mismatch) | 409 | This Idempotency-Key was used with a different body. | | [`idempotency_in_progress`](https://headhoncho.app/docs/api/errors#idempotency_in_progress) | 409 | A command with this Idempotency-Key is still running. Wait a moment and send it again. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [Create job](https://headhoncho.app/docs/api/create_job): Open a job or a lead in one company: the customer, the address, and optionally the job type, the time window and the technician. - [Update job](https://headhoncho.app/docs/api/update_job): Change a job's facts: the customer, the address, the schedule, the job type or the notes. Only the fields you send change. - [Change job status](https://headhoncho.app/docs/api/change_job_status): Move a job to another status by its name, slug or id. The move lands in the job's history with who asked for it. - [Assign worker](https://headhoncho.app/docs/api/assign_worker): Put a technician or subcontractor on a job. If Job follow-up is on, the automation acts on it at once, as it would from the app. - [Add job note](https://headhoncho.app/docs/api/add_job_note): Add a note to a job. It appends to the job's log and never overwrites. - [Update job note](https://headhoncho.app/docs/api/update_job_note): Fix what a note says. Only the person who wrote it may change it; the old text stays in the job's history. - [Delete job note](https://headhoncho.app/docs/api/delete_job_note): Take a note off a job. Its author or an owner may. The removal is in the job's history. - [Set job cut](https://headhoncho.app/docs/api/set_job_cut): What one technician or subcontractor on a job is paid on this job: a percent of the total, a percent of the profit, or a flat amount. - [Release job status](https://headhoncho.app/docs/api/release_job_status): Hand a status set by hand back to the automation. The job moves at once to the status its facts hold, and History says why. - [Resolve job detour](https://headhoncho.app/docs/api/resolve_job_detour): Close a job's detour, such as Waiting on parts. The job goes back to the status it left, then on to where its facts put it. - [Archive job](https://headhoncho.app/docs/api/archive_job): File a finished job away, off the boards. It keeps its money and counts in every figure; Unarchive brings it back. - [Unarchive job](https://headhoncho.app/docs/api/unarchive_job): Bring an archived job back onto the boards, as it was. - [Trash job](https://headhoncho.app/docs/api/trash_job): Move a job to Trash, with why. It leaves every list and every figure, and can be restored for 30 days. - [Restore job](https://headhoncho.app/docs/api/restore_job): Bring a job back from Trash, whole: its money, its history and its technicians. - [Upload photo](https://headhoncho.app/docs/api/upload_photo): Put one photo on a job. Send the picture as base64 text; it is stored and confirmed in one call. - [Delete photo](https://headhoncho.app/docs/api/delete_photo): Remove one photo from a job, for good: its record and its file. - The same records in the app: [the Jobs panel](https://headhoncho.app/docs/jobs). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "accepted": true, "job_id": "job_1203", "number": 1203, "position": 88411, "technicians": [] } ``` ### cURL ```bash curl -X POST "https://api.headhoncho.app/api/v1/commands/unassign-worker" \ -H "Authorization: Bearer hh_live_..." \ -H "Idempotency-Key: 6f1d2c9e-1b7a-4c1e-9a52-0d3f8e4b7a10" \ -H "Content-Type: application/json" \ -d '{ "job_id": "job_1203", "worker_id": "wrk_7a12" }' ``` ### Python ```python import requests import uuid response = requests.post( "https://api.headhoncho.app/api/v1/commands/unassign-worker", headers={ "Authorization": "Bearer hh_live_...", "Idempotency-Key": str(uuid.uuid4()), }, json={ "job_id": "job_1203", "worker_id": "wrk_7a12", }, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/commands/unassign-worker", { method: "POST", headers: { Authorization: "Bearer hh_live_...", "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "job_id": "job_1203", "worker_id": "wrk_7a12" }), }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: unassign_worker Arguments: job_id (id, required), worker_id (id, required) Access: do on Jobs Hints: readOnly=false, destructive=false, idempotent=true, openWorld=false Try asking: "Using HeadHoncho, unassign worker with job_id job_1203 and worker_id wrk_7a12." ``` --- # Add job note Add job note is a command in the HeadHoncho API. Add a note to a job. It appends to the job's log and never overwrites. Page: https://headhoncho.app/docs/api/add_job_note | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **Add job note**, HeadHoncho API v1. It is a command, sent to the base address `https://api.headhoncho.app`. `POST /api/v1/commands/add-job-note` The key needs the **Jobs** area at **do**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). It runs the app's own command `add-job-note`. Send an `Idempotency-Key` header with every call: the same key with the same body returns the first answer and runs nothing twice. See [the model](https://headhoncho.app/docs/api/model#idempotency). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `job_id` | id, in the JSON body | Yes | The job id, or its number. | `job_1203` | | `body` | text, in the JSON body | Yes | The note, as written. | `Gate code 4410` | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back accepted, job_id, number, note_id and position. It never deletes anything. It changes only what the command names, and it writes the change to the job's history with who asked for it. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `accepted` | true or false | True when the command ran. A command that cannot run is an error instead. | | `job_id` | id (text) | The id of the job. | | `number` | whole number | The number people say out loud, such as the job number. | | `position` | whole number | Where the change landed in the event log. Pass it as `after` on a read to see your own write. | | `note_id` | id (text) | The id of the note. | ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`read_only`](https://headhoncho.app/docs/api/errors#read_only) | 403 | This credential may read this area but not change it. | | [`not_found`](https://headhoncho.app/docs/api/errors#not_found) | 404 | No such record in the companies this credential reaches. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`missing_idempotency_key`](https://headhoncho.app/docs/api/errors#missing_idempotency_key) | 400 | Send an Idempotency-Key header on every command. | | [`idempotency_mismatch`](https://headhoncho.app/docs/api/errors#idempotency_mismatch) | 409 | This Idempotency-Key was used with a different body. | | [`idempotency_in_progress`](https://headhoncho.app/docs/api/errors#idempotency_in_progress) | 409 | A command with this Idempotency-Key is still running. Wait a moment and send it again. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [Create job](https://headhoncho.app/docs/api/create_job): Open a job or a lead in one company: the customer, the address, and optionally the job type, the time window and the technician. - [Update job](https://headhoncho.app/docs/api/update_job): Change a job's facts: the customer, the address, the schedule, the job type or the notes. Only the fields you send change. - [Change job status](https://headhoncho.app/docs/api/change_job_status): Move a job to another status by its name, slug or id. The move lands in the job's history with who asked for it. - [Assign worker](https://headhoncho.app/docs/api/assign_worker): Put a technician or subcontractor on a job. If Job follow-up is on, the automation acts on it at once, as it would from the app. - [Unassign worker](https://headhoncho.app/docs/api/unassign_worker): Take a technician or subcontractor off a job. The ticket's cancellation reaches them the way it does from the app. - [Update job note](https://headhoncho.app/docs/api/update_job_note): Fix what a note says. Only the person who wrote it may change it; the old text stays in the job's history. - [Delete job note](https://headhoncho.app/docs/api/delete_job_note): Take a note off a job. Its author or an owner may. The removal is in the job's history. - [Set job cut](https://headhoncho.app/docs/api/set_job_cut): What one technician or subcontractor on a job is paid on this job: a percent of the total, a percent of the profit, or a flat amount. - [Release job status](https://headhoncho.app/docs/api/release_job_status): Hand a status set by hand back to the automation. The job moves at once to the status its facts hold, and History says why. - [Resolve job detour](https://headhoncho.app/docs/api/resolve_job_detour): Close a job's detour, such as Waiting on parts. The job goes back to the status it left, then on to where its facts put it. - [Archive job](https://headhoncho.app/docs/api/archive_job): File a finished job away, off the boards. It keeps its money and counts in every figure; Unarchive brings it back. - [Unarchive job](https://headhoncho.app/docs/api/unarchive_job): Bring an archived job back onto the boards, as it was. - [Trash job](https://headhoncho.app/docs/api/trash_job): Move a job to Trash, with why. It leaves every list and every figure, and can be restored for 30 days. - [Restore job](https://headhoncho.app/docs/api/restore_job): Bring a job back from Trash, whole: its money, its history and its technicians. - [Upload photo](https://headhoncho.app/docs/api/upload_photo): Put one photo on a job. Send the picture as base64 text; it is stored and confirmed in one call. - [Delete photo](https://headhoncho.app/docs/api/delete_photo): Remove one photo from a job, for good: its record and its file. - The same records in the app: [the Jobs panel](https://headhoncho.app/docs/jobs). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "accepted": true, "job_id": "job_1203", "number": 1203, "position": 88411, "note_id": "note_5c21" } ``` ### cURL ```bash curl -X POST "https://api.headhoncho.app/api/v1/commands/add-job-note" \ -H "Authorization: Bearer hh_live_..." \ -H "Idempotency-Key: 6f1d2c9e-1b7a-4c1e-9a52-0d3f8e4b7a10" \ -H "Content-Type: application/json" \ -d '{ "job_id": "job_1203", "body": "Gate code 4410" }' ``` ### Python ```python import requests import uuid response = requests.post( "https://api.headhoncho.app/api/v1/commands/add-job-note", headers={ "Authorization": "Bearer hh_live_...", "Idempotency-Key": str(uuid.uuid4()), }, json={ "job_id": "job_1203", "body": "Gate code 4410", }, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/commands/add-job-note", { method: "POST", headers: { Authorization: "Bearer hh_live_...", "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "job_id": "job_1203", "body": "Gate code 4410" }), }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: add_job_note Arguments: job_id (id, required), body (text, required) Access: do on Jobs Hints: readOnly=false, destructive=false, idempotent=false, openWorld=false Try asking: "Using HeadHoncho, add job note with job_id job_1203 and body Gate code 4410." ``` --- # Update job note Update job note is a command in the HeadHoncho API. Fix what a note says. Only the person who wrote it may change it; the old text stays in the job's history. Page: https://headhoncho.app/docs/api/update_job_note | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **Update job note**, HeadHoncho API v1. It is a command, sent to the base address `https://api.headhoncho.app`. `POST /api/v1/commands/update-job-note` The key needs the **Jobs** area at **do**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). It runs the app's own command `update-job-note`. Send an `Idempotency-Key` header with every call: the same key with the same body returns the first answer and runs nothing twice. See [the model](https://headhoncho.app/docs/api/model#idempotency). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `job_id` | id, in the JSON body | Yes | The job id, or its number. | `job_1203` | | `note_id` | id, in the JSON body | Yes | From Add a note's answer, or the job's history. | `note_5c21` | | `body` | text, in the JSON body | Yes | The corrected note. | `Gate code 4417` | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back accepted, job_id, number, note_id and position. unchanged: true when the text was already that. It never deletes anything. It changes only what the command names, and it writes the change to the job's history with who asked for it. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `accepted` | true or false | True when the command ran. A command that cannot run is an error instead. | | `job_id` | id (text) | The id of the job. | | `number` | whole number | The number people say out loud, such as the job number. | | `position` | whole number | Where the change landed in the event log. Pass it as `after` on a read to see your own write. | | `note_id` | id (text) | The id of the note. | ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`read_only`](https://headhoncho.app/docs/api/errors#read_only) | 403 | This credential may read this area but not change it. | | [`not_found`](https://headhoncho.app/docs/api/errors#not_found) | 404 | No such record in the companies this credential reaches. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`missing_idempotency_key`](https://headhoncho.app/docs/api/errors#missing_idempotency_key) | 400 | Send an Idempotency-Key header on every command. | | [`idempotency_mismatch`](https://headhoncho.app/docs/api/errors#idempotency_mismatch) | 409 | This Idempotency-Key was used with a different body. | | [`idempotency_in_progress`](https://headhoncho.app/docs/api/errors#idempotency_in_progress) | 409 | A command with this Idempotency-Key is still running. Wait a moment and send it again. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [Create job](https://headhoncho.app/docs/api/create_job): Open a job or a lead in one company: the customer, the address, and optionally the job type, the time window and the technician. - [Update job](https://headhoncho.app/docs/api/update_job): Change a job's facts: the customer, the address, the schedule, the job type or the notes. Only the fields you send change. - [Change job status](https://headhoncho.app/docs/api/change_job_status): Move a job to another status by its name, slug or id. The move lands in the job's history with who asked for it. - [Assign worker](https://headhoncho.app/docs/api/assign_worker): Put a technician or subcontractor on a job. If Job follow-up is on, the automation acts on it at once, as it would from the app. - [Unassign worker](https://headhoncho.app/docs/api/unassign_worker): Take a technician or subcontractor off a job. The ticket's cancellation reaches them the way it does from the app. - [Add job note](https://headhoncho.app/docs/api/add_job_note): Add a note to a job. It appends to the job's log and never overwrites. - [Delete job note](https://headhoncho.app/docs/api/delete_job_note): Take a note off a job. Its author or an owner may. The removal is in the job's history. - [Set job cut](https://headhoncho.app/docs/api/set_job_cut): What one technician or subcontractor on a job is paid on this job: a percent of the total, a percent of the profit, or a flat amount. - [Release job status](https://headhoncho.app/docs/api/release_job_status): Hand a status set by hand back to the automation. The job moves at once to the status its facts hold, and History says why. - [Resolve job detour](https://headhoncho.app/docs/api/resolve_job_detour): Close a job's detour, such as Waiting on parts. The job goes back to the status it left, then on to where its facts put it. - [Archive job](https://headhoncho.app/docs/api/archive_job): File a finished job away, off the boards. It keeps its money and counts in every figure; Unarchive brings it back. - [Unarchive job](https://headhoncho.app/docs/api/unarchive_job): Bring an archived job back onto the boards, as it was. - [Trash job](https://headhoncho.app/docs/api/trash_job): Move a job to Trash, with why. It leaves every list and every figure, and can be restored for 30 days. - [Restore job](https://headhoncho.app/docs/api/restore_job): Bring a job back from Trash, whole: its money, its history and its technicians. - [Upload photo](https://headhoncho.app/docs/api/upload_photo): Put one photo on a job. Send the picture as base64 text; it is stored and confirmed in one call. - [Delete photo](https://headhoncho.app/docs/api/delete_photo): Remove one photo from a job, for good: its record and its file. - The same records in the app: [the Jobs panel](https://headhoncho.app/docs/jobs). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "accepted": true, "job_id": "job_1203", "number": 1203, "position": 88411, "note_id": "note_5c21" } ``` ### cURL ```bash curl -X POST "https://api.headhoncho.app/api/v1/commands/update-job-note" \ -H "Authorization: Bearer hh_live_..." \ -H "Idempotency-Key: 6f1d2c9e-1b7a-4c1e-9a52-0d3f8e4b7a10" \ -H "Content-Type: application/json" \ -d '{ "job_id": "job_1203", "note_id": "note_5c21", "body": "Gate code 4417" }' ``` ### Python ```python import requests import uuid response = requests.post( "https://api.headhoncho.app/api/v1/commands/update-job-note", headers={ "Authorization": "Bearer hh_live_...", "Idempotency-Key": str(uuid.uuid4()), }, json={ "job_id": "job_1203", "note_id": "note_5c21", "body": "Gate code 4417", }, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/commands/update-job-note", { method: "POST", headers: { Authorization: "Bearer hh_live_...", "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "job_id": "job_1203", "note_id": "note_5c21", "body": "Gate code 4417" }), }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: update_job_note Arguments: job_id (id, required), note_id (id, required), body (text, required) Access: do on Jobs Hints: readOnly=false, destructive=false, idempotent=true, openWorld=false Try asking: "Using HeadHoncho, update job note with job_id job_1203 and note_id note_5c21 and body Gate code 4417." ``` --- # Delete job note Delete job note is a command in the HeadHoncho API. Take a note off a job. Its author or an owner may. The removal is in the job's history. Page: https://headhoncho.app/docs/api/delete_job_note | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **Delete job note**, HeadHoncho API v1. It is a command, sent to the base address `https://api.headhoncho.app`. `POST /api/v1/commands/delete-job-note` The key needs the **Jobs** area at **do**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). It runs the app's own command `delete-job-note`. Send an `Idempotency-Key` header with every call: the same key with the same body returns the first answer and runs nothing twice. See [the model](https://headhoncho.app/docs/api/model#idempotency). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `job_id` | id, in the JSON body | Yes | The job id, or its number. | `job_1203` | | `note_id` | id, in the JSON body | Yes | The note to remove. | `note_5c21` | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back accepted, job_id, number, note_id and position. It never deletes anything. It changes only what the command names, and it writes the change to the job's history with who asked for it. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `accepted` | true or false | True when the command ran. A command that cannot run is an error instead. | | `job_id` | id (text) | The id of the job. | | `number` | whole number | The number people say out loud, such as the job number. | | `position` | whole number | Where the change landed in the event log. Pass it as `after` on a read to see your own write. | | `note_id` | id (text) | The id of the note. | ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`read_only`](https://headhoncho.app/docs/api/errors#read_only) | 403 | This credential may read this area but not change it. | | [`not_found`](https://headhoncho.app/docs/api/errors#not_found) | 404 | No such record in the companies this credential reaches. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`missing_idempotency_key`](https://headhoncho.app/docs/api/errors#missing_idempotency_key) | 400 | Send an Idempotency-Key header on every command. | | [`idempotency_mismatch`](https://headhoncho.app/docs/api/errors#idempotency_mismatch) | 409 | This Idempotency-Key was used with a different body. | | [`idempotency_in_progress`](https://headhoncho.app/docs/api/errors#idempotency_in_progress) | 409 | A command with this Idempotency-Key is still running. Wait a moment and send it again. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [Create job](https://headhoncho.app/docs/api/create_job): Open a job or a lead in one company: the customer, the address, and optionally the job type, the time window and the technician. - [Update job](https://headhoncho.app/docs/api/update_job): Change a job's facts: the customer, the address, the schedule, the job type or the notes. Only the fields you send change. - [Change job status](https://headhoncho.app/docs/api/change_job_status): Move a job to another status by its name, slug or id. The move lands in the job's history with who asked for it. - [Assign worker](https://headhoncho.app/docs/api/assign_worker): Put a technician or subcontractor on a job. If Job follow-up is on, the automation acts on it at once, as it would from the app. - [Unassign worker](https://headhoncho.app/docs/api/unassign_worker): Take a technician or subcontractor off a job. The ticket's cancellation reaches them the way it does from the app. - [Add job note](https://headhoncho.app/docs/api/add_job_note): Add a note to a job. It appends to the job's log and never overwrites. - [Update job note](https://headhoncho.app/docs/api/update_job_note): Fix what a note says. Only the person who wrote it may change it; the old text stays in the job's history. - [Set job cut](https://headhoncho.app/docs/api/set_job_cut): What one technician or subcontractor on a job is paid on this job: a percent of the total, a percent of the profit, or a flat amount. - [Release job status](https://headhoncho.app/docs/api/release_job_status): Hand a status set by hand back to the automation. The job moves at once to the status its facts hold, and History says why. - [Resolve job detour](https://headhoncho.app/docs/api/resolve_job_detour): Close a job's detour, such as Waiting on parts. The job goes back to the status it left, then on to where its facts put it. - [Archive job](https://headhoncho.app/docs/api/archive_job): File a finished job away, off the boards. It keeps its money and counts in every figure; Unarchive brings it back. - [Unarchive job](https://headhoncho.app/docs/api/unarchive_job): Bring an archived job back onto the boards, as it was. - [Trash job](https://headhoncho.app/docs/api/trash_job): Move a job to Trash, with why. It leaves every list and every figure, and can be restored for 30 days. - [Restore job](https://headhoncho.app/docs/api/restore_job): Bring a job back from Trash, whole: its money, its history and its technicians. - [Upload photo](https://headhoncho.app/docs/api/upload_photo): Put one photo on a job. Send the picture as base64 text; it is stored and confirmed in one call. - [Delete photo](https://headhoncho.app/docs/api/delete_photo): Remove one photo from a job, for good: its record and its file. - The same records in the app: [the Jobs panel](https://headhoncho.app/docs/jobs). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "accepted": true, "job_id": "job_1203", "number": 1203, "position": 88411, "note_id": "note_5c21" } ``` ### cURL ```bash curl -X POST "https://api.headhoncho.app/api/v1/commands/delete-job-note" \ -H "Authorization: Bearer hh_live_..." \ -H "Idempotency-Key: 6f1d2c9e-1b7a-4c1e-9a52-0d3f8e4b7a10" \ -H "Content-Type: application/json" \ -d '{ "job_id": "job_1203", "note_id": "note_5c21" }' ``` ### Python ```python import requests import uuid response = requests.post( "https://api.headhoncho.app/api/v1/commands/delete-job-note", headers={ "Authorization": "Bearer hh_live_...", "Idempotency-Key": str(uuid.uuid4()), }, json={ "job_id": "job_1203", "note_id": "note_5c21", }, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/commands/delete-job-note", { method: "POST", headers: { Authorization: "Bearer hh_live_...", "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "job_id": "job_1203", "note_id": "note_5c21" }), }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: delete_job_note Arguments: job_id (id, required), note_id (id, required) Access: do on Jobs Hints: readOnly=false, destructive=true, idempotent=true, openWorld=false Try asking: "Using HeadHoncho, delete job note with job_id job_1203 and note_id note_5c21." ``` --- # Set job cut Set job cut is a command in the HeadHoncho API. What one technician or subcontractor on a job is paid on this job: a percent of the total, a percent of the profit, or a flat amount. Page: https://headhoncho.app/docs/api/set_job_cut | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **Set job cut**, HeadHoncho API v1. It is a command, sent to the base address `https://api.headhoncho.app`. `POST /api/v1/commands/set-job-cut` The key needs the **Jobs** area at **do**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). It runs the app's own command `set-job-cut`. Send an `Idempotency-Key` header with every call: the same key with the same body returns the first answer and runs nothing twice. See [the model](https://headhoncho.app/docs/api/model#idempotency). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `job_id` | id, in the JSON body | Yes | The job id, or its number. | `job_1203` | | `worker_id` | id, in the JSON body | Yes | Someone on the job, from Who am I. | `wrk_7a12` | | `cut_basis` | text, in the JSON body | No | job_total, job_profit or fixed_amount. Empty with no cut_value goes back to their usual rate. One of `job_total`, `job_profit`, `fixed_amount`, ``. | `job_profit` | | `cut_value` | money, in the JSON body | No | The percent (50 is 50%), or the flat amount. | `50` | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back accepted, job_id, number, position, worker_id, cut_basis and cut_value as now set. A job's money report shows the share it makes. It never deletes anything. It changes only what the command names, and it writes the change to the job's history with who asked for it. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `accepted` | true or false | True when the command ran. A command that cannot run is an error instead. | | `job_id` | id (text) | The id of the job. | | `number` | whole number | The number people say out loud, such as the job number. | | `position` | whole number | Where the change landed in the event log. Pass it as `after` on a read to see your own write. | | `worker_id` | id (text) | The id of the worker. | | `cut_basis` | text | One of `job_total`, `job_profit`, `fixed_amount`, ``. | | `cut_value` | money (decimal as text) | The cut: a percent, or an amount when the basis is `fixed_amount`. In the company's currency. | ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`read_only`](https://headhoncho.app/docs/api/errors#read_only) | 403 | This credential may read this area but not change it. | | [`not_found`](https://headhoncho.app/docs/api/errors#not_found) | 404 | No such record in the companies this credential reaches. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`missing_idempotency_key`](https://headhoncho.app/docs/api/errors#missing_idempotency_key) | 400 | Send an Idempotency-Key header on every command. | | [`idempotency_mismatch`](https://headhoncho.app/docs/api/errors#idempotency_mismatch) | 409 | This Idempotency-Key was used with a different body. | | [`idempotency_in_progress`](https://headhoncho.app/docs/api/errors#idempotency_in_progress) | 409 | A command with this Idempotency-Key is still running. Wait a moment and send it again. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [Create job](https://headhoncho.app/docs/api/create_job): Open a job or a lead in one company: the customer, the address, and optionally the job type, the time window and the technician. - [Update job](https://headhoncho.app/docs/api/update_job): Change a job's facts: the customer, the address, the schedule, the job type or the notes. Only the fields you send change. - [Change job status](https://headhoncho.app/docs/api/change_job_status): Move a job to another status by its name, slug or id. The move lands in the job's history with who asked for it. - [Assign worker](https://headhoncho.app/docs/api/assign_worker): Put a technician or subcontractor on a job. If Job follow-up is on, the automation acts on it at once, as it would from the app. - [Unassign worker](https://headhoncho.app/docs/api/unassign_worker): Take a technician or subcontractor off a job. The ticket's cancellation reaches them the way it does from the app. - [Add job note](https://headhoncho.app/docs/api/add_job_note): Add a note to a job. It appends to the job's log and never overwrites. - [Update job note](https://headhoncho.app/docs/api/update_job_note): Fix what a note says. Only the person who wrote it may change it; the old text stays in the job's history. - [Delete job note](https://headhoncho.app/docs/api/delete_job_note): Take a note off a job. Its author or an owner may. The removal is in the job's history. - [Release job status](https://headhoncho.app/docs/api/release_job_status): Hand a status set by hand back to the automation. The job moves at once to the status its facts hold, and History says why. - [Resolve job detour](https://headhoncho.app/docs/api/resolve_job_detour): Close a job's detour, such as Waiting on parts. The job goes back to the status it left, then on to where its facts put it. - [Archive job](https://headhoncho.app/docs/api/archive_job): File a finished job away, off the boards. It keeps its money and counts in every figure; Unarchive brings it back. - [Unarchive job](https://headhoncho.app/docs/api/unarchive_job): Bring an archived job back onto the boards, as it was. - [Trash job](https://headhoncho.app/docs/api/trash_job): Move a job to Trash, with why. It leaves every list and every figure, and can be restored for 30 days. - [Restore job](https://headhoncho.app/docs/api/restore_job): Bring a job back from Trash, whole: its money, its history and its technicians. - [Upload photo](https://headhoncho.app/docs/api/upload_photo): Put one photo on a job. Send the picture as base64 text; it is stored and confirmed in one call. - [Delete photo](https://headhoncho.app/docs/api/delete_photo): Remove one photo from a job, for good: its record and its file. - The same records in the app: [the Jobs panel](https://headhoncho.app/docs/jobs). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "accepted": true, "job_id": "job_1203", "number": 1203, "position": 88411, "worker_id": "wrk_7a12", "cut_basis": "job_profit", "cut_value": "50.00" } ``` ### cURL ```bash curl -X POST "https://api.headhoncho.app/api/v1/commands/set-job-cut" \ -H "Authorization: Bearer hh_live_..." \ -H "Idempotency-Key: 6f1d2c9e-1b7a-4c1e-9a52-0d3f8e4b7a10" \ -H "Content-Type: application/json" \ -d '{ "job_id": "job_1203", "worker_id": "wrk_7a12", "cut_basis": "job_profit", "cut_value": 50 }' ``` ### Python ```python import requests import uuid response = requests.post( "https://api.headhoncho.app/api/v1/commands/set-job-cut", headers={ "Authorization": "Bearer hh_live_...", "Idempotency-Key": str(uuid.uuid4()), }, json={ "job_id": "job_1203", "worker_id": "wrk_7a12", "cut_basis": "job_profit", "cut_value": 50, }, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/commands/set-job-cut", { method: "POST", headers: { Authorization: "Bearer hh_live_...", "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "job_id": "job_1203", "worker_id": "wrk_7a12", "cut_basis": "job_profit", "cut_value": 50 }), }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: set_job_cut Arguments: job_id (id, required), worker_id (id, required), cut_basis (text, optional), cut_value (money, optional) Access: do on Jobs Hints: readOnly=false, destructive=false, idempotent=true, openWorld=false Try asking: "Using HeadHoncho, set job cut with job_id job_1203 and worker_id wrk_7a12 and cut_basis job_profit." ``` --- # Release job status Release job status is a command in the HeadHoncho API. Hand a status set by hand back to the automation. The job moves at once to the status its facts hold, and History says why. Page: https://headhoncho.app/docs/api/release_job_status | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **Release job status**, HeadHoncho API v1. It is a command, sent to the base address `https://api.headhoncho.app`. `POST /api/v1/commands/release-job-status` The key needs the **Jobs** area at **do**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). It runs the app's own command `release-job-status`. Send an `Idempotency-Key` header with every call: the same key with the same body returns the first answer and runs nothing twice. See [the model](https://headhoncho.app/docs/api/model#idempotency). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `job_id` | id, in the JSON body | Yes | The job id, or its number. | `job_1138` | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back accepted, job_id, number, status (id and name), unchanged (true when the status was not set by hand, so nothing moved), automation and position. It never deletes anything. It changes only what the command names, and it writes the change to the job's history with who asked for it. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `accepted` | true or false | True when the command ran. A command that cannot run is an error instead. | | `job_id` | id (text) | The id of the job. | | `number` | whole number | The number people say out loud, such as the job number. | | `position` | whole number | Where the change landed in the event log. Pass it as `after` on a read to see your own write. | | `status` | object | The job status. | | `status.id` | id (text) | The id of this record. Ids are opaque text: keep them exactly as given. | | `status.name` | text | The name, as the app shows it. | | `unchanged` | true or false | True when the record already had these values, so nothing was written. | | `automation` | text | One sentence on what an automation did because of this change, or empty. | ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`read_only`](https://headhoncho.app/docs/api/errors#read_only) | 403 | This credential may read this area but not change it. | | [`not_found`](https://headhoncho.app/docs/api/errors#not_found) | 404 | No such record in the companies this credential reaches. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`missing_idempotency_key`](https://headhoncho.app/docs/api/errors#missing_idempotency_key) | 400 | Send an Idempotency-Key header on every command. | | [`idempotency_mismatch`](https://headhoncho.app/docs/api/errors#idempotency_mismatch) | 409 | This Idempotency-Key was used with a different body. | | [`idempotency_in_progress`](https://headhoncho.app/docs/api/errors#idempotency_in_progress) | 409 | A command with this Idempotency-Key is still running. Wait a moment and send it again. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [Create job](https://headhoncho.app/docs/api/create_job): Open a job or a lead in one company: the customer, the address, and optionally the job type, the time window and the technician. - [Update job](https://headhoncho.app/docs/api/update_job): Change a job's facts: the customer, the address, the schedule, the job type or the notes. Only the fields you send change. - [Change job status](https://headhoncho.app/docs/api/change_job_status): Move a job to another status by its name, slug or id. The move lands in the job's history with who asked for it. - [Assign worker](https://headhoncho.app/docs/api/assign_worker): Put a technician or subcontractor on a job. If Job follow-up is on, the automation acts on it at once, as it would from the app. - [Unassign worker](https://headhoncho.app/docs/api/unassign_worker): Take a technician or subcontractor off a job. The ticket's cancellation reaches them the way it does from the app. - [Add job note](https://headhoncho.app/docs/api/add_job_note): Add a note to a job. It appends to the job's log and never overwrites. - [Update job note](https://headhoncho.app/docs/api/update_job_note): Fix what a note says. Only the person who wrote it may change it; the old text stays in the job's history. - [Delete job note](https://headhoncho.app/docs/api/delete_job_note): Take a note off a job. Its author or an owner may. The removal is in the job's history. - [Set job cut](https://headhoncho.app/docs/api/set_job_cut): What one technician or subcontractor on a job is paid on this job: a percent of the total, a percent of the profit, or a flat amount. - [Resolve job detour](https://headhoncho.app/docs/api/resolve_job_detour): Close a job's detour, such as Waiting on parts. The job goes back to the status it left, then on to where its facts put it. - [Archive job](https://headhoncho.app/docs/api/archive_job): File a finished job away, off the boards. It keeps its money and counts in every figure; Unarchive brings it back. - [Unarchive job](https://headhoncho.app/docs/api/unarchive_job): Bring an archived job back onto the boards, as it was. - [Trash job](https://headhoncho.app/docs/api/trash_job): Move a job to Trash, with why. It leaves every list and every figure, and can be restored for 30 days. - [Restore job](https://headhoncho.app/docs/api/restore_job): Bring a job back from Trash, whole: its money, its history and its technicians. - [Upload photo](https://headhoncho.app/docs/api/upload_photo): Put one photo on a job. Send the picture as base64 text; it is stored and confirmed in one call. - [Delete photo](https://headhoncho.app/docs/api/delete_photo): Remove one photo from a job, for good: its record and its file. - The same records in the app: [the Jobs panel](https://headhoncho.app/docs/jobs). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "accepted": true, "job_id": "job_1203", "number": 1203, "position": 88411, "status": { "id": "sts_09", "name": "Scheduled" }, "unchanged": false, "automation": "" } ``` ### cURL ```bash curl -X POST "https://api.headhoncho.app/api/v1/commands/release-job-status" \ -H "Authorization: Bearer hh_live_..." \ -H "Idempotency-Key: 6f1d2c9e-1b7a-4c1e-9a52-0d3f8e4b7a10" \ -H "Content-Type: application/json" \ -d '{ "job_id": "job_1138" }' ``` ### Python ```python import requests import uuid response = requests.post( "https://api.headhoncho.app/api/v1/commands/release-job-status", headers={ "Authorization": "Bearer hh_live_...", "Idempotency-Key": str(uuid.uuid4()), }, json={ "job_id": "job_1138", }, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/commands/release-job-status", { method: "POST", headers: { Authorization: "Bearer hh_live_...", "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "job_id": "job_1138" }), }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: release_job_status Arguments: job_id (id, required) Access: do on Jobs Hints: readOnly=false, destructive=false, idempotent=true, openWorld=false Try asking: "Using HeadHoncho, release job status with job_id job_1138." ``` --- # Resolve job detour Resolve job detour is a command in the HeadHoncho API. Close a job's detour, such as Waiting on parts. The job goes back to the status it left, then on to where its facts put it. Page: https://headhoncho.app/docs/api/resolve_job_detour | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **Resolve job detour**, HeadHoncho API v1. It is a command, sent to the base address `https://api.headhoncho.app`. `POST /api/v1/commands/resolve-job-detour` The key needs the **Jobs** area at **do**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). It runs the app's own command `resolve-job-detour`. Send an `Idempotency-Key` header with every call: the same key with the same body returns the first answer and runs nothing twice. See [the model](https://headhoncho.app/docs/api/model#idempotency). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `job_id` | id, in the JSON body | Yes | The job id, or its number. | `job_1138` | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back accepted, job_id, number, detour (the one it left), status (id and name, where it went back to), automation and position. A job with no detour open is refused. It never deletes anything. It changes only what the command names, and it writes the change to the job's history with who asked for it. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `accepted` | true or false | True when the command ran. A command that cannot run is an error instead. | | `job_id` | id (text) | The id of the job. | | `number` | whole number | The number people say out loud, such as the job number. | | `position` | whole number | Where the change landed in the event log. Pass it as `after` on a read to see your own write. | | `detour` | text | Why the job is waiting, in words. | | `status` | object | The job status. | | `status.id` | id (text) | The id of this record. Ids are opaque text: keep them exactly as given. | | `status.name` | text | The name, as the app shows it. | | `automation` | text | One sentence on what an automation did because of this change, or empty. | ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`read_only`](https://headhoncho.app/docs/api/errors#read_only) | 403 | This credential may read this area but not change it. | | [`not_found`](https://headhoncho.app/docs/api/errors#not_found) | 404 | No such record in the companies this credential reaches. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`missing_idempotency_key`](https://headhoncho.app/docs/api/errors#missing_idempotency_key) | 400 | Send an Idempotency-Key header on every command. | | [`idempotency_mismatch`](https://headhoncho.app/docs/api/errors#idempotency_mismatch) | 409 | This Idempotency-Key was used with a different body. | | [`idempotency_in_progress`](https://headhoncho.app/docs/api/errors#idempotency_in_progress) | 409 | A command with this Idempotency-Key is still running. Wait a moment and send it again. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [Create job](https://headhoncho.app/docs/api/create_job): Open a job or a lead in one company: the customer, the address, and optionally the job type, the time window and the technician. - [Update job](https://headhoncho.app/docs/api/update_job): Change a job's facts: the customer, the address, the schedule, the job type or the notes. Only the fields you send change. - [Change job status](https://headhoncho.app/docs/api/change_job_status): Move a job to another status by its name, slug or id. The move lands in the job's history with who asked for it. - [Assign worker](https://headhoncho.app/docs/api/assign_worker): Put a technician or subcontractor on a job. If Job follow-up is on, the automation acts on it at once, as it would from the app. - [Unassign worker](https://headhoncho.app/docs/api/unassign_worker): Take a technician or subcontractor off a job. The ticket's cancellation reaches them the way it does from the app. - [Add job note](https://headhoncho.app/docs/api/add_job_note): Add a note to a job. It appends to the job's log and never overwrites. - [Update job note](https://headhoncho.app/docs/api/update_job_note): Fix what a note says. Only the person who wrote it may change it; the old text stays in the job's history. - [Delete job note](https://headhoncho.app/docs/api/delete_job_note): Take a note off a job. Its author or an owner may. The removal is in the job's history. - [Set job cut](https://headhoncho.app/docs/api/set_job_cut): What one technician or subcontractor on a job is paid on this job: a percent of the total, a percent of the profit, or a flat amount. - [Release job status](https://headhoncho.app/docs/api/release_job_status): Hand a status set by hand back to the automation. The job moves at once to the status its facts hold, and History says why. - [Archive job](https://headhoncho.app/docs/api/archive_job): File a finished job away, off the boards. It keeps its money and counts in every figure; Unarchive brings it back. - [Unarchive job](https://headhoncho.app/docs/api/unarchive_job): Bring an archived job back onto the boards, as it was. - [Trash job](https://headhoncho.app/docs/api/trash_job): Move a job to Trash, with why. It leaves every list and every figure, and can be restored for 30 days. - [Restore job](https://headhoncho.app/docs/api/restore_job): Bring a job back from Trash, whole: its money, its history and its technicians. - [Upload photo](https://headhoncho.app/docs/api/upload_photo): Put one photo on a job. Send the picture as base64 text; it is stored and confirmed in one call. - [Delete photo](https://headhoncho.app/docs/api/delete_photo): Remove one photo from a job, for good: its record and its file. - The same records in the app: [the Jobs panel](https://headhoncho.app/docs/jobs). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "accepted": true, "job_id": "job_1203", "number": 1203, "position": 88411, "detour": "Waiting on parts", "status": { "id": "sts_09", "name": "Scheduled" }, "automation": "" } ``` ### cURL ```bash curl -X POST "https://api.headhoncho.app/api/v1/commands/resolve-job-detour" \ -H "Authorization: Bearer hh_live_..." \ -H "Idempotency-Key: 6f1d2c9e-1b7a-4c1e-9a52-0d3f8e4b7a10" \ -H "Content-Type: application/json" \ -d '{ "job_id": "job_1138" }' ``` ### Python ```python import requests import uuid response = requests.post( "https://api.headhoncho.app/api/v1/commands/resolve-job-detour", headers={ "Authorization": "Bearer hh_live_...", "Idempotency-Key": str(uuid.uuid4()), }, json={ "job_id": "job_1138", }, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/commands/resolve-job-detour", { method: "POST", headers: { Authorization: "Bearer hh_live_...", "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "job_id": "job_1138" }), }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: resolve_job_detour Arguments: job_id (id, required) Access: do on Jobs Hints: readOnly=false, destructive=false, idempotent=true, openWorld=false Try asking: "Using HeadHoncho, resolve job detour with job_id job_1138." ``` --- # Archive job Archive job is a command in the HeadHoncho API. File a finished job away, off the boards. It keeps its money and counts in every figure; Unarchive brings it back. Page: https://headhoncho.app/docs/api/archive_job | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **Archive job**, HeadHoncho API v1. It is a command, sent to the base address `https://api.headhoncho.app`. `POST /api/v1/commands/archive-job` The key needs the **Jobs** area at **do**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). It runs the app's own command `archive-job`. Send an `Idempotency-Key` header with every call: the same key with the same body returns the first answer and runs nothing twice. See [the model](https://headhoncho.app/docs/api/model#idempotency). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `job_id` | id, in the JSON body | Yes | The job id, or its number. | `job_1138` | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back accepted, job_id, number and position. It never deletes anything. It changes only what the command names, and it writes the change to the job's history with who asked for it. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `accepted` | true or false | True when the command ran. A command that cannot run is an error instead. | | `job_id` | id (text) | The id of the job. | | `number` | whole number | The number people say out loud, such as the job number. | | `position` | whole number | Where the change landed in the event log. Pass it as `after` on a read to see your own write. | ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`read_only`](https://headhoncho.app/docs/api/errors#read_only) | 403 | This credential may read this area but not change it. | | [`not_found`](https://headhoncho.app/docs/api/errors#not_found) | 404 | No such record in the companies this credential reaches. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`missing_idempotency_key`](https://headhoncho.app/docs/api/errors#missing_idempotency_key) | 400 | Send an Idempotency-Key header on every command. | | [`idempotency_mismatch`](https://headhoncho.app/docs/api/errors#idempotency_mismatch) | 409 | This Idempotency-Key was used with a different body. | | [`idempotency_in_progress`](https://headhoncho.app/docs/api/errors#idempotency_in_progress) | 409 | A command with this Idempotency-Key is still running. Wait a moment and send it again. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [Create job](https://headhoncho.app/docs/api/create_job): Open a job or a lead in one company: the customer, the address, and optionally the job type, the time window and the technician. - [Update job](https://headhoncho.app/docs/api/update_job): Change a job's facts: the customer, the address, the schedule, the job type or the notes. Only the fields you send change. - [Change job status](https://headhoncho.app/docs/api/change_job_status): Move a job to another status by its name, slug or id. The move lands in the job's history with who asked for it. - [Assign worker](https://headhoncho.app/docs/api/assign_worker): Put a technician or subcontractor on a job. If Job follow-up is on, the automation acts on it at once, as it would from the app. - [Unassign worker](https://headhoncho.app/docs/api/unassign_worker): Take a technician or subcontractor off a job. The ticket's cancellation reaches them the way it does from the app. - [Add job note](https://headhoncho.app/docs/api/add_job_note): Add a note to a job. It appends to the job's log and never overwrites. - [Update job note](https://headhoncho.app/docs/api/update_job_note): Fix what a note says. Only the person who wrote it may change it; the old text stays in the job's history. - [Delete job note](https://headhoncho.app/docs/api/delete_job_note): Take a note off a job. Its author or an owner may. The removal is in the job's history. - [Set job cut](https://headhoncho.app/docs/api/set_job_cut): What one technician or subcontractor on a job is paid on this job: a percent of the total, a percent of the profit, or a flat amount. - [Release job status](https://headhoncho.app/docs/api/release_job_status): Hand a status set by hand back to the automation. The job moves at once to the status its facts hold, and History says why. - [Resolve job detour](https://headhoncho.app/docs/api/resolve_job_detour): Close a job's detour, such as Waiting on parts. The job goes back to the status it left, then on to where its facts put it. - [Unarchive job](https://headhoncho.app/docs/api/unarchive_job): Bring an archived job back onto the boards, as it was. - [Trash job](https://headhoncho.app/docs/api/trash_job): Move a job to Trash, with why. It leaves every list and every figure, and can be restored for 30 days. - [Restore job](https://headhoncho.app/docs/api/restore_job): Bring a job back from Trash, whole: its money, its history and its technicians. - [Upload photo](https://headhoncho.app/docs/api/upload_photo): Put one photo on a job. Send the picture as base64 text; it is stored and confirmed in one call. - [Delete photo](https://headhoncho.app/docs/api/delete_photo): Remove one photo from a job, for good: its record and its file. - The same records in the app: [the Jobs panel](https://headhoncho.app/docs/jobs). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "accepted": true, "job_id": "job_1138", "number": 1138, "position": 88411 } ``` ### cURL ```bash curl -X POST "https://api.headhoncho.app/api/v1/commands/archive-job" \ -H "Authorization: Bearer hh_live_..." \ -H "Idempotency-Key: 6f1d2c9e-1b7a-4c1e-9a52-0d3f8e4b7a10" \ -H "Content-Type: application/json" \ -d '{ "job_id": "job_1138" }' ``` ### Python ```python import requests import uuid response = requests.post( "https://api.headhoncho.app/api/v1/commands/archive-job", headers={ "Authorization": "Bearer hh_live_...", "Idempotency-Key": str(uuid.uuid4()), }, json={ "job_id": "job_1138", }, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/commands/archive-job", { method: "POST", headers: { Authorization: "Bearer hh_live_...", "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "job_id": "job_1138" }), }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: archive_job Arguments: job_id (id, required) Access: do on Jobs Hints: readOnly=false, destructive=false, idempotent=true, openWorld=false Try asking: "Using HeadHoncho, archive job with job_id job_1138." ``` --- # Unarchive job Unarchive job is a command in the HeadHoncho API. Bring an archived job back onto the boards, as it was. Page: https://headhoncho.app/docs/api/unarchive_job | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **Unarchive job**, HeadHoncho API v1. It is a command, sent to the base address `https://api.headhoncho.app`. `POST /api/v1/commands/unarchive-job` The key needs the **Jobs** area at **do**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). It runs the app's own command `unarchive-job`. Send an `Idempotency-Key` header with every call: the same key with the same body returns the first answer and runs nothing twice. See [the model](https://headhoncho.app/docs/api/model#idempotency). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `job_id` | id, in the JSON body | Yes | The job id, or its number. | `job_1138` | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back accepted, job_id, number and position. It never deletes anything. It changes only what the command names, and it writes the change to the job's history with who asked for it. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `accepted` | true or false | True when the command ran. A command that cannot run is an error instead. | | `job_id` | id (text) | The id of the job. | | `number` | whole number | The number people say out loud, such as the job number. | | `position` | whole number | Where the change landed in the event log. Pass it as `after` on a read to see your own write. | ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`read_only`](https://headhoncho.app/docs/api/errors#read_only) | 403 | This credential may read this area but not change it. | | [`not_found`](https://headhoncho.app/docs/api/errors#not_found) | 404 | No such record in the companies this credential reaches. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`missing_idempotency_key`](https://headhoncho.app/docs/api/errors#missing_idempotency_key) | 400 | Send an Idempotency-Key header on every command. | | [`idempotency_mismatch`](https://headhoncho.app/docs/api/errors#idempotency_mismatch) | 409 | This Idempotency-Key was used with a different body. | | [`idempotency_in_progress`](https://headhoncho.app/docs/api/errors#idempotency_in_progress) | 409 | A command with this Idempotency-Key is still running. Wait a moment and send it again. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [Create job](https://headhoncho.app/docs/api/create_job): Open a job or a lead in one company: the customer, the address, and optionally the job type, the time window and the technician. - [Update job](https://headhoncho.app/docs/api/update_job): Change a job's facts: the customer, the address, the schedule, the job type or the notes. Only the fields you send change. - [Change job status](https://headhoncho.app/docs/api/change_job_status): Move a job to another status by its name, slug or id. The move lands in the job's history with who asked for it. - [Assign worker](https://headhoncho.app/docs/api/assign_worker): Put a technician or subcontractor on a job. If Job follow-up is on, the automation acts on it at once, as it would from the app. - [Unassign worker](https://headhoncho.app/docs/api/unassign_worker): Take a technician or subcontractor off a job. The ticket's cancellation reaches them the way it does from the app. - [Add job note](https://headhoncho.app/docs/api/add_job_note): Add a note to a job. It appends to the job's log and never overwrites. - [Update job note](https://headhoncho.app/docs/api/update_job_note): Fix what a note says. Only the person who wrote it may change it; the old text stays in the job's history. - [Delete job note](https://headhoncho.app/docs/api/delete_job_note): Take a note off a job. Its author or an owner may. The removal is in the job's history. - [Set job cut](https://headhoncho.app/docs/api/set_job_cut): What one technician or subcontractor on a job is paid on this job: a percent of the total, a percent of the profit, or a flat amount. - [Release job status](https://headhoncho.app/docs/api/release_job_status): Hand a status set by hand back to the automation. The job moves at once to the status its facts hold, and History says why. - [Resolve job detour](https://headhoncho.app/docs/api/resolve_job_detour): Close a job's detour, such as Waiting on parts. The job goes back to the status it left, then on to where its facts put it. - [Archive job](https://headhoncho.app/docs/api/archive_job): File a finished job away, off the boards. It keeps its money and counts in every figure; Unarchive brings it back. - [Trash job](https://headhoncho.app/docs/api/trash_job): Move a job to Trash, with why. It leaves every list and every figure, and can be restored for 30 days. - [Restore job](https://headhoncho.app/docs/api/restore_job): Bring a job back from Trash, whole: its money, its history and its technicians. - [Upload photo](https://headhoncho.app/docs/api/upload_photo): Put one photo on a job. Send the picture as base64 text; it is stored and confirmed in one call. - [Delete photo](https://headhoncho.app/docs/api/delete_photo): Remove one photo from a job, for good: its record and its file. - The same records in the app: [the Jobs panel](https://headhoncho.app/docs/jobs). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "accepted": true, "job_id": "job_1138", "number": 1138, "position": 88411 } ``` ### cURL ```bash curl -X POST "https://api.headhoncho.app/api/v1/commands/unarchive-job" \ -H "Authorization: Bearer hh_live_..." \ -H "Idempotency-Key: 6f1d2c9e-1b7a-4c1e-9a52-0d3f8e4b7a10" \ -H "Content-Type: application/json" \ -d '{ "job_id": "job_1138" }' ``` ### Python ```python import requests import uuid response = requests.post( "https://api.headhoncho.app/api/v1/commands/unarchive-job", headers={ "Authorization": "Bearer hh_live_...", "Idempotency-Key": str(uuid.uuid4()), }, json={ "job_id": "job_1138", }, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/commands/unarchive-job", { method: "POST", headers: { Authorization: "Bearer hh_live_...", "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "job_id": "job_1138" }), }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: unarchive_job Arguments: job_id (id, required) Access: do on Jobs Hints: readOnly=false, destructive=false, idempotent=true, openWorld=false Try asking: "Using HeadHoncho, unarchive job with job_id job_1138." ``` --- # Trash job Trash job is a command in the HeadHoncho API. Move a job to Trash, with why. It leaves every list and every figure, and can be restored for 30 days. Page: https://headhoncho.app/docs/api/trash_job | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **Trash job**, HeadHoncho API v1. It is a command, sent to the base address `https://api.headhoncho.app`. `POST /api/v1/commands/trash-job` The key needs the **Jobs** area at **do**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). It runs the app's own command `trash-job`. Send an `Idempotency-Key` header with every call: the same key with the same body returns the first answer and runs nothing twice. See [the model](https://headhoncho.app/docs/api/model#idempotency). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `job_id` | id, in the JSON body | Yes | The job id, or its number. | `job_1203` | | `reason` | text, in the JSON body | Yes | Why, as the Trash tab will show it. | `Duplicate of #1202` | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back accepted, job_id, number and position. Erasing a job for good is done in the app only. It never deletes anything. It changes only what the command names, and it writes the change to the job's history with who asked for it. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `accepted` | true or false | True when the command ran. A command that cannot run is an error instead. | | `job_id` | id (text) | The id of the job. | | `number` | whole number | The number people say out loud, such as the job number. | | `position` | whole number | Where the change landed in the event log. Pass it as `after` on a read to see your own write. | ## Delete is Trash Nothing is erased. The job, its money and its history wait in Trash, out of every list and every figure, until someone restores it or 30 days pass. Erasing for good is in the app only. ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`read_only`](https://headhoncho.app/docs/api/errors#read_only) | 403 | This credential may read this area but not change it. | | [`not_found`](https://headhoncho.app/docs/api/errors#not_found) | 404 | No such record in the companies this credential reaches. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`missing_idempotency_key`](https://headhoncho.app/docs/api/errors#missing_idempotency_key) | 400 | Send an Idempotency-Key header on every command. | | [`idempotency_mismatch`](https://headhoncho.app/docs/api/errors#idempotency_mismatch) | 409 | This Idempotency-Key was used with a different body. | | [`idempotency_in_progress`](https://headhoncho.app/docs/api/errors#idempotency_in_progress) | 409 | A command with this Idempotency-Key is still running. Wait a moment and send it again. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [Create job](https://headhoncho.app/docs/api/create_job): Open a job or a lead in one company: the customer, the address, and optionally the job type, the time window and the technician. - [Update job](https://headhoncho.app/docs/api/update_job): Change a job's facts: the customer, the address, the schedule, the job type or the notes. Only the fields you send change. - [Change job status](https://headhoncho.app/docs/api/change_job_status): Move a job to another status by its name, slug or id. The move lands in the job's history with who asked for it. - [Assign worker](https://headhoncho.app/docs/api/assign_worker): Put a technician or subcontractor on a job. If Job follow-up is on, the automation acts on it at once, as it would from the app. - [Unassign worker](https://headhoncho.app/docs/api/unassign_worker): Take a technician or subcontractor off a job. The ticket's cancellation reaches them the way it does from the app. - [Add job note](https://headhoncho.app/docs/api/add_job_note): Add a note to a job. It appends to the job's log and never overwrites. - [Update job note](https://headhoncho.app/docs/api/update_job_note): Fix what a note says. Only the person who wrote it may change it; the old text stays in the job's history. - [Delete job note](https://headhoncho.app/docs/api/delete_job_note): Take a note off a job. Its author or an owner may. The removal is in the job's history. - [Set job cut](https://headhoncho.app/docs/api/set_job_cut): What one technician or subcontractor on a job is paid on this job: a percent of the total, a percent of the profit, or a flat amount. - [Release job status](https://headhoncho.app/docs/api/release_job_status): Hand a status set by hand back to the automation. The job moves at once to the status its facts hold, and History says why. - [Resolve job detour](https://headhoncho.app/docs/api/resolve_job_detour): Close a job's detour, such as Waiting on parts. The job goes back to the status it left, then on to where its facts put it. - [Archive job](https://headhoncho.app/docs/api/archive_job): File a finished job away, off the boards. It keeps its money and counts in every figure; Unarchive brings it back. - [Unarchive job](https://headhoncho.app/docs/api/unarchive_job): Bring an archived job back onto the boards, as it was. - [Restore job](https://headhoncho.app/docs/api/restore_job): Bring a job back from Trash, whole: its money, its history and its technicians. - [Upload photo](https://headhoncho.app/docs/api/upload_photo): Put one photo on a job. Send the picture as base64 text; it is stored and confirmed in one call. - [Delete photo](https://headhoncho.app/docs/api/delete_photo): Remove one photo from a job, for good: its record and its file. - The same records in the app: [the Jobs panel](https://headhoncho.app/docs/jobs). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "accepted": true, "job_id": "job_1203", "number": 1203, "position": 88411 } ``` ### cURL ```bash curl -X POST "https://api.headhoncho.app/api/v1/commands/trash-job" \ -H "Authorization: Bearer hh_live_..." \ -H "Idempotency-Key: 6f1d2c9e-1b7a-4c1e-9a52-0d3f8e4b7a10" \ -H "Content-Type: application/json" \ -d '{ "job_id": "job_1203", "reason": "Duplicate of #1202" }' ``` ### Python ```python import requests import uuid response = requests.post( "https://api.headhoncho.app/api/v1/commands/trash-job", headers={ "Authorization": "Bearer hh_live_...", "Idempotency-Key": str(uuid.uuid4()), }, json={ "job_id": "job_1203", "reason": "Duplicate of #1202", }, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/commands/trash-job", { method: "POST", headers: { Authorization: "Bearer hh_live_...", "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "job_id": "job_1203", "reason": "Duplicate of #1202" }), }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: trash_job Arguments: job_id (id, required), reason (text, required) Access: do on Jobs Hints: readOnly=false, destructive=true, idempotent=true, openWorld=false Try asking: "Using HeadHoncho, trash job with job_id job_1203 and reason Duplicate of #1202." ``` --- # Restore job Restore job is a command in the HeadHoncho API. Bring a job back from Trash, whole: its money, its history and its technicians. Page: https://headhoncho.app/docs/api/restore_job | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **Restore job**, HeadHoncho API v1. It is a command, sent to the base address `https://api.headhoncho.app`. `POST /api/v1/commands/restore-job` The key needs the **Jobs** area at **do**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). It runs the app's own command `restore-job`. Send an `Idempotency-Key` header with every call: the same key with the same body returns the first answer and runs nothing twice. See [the model](https://headhoncho.app/docs/api/model#idempotency). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `job_id` | id, in the JSON body | Yes | The job id, or its number. List jobs with bin=trash finds it. | `job_1203` | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back accepted, job_id, number and position. It never deletes anything. It changes only what the command names, and it writes the change to the job's history with who asked for it. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `accepted` | true or false | True when the command ran. A command that cannot run is an error instead. | | `job_id` | id (text) | The id of the job. | | `number` | whole number | The number people say out loud, such as the job number. | | `position` | whole number | Where the change landed in the event log. Pass it as `after` on a read to see your own write. | ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`read_only`](https://headhoncho.app/docs/api/errors#read_only) | 403 | This credential may read this area but not change it. | | [`not_found`](https://headhoncho.app/docs/api/errors#not_found) | 404 | No such record in the companies this credential reaches. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`missing_idempotency_key`](https://headhoncho.app/docs/api/errors#missing_idempotency_key) | 400 | Send an Idempotency-Key header on every command. | | [`idempotency_mismatch`](https://headhoncho.app/docs/api/errors#idempotency_mismatch) | 409 | This Idempotency-Key was used with a different body. | | [`idempotency_in_progress`](https://headhoncho.app/docs/api/errors#idempotency_in_progress) | 409 | A command with this Idempotency-Key is still running. Wait a moment and send it again. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [Create job](https://headhoncho.app/docs/api/create_job): Open a job or a lead in one company: the customer, the address, and optionally the job type, the time window and the technician. - [Update job](https://headhoncho.app/docs/api/update_job): Change a job's facts: the customer, the address, the schedule, the job type or the notes. Only the fields you send change. - [Change job status](https://headhoncho.app/docs/api/change_job_status): Move a job to another status by its name, slug or id. The move lands in the job's history with who asked for it. - [Assign worker](https://headhoncho.app/docs/api/assign_worker): Put a technician or subcontractor on a job. If Job follow-up is on, the automation acts on it at once, as it would from the app. - [Unassign worker](https://headhoncho.app/docs/api/unassign_worker): Take a technician or subcontractor off a job. The ticket's cancellation reaches them the way it does from the app. - [Add job note](https://headhoncho.app/docs/api/add_job_note): Add a note to a job. It appends to the job's log and never overwrites. - [Update job note](https://headhoncho.app/docs/api/update_job_note): Fix what a note says. Only the person who wrote it may change it; the old text stays in the job's history. - [Delete job note](https://headhoncho.app/docs/api/delete_job_note): Take a note off a job. Its author or an owner may. The removal is in the job's history. - [Set job cut](https://headhoncho.app/docs/api/set_job_cut): What one technician or subcontractor on a job is paid on this job: a percent of the total, a percent of the profit, or a flat amount. - [Release job status](https://headhoncho.app/docs/api/release_job_status): Hand a status set by hand back to the automation. The job moves at once to the status its facts hold, and History says why. - [Resolve job detour](https://headhoncho.app/docs/api/resolve_job_detour): Close a job's detour, such as Waiting on parts. The job goes back to the status it left, then on to where its facts put it. - [Archive job](https://headhoncho.app/docs/api/archive_job): File a finished job away, off the boards. It keeps its money and counts in every figure; Unarchive brings it back. - [Unarchive job](https://headhoncho.app/docs/api/unarchive_job): Bring an archived job back onto the boards, as it was. - [Trash job](https://headhoncho.app/docs/api/trash_job): Move a job to Trash, with why. It leaves every list and every figure, and can be restored for 30 days. - [Upload photo](https://headhoncho.app/docs/api/upload_photo): Put one photo on a job. Send the picture as base64 text; it is stored and confirmed in one call. - [Delete photo](https://headhoncho.app/docs/api/delete_photo): Remove one photo from a job, for good: its record and its file. - The same records in the app: [the Jobs panel](https://headhoncho.app/docs/jobs). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "accepted": true, "job_id": "job_1203", "number": 1203, "position": 88411 } ``` ### cURL ```bash curl -X POST "https://api.headhoncho.app/api/v1/commands/restore-job" \ -H "Authorization: Bearer hh_live_..." \ -H "Idempotency-Key: 6f1d2c9e-1b7a-4c1e-9a52-0d3f8e4b7a10" \ -H "Content-Type: application/json" \ -d '{ "job_id": "job_1203" }' ``` ### Python ```python import requests import uuid response = requests.post( "https://api.headhoncho.app/api/v1/commands/restore-job", headers={ "Authorization": "Bearer hh_live_...", "Idempotency-Key": str(uuid.uuid4()), }, json={ "job_id": "job_1203", }, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/commands/restore-job", { method: "POST", headers: { Authorization: "Bearer hh_live_...", "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "job_id": "job_1203" }), }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: restore_job Arguments: job_id (id, required) Access: do on Jobs Hints: readOnly=false, destructive=false, idempotent=true, openWorld=false Try asking: "Using HeadHoncho, restore job with job_id job_1203." ``` --- # Get job money Get job money is a read in the HeadHoncho API. What a job made and where the money went: money in, parts and fees, the profit, each person's share, and every payment and expense line. Page: https://headhoncho.app/docs/api/get_job_money | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **Get job money**, HeadHoncho API v1. It is a read, sent to the base address `https://api.headhoncho.app`. `GET /api/v1/jobs/{job_id}/money` The key needs the **Money** area at **read**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). Send your key as `Authorization: Bearer hh_live_...`. See [API keys](https://headhoncho.app/docs/api/keys). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `job_id` | id, in the path | Yes | The job id, or its number. | `job_1138` | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back summary: quoted, collected, still_owed, money_in (and whether it is the quote or what came in), parts, fees, profit and the company's share. shares: one per person paid on the job, with the rate, the working and whether it is projected or posted, then the company. lines: every payment, expense, fee and cut, voided ones included and marked. checks: whether the shares and fees add back to money in, to the cent. It never changes a record. It only reads the companies the key reaches. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `job` | object | The job. | | `job.id` | id (text) | The id of this record. Ids are opaque text: keep them exactly as given. | | `job.number` | whole number | The number people say out loud, such as the job number. | | `job.status` | text | The job status. | | `currency` | text | The three-letter currency code (ISO 4217). Every money value in the answer is in it. | | `summary` | object | The summary. | | `summary.quoted` | money (number) | The price quoted for the job. In the company's currency. | | `summary.collected` | money (number) | The money received on the job so far. In the company's currency. | | `summary.still_owed` | money (number) | The still owed. In the company's currency. | | `summary.money_in` | money (number) | The money in. In the company's currency. | | `summary.money_in_basis` | text | Which money counted as money in. | | `summary.parts` | money (number) | The parts. In the company's currency. | | `summary.fees` | money (number) | What the payment processor kept. In the company's currency. | | `summary.profit` | money (number) | The job's profit, worked out the way the app works it out. In the company's currency. | | `summary.company_share` | money (number) | The company share. In the company's currency. | | `summary.technicians_total` | money (number) | The technicians total. In the company's currency. | | `shares` | list of objects | The shares. | | `shares[].worker_id` | id (text) | The id of the worker. | | `shares[].name` | text | The name, as the app shows it. | | `shares[].role` | text | The role: what this person does on a job. | | `shares[].rate` | text | How the cut is worked out, in words. | | `shares[].working` | text | The sum, shown the way the app shows it. | | `shares[].share` | money (number) | The share. In the company's currency. | | `shares[].parts_paid` | money (number) | The parts paid. In the company's currency. | | `shares[].payout` | money (number) | The payout. In the company's currency. | | `shares[].projected` | true or false | True while the figure is an estimate that the job has not closed on yet. | | `lines` | list of objects | The lines, oldest first. | | `lines[].id` | id (text) | The id of this record. Ids are opaque text: keep them exactly as given. | | `lines[].kind` | text | What sort of thing this is. | | `lines[].on` | date (YYYY-MM-DD) | The date it happened, as a date in the company's time zone. | | `lines[].amount` | money (number) | The amount. In the company's currency. | | `lines[].method` | text | How it was paid, such as card or cash. | | `lines[].who` | text | The person it concerns. | | `lines[].memo` | text | A free-text note on the line. Empty when there is none. | | `lines[].voided` | true or false | True when the line was voided. A voided line counts in no figure. | | `lines[].type` | text | What sort of thing this is. | | `checks` | object | The checks. | | `checks.adds_up` | true or false | True when the figures agree with each other. | | `checks.payouts` | money (number) | The payouts. In the company's currency. | | `checks.fees` | money (number) | What the payment processor kept. In the company's currency. | | `checks.money_in` | money (number) | The money in. In the company's currency. | ## One derivation This is the arithmetic the job's Money tab shows, computed by the same function, so the API and the screen cannot disagree. A share is projected until the job closes and the cut is posted. ## Voided lines A voided payment or expense is listed with voided: true and its reason, and counts in no figure. ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`not_found`](https://headhoncho.app/docs/api/errors#not_found) | 404 | No such record in the companies this credential reaches. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [List field reports](https://headhoncho.app/docs/api/list_field_reports): What technicians reported from the field and nobody booked yet: what they collected, how, the parts and the job's total, newest first. - The same records in the app: [the Finance panel](https://headhoncho.app/docs/finance). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "job": { "id": "job_1138", "number": 1138, "status": "Closed" }, "currency": "USD", "summary": { "quoted": 1450.0, "collected": 1450.0, "still_owed": 0.0, "money_in": 1450.0, "money_in_basis": "collected", "parts": 180.0, "fees": 42.35, "profit": 1227.65, "company_share": 613.83, "technicians_total": 793.82 }, "shares": [ { "worker_id": "wrk_7a12", "name": "Omar S.", "role": "subcontractor", "rate": "50% of job profit", "working": "$1,227.65 × 50%", "share": 613.82, "parts_paid": 180.0, "payout": 793.82, "projected": false }, { "worker_id": null, "name": "The company", "role": "company", "rate": "the rest · ≈50%", "working": "$1,227.65 − the other shares", "share": 613.83, "parts_paid": 0.0, "payout": 613.83, "projected": false } ], "lines": [ { "id": "pay_91c0", "kind": "payment", "on": "2026-10-16", "amount": 1450.0, "method": "card", "who": "Omar S.", "memo": "", "voided": false }, { "id": "fee_91c0", "kind": "fee", "on": "2026-10-16", "amount": 42.35, "method": "card", "who": "", "memo": "Processing fee", "voided": false }, { "id": "exp_2b11", "kind": "expense", "on": "2026-10-16", "amount": 180.0, "type": "Parts", "who": "Omar S.", "memo": "Dolly rental", "voided": false }, { "id": "led_4d0e", "kind": "cut", "on": "2026-10-16", "amount": 613.82, "who": "Omar S.", "memo": "", "voided": false } ], "checks": { "adds_up": true, "payouts": 1407.65, "fees": 42.35, "money_in": 1450.0 } } ``` ### cURL ```bash curl "https://api.headhoncho.app/api/v1/jobs/job_1138/money" \ -H "Authorization: Bearer hh_live_..." ``` ### Python ```python import requests response = requests.get( "https://api.headhoncho.app/api/v1/jobs/job_1138/money", headers={"Authorization": "Bearer hh_live_..."}, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/jobs/job_1138/money", { headers: { Authorization: "Bearer hh_live_..." }, }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: get_job_money Arguments: job_id (id, required) Access: read on Money Hints: readOnly=true, destructive=false, idempotent=true, openWorld=false Try asking: "Using HeadHoncho, get job money with job_id job_1138." ``` --- # List field reports List field reports is a read in the HeadHoncho API. What technicians reported from the field and nobody booked yet: what they collected, how, the parts and the job's total, newest first. Page: https://headhoncho.app/docs/api/list_field_reports | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **List field reports**, HeadHoncho API v1. It is a read, sent to the base address `https://api.headhoncho.app`. `GET /api/v1/field-reports` The key needs the **Money** area at **read**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). Send your key as `Authorization: Bearer hh_live_...`. See [API keys](https://headhoncho.app/docs/api/keys). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `job_id` | id, in the query | No | Only this job, by id or number. | `job_1138` | | `company_id` | id, in the query | No | Only this company. Default: every company in reach. | `cmp_14f5` | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back field_reports: id, job (id, number, status), worker_id, worker_name, collected, method, parts, total and reported_at. Booked and set-aside ones are not listed. It never changes a record. It only reads the companies the key reaches. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `field_reports` | list of objects | The field reports. | | `field_reports[].id` | id (text) | The id of this record. Ids are opaque text: keep them exactly as given. | | `field_reports[].job` | object | The job. | | `field_reports[].job.id` | id (text) | The id of this record. Ids are opaque text: keep them exactly as given. | | `field_reports[].job.number` | whole number | The number people say out loud, such as the job number. | | `field_reports[].job.status` | text | The job status. | | `field_reports[].worker_id` | id (text) | The id of the worker. | | `field_reports[].worker_name` | text | The worker name. | | `field_reports[].collected` | money (number) | The money received on the job so far. In the company's currency. | | `field_reports[].method` | text | How it was paid, such as card or cash. | | `field_reports[].parts` | money (number) | The parts. In the company's currency. | | `field_reports[].total` | money (number) | The total, in the company's currency. | | `field_reports[].reported_at` | time (ISO 8601, with offset) | When it was reported. Carries its offset from UTC; `Z` is UTC. | ## Where they come from A technician texts the numbers when the job is done. The app reads them into a field report; Book it or Not this decides it, here or on Finance. ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`not_found`](https://headhoncho.app/docs/api/errors#not_found) | 404 | No such record in the companies this credential reaches. | | [`out_of_scope`](https://headhoncho.app/docs/api/errors#out_of_scope) | 404 | No such company in the companies this credential reaches. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [Get job money](https://headhoncho.app/docs/api/get_job_money): What a job made and where the money went: money in, parts and fees, the profit, each person's share, and every payment and expense line. - The same records in the app: [the Finance panel](https://headhoncho.app/docs/finance). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "field_reports": [ { "id": "frp_77a1", "job": { "id": "job_1138", "number": 1138, "status": "Done" }, "worker_id": "wrk_7a12", "worker_name": "Omar S.", "collected": 1450.0, "method": "cash", "parts": 180.0, "total": 1450.0, "reported_at": "2026-10-16T19:02:11Z" } ] } ``` ### cURL ```bash curl "https://api.headhoncho.app/api/v1/field-reports?job_id=job_1138&company_id=cmp_14f5" \ -H "Authorization: Bearer hh_live_..." ``` ### Python ```python import requests response = requests.get( "https://api.headhoncho.app/api/v1/field-reports", headers={"Authorization": "Bearer hh_live_..."}, params={ "job_id": "job_1138", "company_id": "cmp_14f5", }, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/field-reports?job_id=job_1138&company_id=cmp_14f5", { headers: { Authorization: "Bearer hh_live_..." }, }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: list_field_reports Arguments: job_id (id, optional), company_id (id, optional) Access: read on Money Hints: readOnly=true, destructive=false, idempotent=true, openWorld=false Try asking: "Using HeadHoncho, list field reports with job_id job_1138." ``` --- # Record payment Record payment is a command in the HeadHoncho API. Record money the customer paid on a job. A payment that covers the price closes the job, as it does in the app. Page: https://headhoncho.app/docs/api/record_payment | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **Record payment**, HeadHoncho API v1. It is a command, sent to the base address `https://api.headhoncho.app`. `POST /api/v1/commands/record-payment` The key needs the **Money** area at **do**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). It runs the app's own command `record-payment`. Send an `Idempotency-Key` header with every call: the same key with the same body returns the first answer and runs nothing twice. See [the model](https://headhoncho.app/docs/api/model#idempotency). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `job_id` | id, in the JSON body | Yes | The job id, or its number. | `job_1138` | | `amount` | money, in the JSON body | Yes | What was paid, a number. | `1450` | | `method` | text, in the JSON body | Yes | cash, card, zelle, check or other. One of `cash`, `card`, `zelle`, `check`, `other`. | `card` | | `received_at` | datetime, in the JSON body | No | When. Default: now. | `2026-10-16T11:40:00-05:00` | | `collected_by_id` | id, in the JSON body | No | The technician who took the money, if one did. | `wrk_7a12` | | `processing_fee` | money, in the JSON body | No | What the card processor kept, if anything. | `42.35` | | `processor_reference` | text, in the JSON body | No | The processor's id for the charge. | `ch_3P1x...` | | `memo` | text, in the JSON body | No | Anything to remember. | `Paid at the door` | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back accepted, job_id, number, payment_id, amount, position, and closed: whether the payment closed the job. close_gaps names what kept it open, when something did. It never deletes anything. It changes only what the command names, and it writes the change to the job's history with who asked for it. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `accepted` | true or false | True when the command ran. A command that cannot run is an error instead. | | `job_id` | id (text) | The id of the job. | | `number` | whole number | The number people say out loud, such as the job number. | | `position` | whole number | Where the change landed in the event log. Pass it as `after` on a read to see your own write. | | `payment_id` | id (text) | The id of the payment. | | `amount` | money (decimal as text) | The amount. In the company's currency. | | `closed` | true or false | True when the job is closed. | ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`read_only`](https://headhoncho.app/docs/api/errors#read_only) | 403 | This credential may read this area but not change it. | | [`not_found`](https://headhoncho.app/docs/api/errors#not_found) | 404 | No such record in the companies this credential reaches. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`missing_idempotency_key`](https://headhoncho.app/docs/api/errors#missing_idempotency_key) | 400 | Send an Idempotency-Key header on every command. | | [`idempotency_mismatch`](https://headhoncho.app/docs/api/errors#idempotency_mismatch) | 409 | This Idempotency-Key was used with a different body. | | [`idempotency_in_progress`](https://headhoncho.app/docs/api/errors#idempotency_in_progress) | 409 | A command with this Idempotency-Key is still running. Wait a moment and send it again. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [Void payment](https://headhoncho.app/docs/api/void_payment): Stop a payment entered wrong from counting. It stays on the job's money, marked voided, with why. - [Record expense](https://headhoncho.app/docs/api/record_expense): Record a cost on a job: parts, a rental, fuel. Paid by a technician, it is paid back to them on top of their share. - [Void expense](https://headhoncho.app/docs/api/void_expense): Stop an expense entered wrong from counting. It stays on the job's money, marked voided, with why. - [Book field report](https://headhoncho.app/docs/api/book_field_report): Book what a technician reported: the payment, the parts and the job's price, as sent or as you correct them. The job closes when nothing is missing. - [Dismiss field report](https://headhoncho.app/docs/api/dismiss_field_report): Not this: book nothing from a technician's report. What they said is kept on the job. - [Add expense type](https://headhoncho.app/docs/api/add_expense_type): Add a kind of cost the company records, such as Parts or Truck rental. A name already in use is refused, so sending it twice adds one. - [Update expense type](https://headhoncho.app/docs/api/update_expense_type): Rename an expense type, or retire it so new expenses cannot pick it. Old expenses keep it either way. - The same records in the app: [the Finance panel](https://headhoncho.app/docs/finance). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "accepted": true, "job_id": "job_1138", "number": 1138, "position": 88502, "payment_id": "pay_91c0", "amount": "1450.00", "closed": true } ``` ### cURL ```bash curl -X POST "https://api.headhoncho.app/api/v1/commands/record-payment" \ -H "Authorization: Bearer hh_live_..." \ -H "Idempotency-Key: 6f1d2c9e-1b7a-4c1e-9a52-0d3f8e4b7a10" \ -H "Content-Type: application/json" \ -d '{ "job_id": "job_1138", "amount": 1450, "method": "card", "received_at": "2026-10-16T11:40:00-05:00", "collected_by_id": "wrk_7a12", "processing_fee": 42.35, "processor_reference": "ch_3P1x...", "memo": "Paid at the door" }' ``` ### Python ```python import requests import uuid response = requests.post( "https://api.headhoncho.app/api/v1/commands/record-payment", headers={ "Authorization": "Bearer hh_live_...", "Idempotency-Key": str(uuid.uuid4()), }, json={ "job_id": "job_1138", "amount": 1450, "method": "card", "received_at": "2026-10-16T11:40:00-05:00", "collected_by_id": "wrk_7a12", "processing_fee": 42.35, "processor_reference": "ch_3P1x...", "memo": "Paid at the door", }, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/commands/record-payment", { method: "POST", headers: { Authorization: "Bearer hh_live_...", "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "job_id": "job_1138", "amount": 1450, "method": "card", "received_at": "2026-10-16T11:40:00-05:00", "collected_by_id": "wrk_7a12", "processing_fee": 42.35, "processor_reference": "ch_3P1x...", "memo": "Paid at the door" }), }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: record_payment Arguments: job_id (id, required), amount (money, required), method (text, required), received_at (datetime, optional), collected_by_id (id, optional), processing_fee (money, optional), processor_reference (text, optional), memo (text, optional) Access: do on Money Hints: readOnly=false, destructive=false, idempotent=false, openWorld=false Try asking: "Using HeadHoncho, record payment with job_id job_1138 and amount 1450 and method card and received_at 2026-10-16T11:40:00-05:00." ``` --- # Void payment Void payment is a command in the HeadHoncho API. Stop a payment entered wrong from counting. It stays on the job's money, marked voided, with why. Page: https://headhoncho.app/docs/api/void_payment | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **Void payment**, HeadHoncho API v1. It is a command, sent to the base address `https://api.headhoncho.app`. `POST /api/v1/commands/void-payment` The key needs the **Money** area at **do**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). It runs the app's own command `void-payment`. Send an `Idempotency-Key` header with every call: the same key with the same body returns the first answer and runs nothing twice. See [the model](https://headhoncho.app/docs/api/model#idempotency). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `payment_id` | id, in the JSON body | Yes | From Record a payment, or a line of A job's money. | `pay_91c0` | | `reason` | text, in the JSON body | Yes | Why it was wrong. | `Entered twice` | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back accepted, job_id, number, payment_id and position. It never deletes anything. It changes only what the command names, and it writes the change to the job's history with who asked for it. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `accepted` | true or false | True when the command ran. A command that cannot run is an error instead. | | `job_id` | id (text) | The id of the job. | | `number` | whole number | The number people say out loud, such as the job number. | | `position` | whole number | Where the change landed in the event log. Pass it as `after` on a read to see your own write. | | `payment_id` | id (text) | The id of the payment. | ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`read_only`](https://headhoncho.app/docs/api/errors#read_only) | 403 | This credential may read this area but not change it. | | [`not_found`](https://headhoncho.app/docs/api/errors#not_found) | 404 | No such record in the companies this credential reaches. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`missing_idempotency_key`](https://headhoncho.app/docs/api/errors#missing_idempotency_key) | 400 | Send an Idempotency-Key header on every command. | | [`idempotency_mismatch`](https://headhoncho.app/docs/api/errors#idempotency_mismatch) | 409 | This Idempotency-Key was used with a different body. | | [`idempotency_in_progress`](https://headhoncho.app/docs/api/errors#idempotency_in_progress) | 409 | A command with this Idempotency-Key is still running. Wait a moment and send it again. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [Record payment](https://headhoncho.app/docs/api/record_payment): Record money the customer paid on a job. A payment that covers the price closes the job, as it does in the app. - [Record expense](https://headhoncho.app/docs/api/record_expense): Record a cost on a job: parts, a rental, fuel. Paid by a technician, it is paid back to them on top of their share. - [Void expense](https://headhoncho.app/docs/api/void_expense): Stop an expense entered wrong from counting. It stays on the job's money, marked voided, with why. - [Book field report](https://headhoncho.app/docs/api/book_field_report): Book what a technician reported: the payment, the parts and the job's price, as sent or as you correct them. The job closes when nothing is missing. - [Dismiss field report](https://headhoncho.app/docs/api/dismiss_field_report): Not this: book nothing from a technician's report. What they said is kept on the job. - [Add expense type](https://headhoncho.app/docs/api/add_expense_type): Add a kind of cost the company records, such as Parts or Truck rental. A name already in use is refused, so sending it twice adds one. - [Update expense type](https://headhoncho.app/docs/api/update_expense_type): Rename an expense type, or retire it so new expenses cannot pick it. Old expenses keep it either way. - The same records in the app: [the Finance panel](https://headhoncho.app/docs/finance). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "accepted": true, "job_id": "job_1138", "number": 1138, "position": 88502, "payment_id": "pay_91c0" } ``` ### cURL ```bash curl -X POST "https://api.headhoncho.app/api/v1/commands/void-payment" \ -H "Authorization: Bearer hh_live_..." \ -H "Idempotency-Key: 6f1d2c9e-1b7a-4c1e-9a52-0d3f8e4b7a10" \ -H "Content-Type: application/json" \ -d '{ "payment_id": "pay_91c0", "reason": "Entered twice" }' ``` ### Python ```python import requests import uuid response = requests.post( "https://api.headhoncho.app/api/v1/commands/void-payment", headers={ "Authorization": "Bearer hh_live_...", "Idempotency-Key": str(uuid.uuid4()), }, json={ "payment_id": "pay_91c0", "reason": "Entered twice", }, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/commands/void-payment", { method: "POST", headers: { Authorization: "Bearer hh_live_...", "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "payment_id": "pay_91c0", "reason": "Entered twice" }), }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: void_payment Arguments: payment_id (id, required), reason (text, required) Access: do on Money Hints: readOnly=false, destructive=true, idempotent=true, openWorld=false Try asking: "Using HeadHoncho, void payment with payment_id pay_91c0 and reason Entered twice." ``` --- # Record expense Record expense is a command in the HeadHoncho API. Record a cost on a job: parts, a rental, fuel. Paid by a technician, it is paid back to them on top of their share. Page: https://headhoncho.app/docs/api/record_expense | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **Record expense**, HeadHoncho API v1. It is a command, sent to the base address `https://api.headhoncho.app`. `POST /api/v1/commands/record-expense` The key needs the **Money** area at **do**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). It runs the app's own command `record-expense`. Send an `Idempotency-Key` header with every call: the same key with the same body returns the first answer and runs nothing twice. See [the model](https://headhoncho.app/docs/api/model#idempotency). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `job_id` | id, in the JSON body | Yes | The job id, or its number. | `job_1138` | | `expense_type_id` | id, in the JSON body | Yes | From Who am I's expense_types. | `ext_01` | | `amount` | money, in the JSON body | Yes | What it cost, a number. | `180` | | `paid_by_worker_id` | id, in the JSON body | No | The technician who paid it. Empty: the company paid. | `wrk_7a12` | | `incurred_on` | date, in the JSON body | No | The day. Default: today in the company's time zone. | `2026-10-16` | | `vendor` | text, in the JSON body | No | Who it was bought from. | `U-Haul` | | `reference` | text, in the JSON body | No | A receipt or invoice number. | `R-55102` | | `memo` | text, in the JSON body | No | Anything to remember. | `Dolly rental` | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back accepted, job_id, number, expense_id, amount and position. It never deletes anything. It changes only what the command names, and it writes the change to the job's history with who asked for it. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `accepted` | true or false | True when the command ran. A command that cannot run is an error instead. | | `job_id` | id (text) | The id of the job. | | `number` | whole number | The number people say out loud, such as the job number. | | `position` | whole number | Where the change landed in the event log. Pass it as `after` on a read to see your own write. | | `expense_id` | id (text) | The id of the expense. | | `amount` | money (decimal as text) | The amount. In the company's currency. | ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`read_only`](https://headhoncho.app/docs/api/errors#read_only) | 403 | This credential may read this area but not change it. | | [`not_found`](https://headhoncho.app/docs/api/errors#not_found) | 404 | No such record in the companies this credential reaches. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`missing_idempotency_key`](https://headhoncho.app/docs/api/errors#missing_idempotency_key) | 400 | Send an Idempotency-Key header on every command. | | [`idempotency_mismatch`](https://headhoncho.app/docs/api/errors#idempotency_mismatch) | 409 | This Idempotency-Key was used with a different body. | | [`idempotency_in_progress`](https://headhoncho.app/docs/api/errors#idempotency_in_progress) | 409 | A command with this Idempotency-Key is still running. Wait a moment and send it again. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [Record payment](https://headhoncho.app/docs/api/record_payment): Record money the customer paid on a job. A payment that covers the price closes the job, as it does in the app. - [Void payment](https://headhoncho.app/docs/api/void_payment): Stop a payment entered wrong from counting. It stays on the job's money, marked voided, with why. - [Void expense](https://headhoncho.app/docs/api/void_expense): Stop an expense entered wrong from counting. It stays on the job's money, marked voided, with why. - [Book field report](https://headhoncho.app/docs/api/book_field_report): Book what a technician reported: the payment, the parts and the job's price, as sent or as you correct them. The job closes when nothing is missing. - [Dismiss field report](https://headhoncho.app/docs/api/dismiss_field_report): Not this: book nothing from a technician's report. What they said is kept on the job. - [Add expense type](https://headhoncho.app/docs/api/add_expense_type): Add a kind of cost the company records, such as Parts or Truck rental. A name already in use is refused, so sending it twice adds one. - [Update expense type](https://headhoncho.app/docs/api/update_expense_type): Rename an expense type, or retire it so new expenses cannot pick it. Old expenses keep it either way. - The same records in the app: [the Finance panel](https://headhoncho.app/docs/finance). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "accepted": true, "job_id": "job_1138", "number": 1138, "position": 88502, "expense_id": "exp_2b11", "amount": "180.00" } ``` ### cURL ```bash curl -X POST "https://api.headhoncho.app/api/v1/commands/record-expense" \ -H "Authorization: Bearer hh_live_..." \ -H "Idempotency-Key: 6f1d2c9e-1b7a-4c1e-9a52-0d3f8e4b7a10" \ -H "Content-Type: application/json" \ -d '{ "job_id": "job_1138", "expense_type_id": "ext_01", "amount": 180, "paid_by_worker_id": "wrk_7a12", "incurred_on": "2026-10-16", "vendor": "U-Haul", "reference": "R-55102", "memo": "Dolly rental" }' ``` ### Python ```python import requests import uuid response = requests.post( "https://api.headhoncho.app/api/v1/commands/record-expense", headers={ "Authorization": "Bearer hh_live_...", "Idempotency-Key": str(uuid.uuid4()), }, json={ "job_id": "job_1138", "expense_type_id": "ext_01", "amount": 180, "paid_by_worker_id": "wrk_7a12", "incurred_on": "2026-10-16", "vendor": "U-Haul", "reference": "R-55102", "memo": "Dolly rental", }, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/commands/record-expense", { method: "POST", headers: { Authorization: "Bearer hh_live_...", "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "job_id": "job_1138", "expense_type_id": "ext_01", "amount": 180, "paid_by_worker_id": "wrk_7a12", "incurred_on": "2026-10-16", "vendor": "U-Haul", "reference": "R-55102", "memo": "Dolly rental" }), }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: record_expense Arguments: job_id (id, required), expense_type_id (id, required), amount (money, required), paid_by_worker_id (id, optional), incurred_on (date, optional), vendor (text, optional), reference (text, optional), memo (text, optional) Access: do on Money Hints: readOnly=false, destructive=false, idempotent=false, openWorld=false Try asking: "Using HeadHoncho, record expense with job_id job_1138 and expense_type_id ext_01 and amount 180 and paid_by_worker_id wrk_7a12." ``` --- # Void expense Void expense is a command in the HeadHoncho API. Stop an expense entered wrong from counting. It stays on the job's money, marked voided, with why. Page: https://headhoncho.app/docs/api/void_expense | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **Void expense**, HeadHoncho API v1. It is a command, sent to the base address `https://api.headhoncho.app`. `POST /api/v1/commands/void-expense` The key needs the **Money** area at **do**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). It runs the app's own command `void-expense`. Send an `Idempotency-Key` header with every call: the same key with the same body returns the first answer and runs nothing twice. See [the model](https://headhoncho.app/docs/api/model#idempotency). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `expense_id` | id, in the JSON body | Yes | From Record an expense, or a line of A job's money. | `exp_2b11` | | `reason` | text, in the JSON body | Yes | Why it was wrong. | `Wrong job` | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back accepted, job_id, number, expense_id and position. It never deletes anything. It changes only what the command names, and it writes the change to the job's history with who asked for it. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `accepted` | true or false | True when the command ran. A command that cannot run is an error instead. | | `job_id` | id (text) | The id of the job. | | `number` | whole number | The number people say out loud, such as the job number. | | `position` | whole number | Where the change landed in the event log. Pass it as `after` on a read to see your own write. | | `expense_id` | id (text) | The id of the expense. | ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`read_only`](https://headhoncho.app/docs/api/errors#read_only) | 403 | This credential may read this area but not change it. | | [`not_found`](https://headhoncho.app/docs/api/errors#not_found) | 404 | No such record in the companies this credential reaches. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`missing_idempotency_key`](https://headhoncho.app/docs/api/errors#missing_idempotency_key) | 400 | Send an Idempotency-Key header on every command. | | [`idempotency_mismatch`](https://headhoncho.app/docs/api/errors#idempotency_mismatch) | 409 | This Idempotency-Key was used with a different body. | | [`idempotency_in_progress`](https://headhoncho.app/docs/api/errors#idempotency_in_progress) | 409 | A command with this Idempotency-Key is still running. Wait a moment and send it again. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [Record payment](https://headhoncho.app/docs/api/record_payment): Record money the customer paid on a job. A payment that covers the price closes the job, as it does in the app. - [Void payment](https://headhoncho.app/docs/api/void_payment): Stop a payment entered wrong from counting. It stays on the job's money, marked voided, with why. - [Record expense](https://headhoncho.app/docs/api/record_expense): Record a cost on a job: parts, a rental, fuel. Paid by a technician, it is paid back to them on top of their share. - [Book field report](https://headhoncho.app/docs/api/book_field_report): Book what a technician reported: the payment, the parts and the job's price, as sent or as you correct them. The job closes when nothing is missing. - [Dismiss field report](https://headhoncho.app/docs/api/dismiss_field_report): Not this: book nothing from a technician's report. What they said is kept on the job. - [Add expense type](https://headhoncho.app/docs/api/add_expense_type): Add a kind of cost the company records, such as Parts or Truck rental. A name already in use is refused, so sending it twice adds one. - [Update expense type](https://headhoncho.app/docs/api/update_expense_type): Rename an expense type, or retire it so new expenses cannot pick it. Old expenses keep it either way. - The same records in the app: [the Finance panel](https://headhoncho.app/docs/finance). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "accepted": true, "job_id": "job_1138", "number": 1138, "position": 88502, "expense_id": "exp_2b11" } ``` ### cURL ```bash curl -X POST "https://api.headhoncho.app/api/v1/commands/void-expense" \ -H "Authorization: Bearer hh_live_..." \ -H "Idempotency-Key: 6f1d2c9e-1b7a-4c1e-9a52-0d3f8e4b7a10" \ -H "Content-Type: application/json" \ -d '{ "expense_id": "exp_2b11", "reason": "Wrong job" }' ``` ### Python ```python import requests import uuid response = requests.post( "https://api.headhoncho.app/api/v1/commands/void-expense", headers={ "Authorization": "Bearer hh_live_...", "Idempotency-Key": str(uuid.uuid4()), }, json={ "expense_id": "exp_2b11", "reason": "Wrong job", }, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/commands/void-expense", { method: "POST", headers: { Authorization: "Bearer hh_live_...", "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "expense_id": "exp_2b11", "reason": "Wrong job" }), }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: void_expense Arguments: expense_id (id, required), reason (text, required) Access: do on Money Hints: readOnly=false, destructive=true, idempotent=true, openWorld=false Try asking: "Using HeadHoncho, void expense with expense_id exp_2b11 and reason Wrong job." ``` --- # Book field report Book field report is a command in the HeadHoncho API. Book what a technician reported: the payment, the parts and the job's price, as sent or as you correct them. The job closes when nothing is missing. Page: https://headhoncho.app/docs/api/book_field_report | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **Book field report**, HeadHoncho API v1. It is a command, sent to the base address `https://api.headhoncho.app`. `POST /api/v1/commands/book-field-report` The key needs the **Money** area at **do**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). It runs the app's own command `book-field-report`. Send an `Idempotency-Key` header with every call: the same key with the same body returns the first answer and runs nothing twice. See [the model](https://headhoncho.app/docs/api/model#idempotency). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `report_id` | id, in the JSON body | Yes | From Money waiting to be booked. | `frp_77a1` | | `collected` | money, in the JSON body | No | What they collected. Default: what they reported. | `1450` | | `method` | text, in the JSON body | No | cash, card, zelle, check or other. Default: as reported. One of `cash`, `card`, `zelle`, `check`, `other`. | `cash` | | `parts` | money, in the JSON body | No | What the parts cost. Default: as reported. | `180` | | `total` | money, in the JSON body | No | The job's price. Default: as reported. | `1450` | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back accepted, report_id, job_id, number, closed (whether the job closed) and position. A report already booked or set aside is refused. It never deletes anything. It changes only what the command names, and it writes the change to the job's history with who asked for it. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `accepted` | true or false | True when the command ran. A command that cannot run is an error instead. | | `job_id` | id (text) | The id of the job. | | `number` | whole number | The number people say out loud, such as the job number. | | `position` | whole number | Where the change landed in the event log. Pass it as `after` on a read to see your own write. | | `report_id` | id (text) | The id of the report. | | `closed` | true or false | True when the job is closed. | ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`read_only`](https://headhoncho.app/docs/api/errors#read_only) | 403 | This credential may read this area but not change it. | | [`not_found`](https://headhoncho.app/docs/api/errors#not_found) | 404 | No such record in the companies this credential reaches. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`missing_idempotency_key`](https://headhoncho.app/docs/api/errors#missing_idempotency_key) | 400 | Send an Idempotency-Key header on every command. | | [`idempotency_mismatch`](https://headhoncho.app/docs/api/errors#idempotency_mismatch) | 409 | This Idempotency-Key was used with a different body. | | [`idempotency_in_progress`](https://headhoncho.app/docs/api/errors#idempotency_in_progress) | 409 | A command with this Idempotency-Key is still running. Wait a moment and send it again. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [Record payment](https://headhoncho.app/docs/api/record_payment): Record money the customer paid on a job. A payment that covers the price closes the job, as it does in the app. - [Void payment](https://headhoncho.app/docs/api/void_payment): Stop a payment entered wrong from counting. It stays on the job's money, marked voided, with why. - [Record expense](https://headhoncho.app/docs/api/record_expense): Record a cost on a job: parts, a rental, fuel. Paid by a technician, it is paid back to them on top of their share. - [Void expense](https://headhoncho.app/docs/api/void_expense): Stop an expense entered wrong from counting. It stays on the job's money, marked voided, with why. - [Dismiss field report](https://headhoncho.app/docs/api/dismiss_field_report): Not this: book nothing from a technician's report. What they said is kept on the job. - [Add expense type](https://headhoncho.app/docs/api/add_expense_type): Add a kind of cost the company records, such as Parts or Truck rental. A name already in use is refused, so sending it twice adds one. - [Update expense type](https://headhoncho.app/docs/api/update_expense_type): Rename an expense type, or retire it so new expenses cannot pick it. Old expenses keep it either way. - The same records in the app: [the Finance panel](https://headhoncho.app/docs/finance). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "accepted": true, "job_id": "job_1138", "number": 1138, "position": 88502, "report_id": "frp_77a1", "closed": true } ``` ### cURL ```bash curl -X POST "https://api.headhoncho.app/api/v1/commands/book-field-report" \ -H "Authorization: Bearer hh_live_..." \ -H "Idempotency-Key: 6f1d2c9e-1b7a-4c1e-9a52-0d3f8e4b7a10" \ -H "Content-Type: application/json" \ -d '{ "report_id": "frp_77a1", "collected": 1450, "method": "cash", "parts": 180, "total": 1450 }' ``` ### Python ```python import requests import uuid response = requests.post( "https://api.headhoncho.app/api/v1/commands/book-field-report", headers={ "Authorization": "Bearer hh_live_...", "Idempotency-Key": str(uuid.uuid4()), }, json={ "report_id": "frp_77a1", "collected": 1450, "method": "cash", "parts": 180, "total": 1450, }, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/commands/book-field-report", { method: "POST", headers: { Authorization: "Bearer hh_live_...", "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "report_id": "frp_77a1", "collected": 1450, "method": "cash", "parts": 180, "total": 1450 }), }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: book_field_report Arguments: report_id (id, required), collected (money, optional), method (text, optional), parts (money, optional), total (money, optional) Access: do on Money Hints: readOnly=false, destructive=false, idempotent=true, openWorld=false Try asking: "Using HeadHoncho, book field report with report_id frp_77a1 and collected 1450." ``` --- # Dismiss field report Dismiss field report is a command in the HeadHoncho API. Not this: book nothing from a technician's report. What they said is kept on the job. Page: https://headhoncho.app/docs/api/dismiss_field_report | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **Dismiss field report**, HeadHoncho API v1. It is a command, sent to the base address `https://api.headhoncho.app`. `POST /api/v1/commands/dismiss-field-report` The key needs the **Money** area at **do**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). It runs the app's own command `dismiss-field-report`. Send an `Idempotency-Key` header with every call: the same key with the same body returns the first answer and runs nothing twice. See [the model](https://headhoncho.app/docs/api/model#idempotency). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `report_id` | id, in the JSON body | Yes | From Money waiting to be booked. | `frp_77a1` | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back accepted, report_id, job_id, number and position. It never deletes anything. It changes only what the command names, and it writes the change to the job's history with who asked for it. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `accepted` | true or false | True when the command ran. A command that cannot run is an error instead. | | `job_id` | id (text) | The id of the job. | | `number` | whole number | The number people say out loud, such as the job number. | | `position` | whole number | Where the change landed in the event log. Pass it as `after` on a read to see your own write. | | `report_id` | id (text) | The id of the report. | ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`read_only`](https://headhoncho.app/docs/api/errors#read_only) | 403 | This credential may read this area but not change it. | | [`not_found`](https://headhoncho.app/docs/api/errors#not_found) | 404 | No such record in the companies this credential reaches. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`missing_idempotency_key`](https://headhoncho.app/docs/api/errors#missing_idempotency_key) | 400 | Send an Idempotency-Key header on every command. | | [`idempotency_mismatch`](https://headhoncho.app/docs/api/errors#idempotency_mismatch) | 409 | This Idempotency-Key was used with a different body. | | [`idempotency_in_progress`](https://headhoncho.app/docs/api/errors#idempotency_in_progress) | 409 | A command with this Idempotency-Key is still running. Wait a moment and send it again. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [Record payment](https://headhoncho.app/docs/api/record_payment): Record money the customer paid on a job. A payment that covers the price closes the job, as it does in the app. - [Void payment](https://headhoncho.app/docs/api/void_payment): Stop a payment entered wrong from counting. It stays on the job's money, marked voided, with why. - [Record expense](https://headhoncho.app/docs/api/record_expense): Record a cost on a job: parts, a rental, fuel. Paid by a technician, it is paid back to them on top of their share. - [Void expense](https://headhoncho.app/docs/api/void_expense): Stop an expense entered wrong from counting. It stays on the job's money, marked voided, with why. - [Book field report](https://headhoncho.app/docs/api/book_field_report): Book what a technician reported: the payment, the parts and the job's price, as sent or as you correct them. The job closes when nothing is missing. - [Add expense type](https://headhoncho.app/docs/api/add_expense_type): Add a kind of cost the company records, such as Parts or Truck rental. A name already in use is refused, so sending it twice adds one. - [Update expense type](https://headhoncho.app/docs/api/update_expense_type): Rename an expense type, or retire it so new expenses cannot pick it. Old expenses keep it either way. - The same records in the app: [the Finance panel](https://headhoncho.app/docs/finance). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "accepted": true, "job_id": "job_1138", "number": 1138, "position": 88502, "report_id": "frp_77a1" } ``` ### cURL ```bash curl -X POST "https://api.headhoncho.app/api/v1/commands/dismiss-field-report" \ -H "Authorization: Bearer hh_live_..." \ -H "Idempotency-Key: 6f1d2c9e-1b7a-4c1e-9a52-0d3f8e4b7a10" \ -H "Content-Type: application/json" \ -d '{ "report_id": "frp_77a1" }' ``` ### Python ```python import requests import uuid response = requests.post( "https://api.headhoncho.app/api/v1/commands/dismiss-field-report", headers={ "Authorization": "Bearer hh_live_...", "Idempotency-Key": str(uuid.uuid4()), }, json={ "report_id": "frp_77a1", }, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/commands/dismiss-field-report", { method: "POST", headers: { Authorization: "Bearer hh_live_...", "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "report_id": "frp_77a1" }), }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: dismiss_field_report Arguments: report_id (id, required) Access: do on Money Hints: readOnly=false, destructive=true, idempotent=true, openWorld=false Try asking: "Using HeadHoncho, dismiss field report with report_id frp_77a1." ``` --- # Add expense type Add expense type is a command in the HeadHoncho API. Add a kind of cost the company records, such as Parts or Truck rental. A name already in use is refused, so sending it twice adds one. Page: https://headhoncho.app/docs/api/add_expense_type | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **Add expense type**, HeadHoncho API v1. It is a command, sent to the base address `https://api.headhoncho.app`. `POST /api/v1/commands/add-expense-type` The key needs the **Money** area at **do**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). It runs the app's own command `add-expense-type`. Send an `Idempotency-Key` header with every call: the same key with the same body returns the first answer and runs nothing twice. See [the model](https://headhoncho.app/docs/api/model#idempotency). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `name` | text, in the JSON body | Yes | What the cost is called. | `Truck rental` | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back accepted, expense_type_id, name and position. It never deletes anything. It changes only what the command names, and it writes the change to the job's history with who asked for it. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `accepted` | true or false | True when the command ran. A command that cannot run is an error instead. | | `expense_type_id` | id (text) | The id of the expense type. | | `name` | text | The name, as the app shows it. | | `position` | whole number | Where the change landed in the event log. Pass it as `after` on a read to see your own write. | ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`read_only`](https://headhoncho.app/docs/api/errors#read_only) | 403 | This credential may read this area but not change it. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`missing_idempotency_key`](https://headhoncho.app/docs/api/errors#missing_idempotency_key) | 400 | Send an Idempotency-Key header on every command. | | [`idempotency_mismatch`](https://headhoncho.app/docs/api/errors#idempotency_mismatch) | 409 | This Idempotency-Key was used with a different body. | | [`idempotency_in_progress`](https://headhoncho.app/docs/api/errors#idempotency_in_progress) | 409 | A command with this Idempotency-Key is still running. Wait a moment and send it again. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [Record payment](https://headhoncho.app/docs/api/record_payment): Record money the customer paid on a job. A payment that covers the price closes the job, as it does in the app. - [Void payment](https://headhoncho.app/docs/api/void_payment): Stop a payment entered wrong from counting. It stays on the job's money, marked voided, with why. - [Record expense](https://headhoncho.app/docs/api/record_expense): Record a cost on a job: parts, a rental, fuel. Paid by a technician, it is paid back to them on top of their share. - [Void expense](https://headhoncho.app/docs/api/void_expense): Stop an expense entered wrong from counting. It stays on the job's money, marked voided, with why. - [Book field report](https://headhoncho.app/docs/api/book_field_report): Book what a technician reported: the payment, the parts and the job's price, as sent or as you correct them. The job closes when nothing is missing. - [Dismiss field report](https://headhoncho.app/docs/api/dismiss_field_report): Not this: book nothing from a technician's report. What they said is kept on the job. - [Update expense type](https://headhoncho.app/docs/api/update_expense_type): Rename an expense type, or retire it so new expenses cannot pick it. Old expenses keep it either way. - The same records in the app: [the Finance panel](https://headhoncho.app/docs/finance). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "accepted": true, "expense_type_id": "ext_04", "name": "Truck rental", "position": 88510 } ``` ### cURL ```bash curl -X POST "https://api.headhoncho.app/api/v1/commands/add-expense-type" \ -H "Authorization: Bearer hh_live_..." \ -H "Idempotency-Key: 6f1d2c9e-1b7a-4c1e-9a52-0d3f8e4b7a10" \ -H "Content-Type: application/json" \ -d '{ "name": "Truck rental" }' ``` ### Python ```python import requests import uuid response = requests.post( "https://api.headhoncho.app/api/v1/commands/add-expense-type", headers={ "Authorization": "Bearer hh_live_...", "Idempotency-Key": str(uuid.uuid4()), }, json={ "name": "Truck rental", }, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/commands/add-expense-type", { method: "POST", headers: { Authorization: "Bearer hh_live_...", "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "name": "Truck rental" }), }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: add_expense_type Arguments: name (text, required) Access: do on Money Hints: readOnly=false, destructive=false, idempotent=true, openWorld=false Try asking: "Using HeadHoncho, add expense type with name Truck rental." ``` --- # Update expense type Update expense type is a command in the HeadHoncho API. Rename an expense type, or retire it so new expenses cannot pick it. Old expenses keep it either way. Page: https://headhoncho.app/docs/api/update_expense_type | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **Update expense type**, HeadHoncho API v1. It is a command, sent to the base address `https://api.headhoncho.app`. `POST /api/v1/commands/update-expense-type` The key needs the **Money** area at **do**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). It runs the app's own command `update-expense-type`. Send an `Idempotency-Key` header with every call: the same key with the same body returns the first answer and runs nothing twice. See [the model](https://headhoncho.app/docs/api/model#idempotency). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `expense_type_id` | id, in the JSON body | Yes | From Who am I's expense_types. | `ext_04` | | `name` | text, in the JSON body | No | The new name. | `Truck and trailer rental` | | `archived` | boolean, in the JSON body | No | true retires it, false brings it back. | `false` | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back accepted, expense_type_id, name and position. It never deletes anything. It changes only what the command names, and it writes the change to the job's history with who asked for it. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `accepted` | true or false | True when the command ran. A command that cannot run is an error instead. | | `expense_type_id` | id (text) | The id of the expense type. | | `name` | text | The name, as the app shows it. | | `position` | whole number | Where the change landed in the event log. Pass it as `after` on a read to see your own write. | ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`read_only`](https://headhoncho.app/docs/api/errors#read_only) | 403 | This credential may read this area but not change it. | | [`not_found`](https://headhoncho.app/docs/api/errors#not_found) | 404 | No such record in the companies this credential reaches. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`missing_idempotency_key`](https://headhoncho.app/docs/api/errors#missing_idempotency_key) | 400 | Send an Idempotency-Key header on every command. | | [`idempotency_mismatch`](https://headhoncho.app/docs/api/errors#idempotency_mismatch) | 409 | This Idempotency-Key was used with a different body. | | [`idempotency_in_progress`](https://headhoncho.app/docs/api/errors#idempotency_in_progress) | 409 | A command with this Idempotency-Key is still running. Wait a moment and send it again. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [Record payment](https://headhoncho.app/docs/api/record_payment): Record money the customer paid on a job. A payment that covers the price closes the job, as it does in the app. - [Void payment](https://headhoncho.app/docs/api/void_payment): Stop a payment entered wrong from counting. It stays on the job's money, marked voided, with why. - [Record expense](https://headhoncho.app/docs/api/record_expense): Record a cost on a job: parts, a rental, fuel. Paid by a technician, it is paid back to them on top of their share. - [Void expense](https://headhoncho.app/docs/api/void_expense): Stop an expense entered wrong from counting. It stays on the job's money, marked voided, with why. - [Book field report](https://headhoncho.app/docs/api/book_field_report): Book what a technician reported: the payment, the parts and the job's price, as sent or as you correct them. The job closes when nothing is missing. - [Dismiss field report](https://headhoncho.app/docs/api/dismiss_field_report): Not this: book nothing from a technician's report. What they said is kept on the job. - [Add expense type](https://headhoncho.app/docs/api/add_expense_type): Add a kind of cost the company records, such as Parts or Truck rental. A name already in use is refused, so sending it twice adds one. - The same records in the app: [the Finance panel](https://headhoncho.app/docs/finance). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "accepted": true, "expense_type_id": "ext_04", "name": "Truck and trailer rental", "position": 88511 } ``` ### cURL ```bash curl -X POST "https://api.headhoncho.app/api/v1/commands/update-expense-type" \ -H "Authorization: Bearer hh_live_..." \ -H "Idempotency-Key: 6f1d2c9e-1b7a-4c1e-9a52-0d3f8e4b7a10" \ -H "Content-Type: application/json" \ -d '{ "expense_type_id": "ext_04", "name": "Truck and trailer rental", "archived": false }' ``` ### Python ```python import requests import uuid response = requests.post( "https://api.headhoncho.app/api/v1/commands/update-expense-type", headers={ "Authorization": "Bearer hh_live_...", "Idempotency-Key": str(uuid.uuid4()), }, json={ "expense_type_id": "ext_04", "name": "Truck and trailer rental", "archived": False, }, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/commands/update-expense-type", { method: "POST", headers: { Authorization: "Bearer hh_live_...", "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "expense_type_id": "ext_04", "name": "Truck and trailer rental", "archived": false }), }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: update_expense_type Arguments: expense_type_id (id, required), name (text, optional), archived (boolean, optional) Access: do on Money Hints: readOnly=false, destructive=false, idempotent=true, openWorld=false Try asking: "Using HeadHoncho, update expense type with expense_type_id ext_04 and name Truck and trailer rental." ``` --- # List balances List balances is a read in the HeadHoncho API. Who owes who, per technician: their cuts and paid-back parts against the cash they hold and what was already paid out. Page: https://headhoncho.app/docs/api/list_balances | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **List balances**, HeadHoncho API v1. It is a read, sent to the base address `https://api.headhoncho.app`. `GET /api/v1/balances` The key needs the **Money** area at **read**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). Send your key as `Authorization: Bearer hh_live_...`. See [API keys](https://headhoncho.app/docs/api/keys). ## Parameters This call takes no parameters. ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back balances, one per technician with any money: worker_id, name, role, payable (cuts, parts and monthly pay owed to them), receivable (cash they collected and hold), paid_out and paid_in (balance closes and payouts each way), net (what the company owes them; below zero, what they owe the company) and says, in words. totals: the same figures for everyone. It never changes a record. It only reads the companies the key reaches. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `balances` | list of objects | The balances. | | `balances[].worker_id` | id (text) | The id of the worker. | | `balances[].name` | text | The name, as the app shows it. | | `balances[].role` | text | The role: what this person does on a job. | | `balances[].payable` | money (number) | What the business owes this person (cuts, parts and pay owed to them). In the company's currency. | | `balances[].receivable` | money (number) | What this person owes the business (cash they collected and still hold). In the company's currency. | | `balances[].paid_out` | money (number) | What was paid out by the business. In the company's currency. | | `balances[].paid_in` | money (number) | What was paid in to the business. In the company's currency. | | `balances[].monthly_pay` | money (number) | The monthly pay. In the company's currency. | | `balances[].cash_held` | money (number) | The cash held. In the company's currency. | | `balances[].net` | money (number) | The net amount, after what is owed either way. In the company's currency. | | `balances[].says` | text | The text to show a person. | | `totals` | object | The totals. | | `totals.payable` | money (number) | What the business owes this person (cuts, parts and pay owed to them). In the company's currency. | | `totals.receivable` | money (number) | What this person owes the business (cash they collected and still hold). In the company's currency. | | `totals.paid_out` | money (number) | What was paid out by the business. In the company's currency. | | `totals.paid_in` | money (number) | What was paid in to the business. In the company's currency. | | `totals.net` | money (number) | The net amount, after what is owed either way. In the company's currency. | ## The same numbers as the app These are the balances the Team and Finance panels show, from the same function. Trashed jobs count in none of them. ## Every company A balance is a person's, across every company they work for, so a credential must reach every company to read it. ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [Get balance statement](https://headhoncho.app/docs/api/get_balance_statement): Every line on a technician's balance for a period, with the running balance: cuts, parts, cash held and each payout, voided ones marked. - [List closed balances](https://headhoncho.app/docs/api/list_closed_balances): Every balance close and payout, newest first, voided ones included, with the jobs each one covered. - The same records in the app: [the Finance panel](https://headhoncho.app/docs/finance). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "balances": [ { "worker_id": "wrk_7a12", "name": "Omar S.", "role": "subcontractor", "payable": 4210.5, "receivable": 1450.0, "paid_out": 1800.0, "paid_in": 0.0, "monthly_pay": 0.0, "cash_held": 1450.0, "net": 960.5, "says": "Pay out to Omar S." }, { "worker_id": "wrk_3b90", "name": "Dana R.", "role": "technician", "payable": 610.0, "receivable": 900.0, "paid_out": 0.0, "paid_in": 0.0, "monthly_pay": 0.0, "cash_held": 900.0, "net": -290.0, "says": "Dana R. pays the company" } ], "totals": { "payable": 4820.5, "receivable": 2350.0, "paid_out": 1800.0, "paid_in": 0.0, "net": 670.5 } } ``` ### cURL ```bash curl "https://api.headhoncho.app/api/v1/balances" \ -H "Authorization: Bearer hh_live_..." ``` ### Python ```python import requests response = requests.get( "https://api.headhoncho.app/api/v1/balances", headers={"Authorization": "Bearer hh_live_..."}, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/balances", { headers: { Authorization: "Bearer hh_live_..." }, }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: list_balances Arguments: none Access: read on Money Hints: readOnly=true, destructive=false, idempotent=true, openWorld=false Try asking: "Using HeadHoncho, list balances." ``` --- # Get balance statement Get balance statement is a read in the HeadHoncho API. Every line on a technician's balance for a period, with the running balance: cuts, parts, cash held and each payout, voided ones marked. Page: https://headhoncho.app/docs/api/get_balance_statement | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **Get balance statement**, HeadHoncho API v1. It is a read, sent to the base address `https://api.headhoncho.app`. `GET /api/v1/balances/{worker_id}/statement` The key needs the **Money** area at **read**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). Send your key as `Authorization: Bearer hh_live_...`. See [API keys](https://headhoncho.app/docs/api/keys). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `worker_id` | id, in the path | Yes | The technician, from Who am I's technicians. | `wrk_7a12` | | `from` | date, in the query | No | First day. Default: the first of this month. | `2026-10-01` | | `to` | date, in the query | No | Last day, included. Default: today. | `2026-10-31` | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back worker_id, name, from, to, opening_balance (everything before the period), lines (id, kind: ledger or payout, label, job_id, job_number, amount, delta, running_balance, on, memo, voided, void_reason) and closing_balance, which is the balance on the last day. It never changes a record. It only reads the companies the key reaches. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `worker_id` | id (text) | The id of the worker. | | `name` | text | The name, as the app shows it. | | `from` | date (YYYY-MM-DD) | The first day of the range, inclusive. | | `to` | date (YYYY-MM-DD) | The last day of the range, inclusive. | | `opening_balance` | money (number) | The balance at the start of the range. In the company's currency. | | `lines` | list of objects | The lines, oldest first. | | `lines[].id` | id (text) | The id of this record. Ids are opaque text: keep them exactly as given. | | `lines[].kind` | text | What sort of thing this is. | | `lines[].label` | text | The name the app shows for it. | | `lines[].job_id` | id (text) | The id of the job. | | `lines[].job_number` | whole number | The job number people say out loud. | | `lines[].amount` | money (number) | The amount. In the company's currency. | | `lines[].delta` | money (number) | How much this line moved the balance. In the company's currency. | | `lines[].running_balance` | money (number) | The balance after this line. In the company's currency. | | `lines[].on` | date (YYYY-MM-DD) | The date it happened, as a date in the company's time zone. | | `lines[].memo` | text | A free-text note on the line. Empty when there is none. | | `lines[].voided` | true or false | True when the line was voided. A voided line counts in no figure. | | `lines[].void_reason` | text | Why it was voided. Empty when it was not. | | `closing_balance` | money (number) | The balance at the end of the range. In the company's currency. | ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`not_found`](https://headhoncho.app/docs/api/errors#not_found) | 404 | No such record in the companies this credential reaches. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [List balances](https://headhoncho.app/docs/api/list_balances): Who owes who, per technician: their cuts and paid-back parts against the cash they hold and what was already paid out. - [List closed balances](https://headhoncho.app/docs/api/list_closed_balances): Every balance close and payout, newest first, voided ones included, with the jobs each one covered. - The same records in the app: [the Finance panel](https://headhoncho.app/docs/finance). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "worker_id": "wrk_7a12", "name": "Omar S.", "from": "2026-10-01", "to": "2026-10-31", "opening_balance": 1200.0, "lines": [ { "id": "led_4d0e", "kind": "ledger", "label": "cut", "job_id": "job_1138", "job_number": 1138, "amount": 613.82, "delta": 613.82, "running_balance": 1813.82, "on": "2026-10-16", "memo": "", "voided": false, "void_reason": "" }, { "id": "set_51aa", "kind": "payout", "label": "other", "job_id": null, "job_number": null, "amount": 1800.0, "delta": -1800.0, "running_balance": 13.82, "on": "2026-10-20", "memo": "Balance closed", "voided": false, "void_reason": "" } ], "closing_balance": 13.82 } ``` ### cURL ```bash curl "https://api.headhoncho.app/api/v1/balances/wrk_7a12/statement?from=2026-10-01&to=2026-10-31" \ -H "Authorization: Bearer hh_live_..." ``` ### Python ```python import requests response = requests.get( "https://api.headhoncho.app/api/v1/balances/wrk_7a12/statement", headers={"Authorization": "Bearer hh_live_..."}, params={ "from": "2026-10-01", "to": "2026-10-31", }, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/balances/wrk_7a12/statement?from=2026-10-01&to=2026-10-31", { headers: { Authorization: "Bearer hh_live_..." }, }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: get_balance_statement Arguments: worker_id (id, required), from (date, optional), to (date, optional) Access: read on Money Hints: readOnly=true, destructive=false, idempotent=true, openWorld=false Try asking: "Using HeadHoncho, get balance statement with worker_id wrk_7a12 and from 2026-10-01." ``` --- # List closed balances List closed balances is a read in the HeadHoncho API. Every balance close and payout, newest first, voided ones included, with the jobs each one covered. Page: https://headhoncho.app/docs/api/list_closed_balances | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **List closed balances**, HeadHoncho API v1. It is a read, sent to the base address `https://api.headhoncho.app`. `GET /api/v1/closed-balances` The key needs the **Money** area at **read**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). Send your key as `Authorization: Bearer hh_live_...`. See [API keys](https://headhoncho.app/docs/api/keys). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `worker_id` | id, in the query | No | Only this technician. | `wrk_7a12` | | `direction` | text, in the query | No | to_worker (the company paid) or from_worker (they paid in). One of `to_worker`, `from_worker`. | `to_worker` | | `method` | text, in the query | No | ach, cash, check, card or other. | `zelle` | | `voided` | text, in the query | No | include (default), hide or only. One of `include`, `hide`, `only`. | `hide` | | `from` | date, in the query | No | Paid on or after this day. | `2026-10-01` | | `to` | date, in the query | No | Paid on or before this day. | `2026-10-31` | | `page` | number, in the query | No | Default 1, twenty a page. | `1` | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back closed_balances (id, worker_id, name, paid_on, direction, method, reference, amount, jobs, voided, has_statement), total, page and pages. It never changes a record. It only reads the companies the key reaches. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `closed_balances` | list of objects | The closed balances. | | `closed_balances[].id` | id (text) | The id of this record. Ids are opaque text: keep them exactly as given. | | `closed_balances[].worker_id` | id (text) | The id of the worker. | | `closed_balances[].name` | text | The name, as the app shows it. | | `closed_balances[].paid_on` | date (YYYY-MM-DD) | The date it was paid. | | `closed_balances[].direction` | text | One of `to_worker`, `from_worker`. | | `closed_balances[].method` | text | How it was paid, such as card or cash. | | `closed_balances[].reference` | text | The reference the payer or the bank gave. | | `closed_balances[].amount` | money (number) | The amount. In the company's currency. | | `closed_balances[].jobs` | whole number | The jobs. | | `closed_balances[].voided` | true or false | One of `include`, `hide`, `only`. | | `closed_balances[].has_statement` | true or false | True when there is a statement. | | `total` | whole number | The total, in the company's currency. | | `page` | whole number | The page number, starting at 1. | | `pages` | whole number | How many pages there are. | ## The statement file The statement PDF of a balance close stays in the app, on Finance › History: it is a drawn report, which the API does not hand out. ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`not_found`](https://headhoncho.app/docs/api/errors#not_found) | 404 | No such record in the companies this credential reaches. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [List balances](https://headhoncho.app/docs/api/list_balances): Who owes who, per technician: their cuts and paid-back parts against the cash they hold and what was already paid out. - [Get balance statement](https://headhoncho.app/docs/api/get_balance_statement): Every line on a technician's balance for a period, with the running balance: cuts, parts, cash held and each payout, voided ones marked. - The same records in the app: [the Finance panel](https://headhoncho.app/docs/finance). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "closed_balances": [ { "id": "set_51aa", "worker_id": "wrk_7a12", "name": "Omar S.", "paid_on": "2026-10-20", "direction": "to_worker", "method": "other", "reference": "Zelle 8812", "amount": 1800.0, "jobs": 6, "voided": false, "has_statement": true } ], "total": 1, "page": 1, "pages": 1 } ``` ### cURL ```bash curl "https://api.headhoncho.app/api/v1/closed-balances?worker_id=wrk_7a12&direction=to_worker" \ -H "Authorization: Bearer hh_live_..." ``` ### Python ```python import requests response = requests.get( "https://api.headhoncho.app/api/v1/closed-balances", headers={"Authorization": "Bearer hh_live_..."}, params={ "worker_id": "wrk_7a12", "direction": "to_worker", }, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/closed-balances?worker_id=wrk_7a12&direction=to_worker", { headers: { Authorization: "Bearer hh_live_..." }, }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: list_closed_balances Arguments: worker_id (id, optional), direction (text, optional), method (text, optional), voided (text, optional), from (date, optional), to (date, optional), page (number, optional) Access: read on Money Hints: readOnly=true, destructive=false, idempotent=true, openWorld=false Try asking: "Using HeadHoncho, list closed balances with worker_id wrk_7a12." ``` --- # Close balance Close balance is a command in the HeadHoncho API. Close what a technician is owed for the jobs you name, or for everything open through a day, as one payout netted against the cash they hold. Page: https://headhoncho.app/docs/api/close_balance | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **Close balance**, HeadHoncho API v1. It is a command, sent to the base address `https://api.headhoncho.app`. `POST /api/v1/commands/close-balance` The key needs the **Money** area at **do**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). It runs the app's own command `close-balance`. Send an `Idempotency-Key` header with every call: the same key with the same body returns the first answer and runs nothing twice. See [the model](https://headhoncho.app/docs/api/model#idempotency). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `worker_id` | id, in the JSON body | Yes | The technician, from Who am I's technicians. | `wrk_7a12` | | `job_ids` | text, in the JSON body | No | The jobs to close, ids or numbers, comma separated. Empty: every open job through `through`. | `1138,1142,1150` | | `through` | date, in the JSON body | No | With no job_ids: close everything open up to this day. Empty: all time. | `2026-10-31` | | `method` | text, in the JSON body | No | How the money moved: ach, cash, check, card or other. One of `ach`, `cash`, `check`, `card`, `other`. | `other` | | `reference` | text, in the JSON body | No | A check number or transfer id. | `Zelle 8812` | | `memo` | text, in the JSON body | No | Anything to remember. | `October` | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back accepted, worker_id, closed_balance_id, direction (to_worker: the company pays; from_worker: they pay in), amount, payable, receivable, jobs, entries, balanced (each job and whether its status moved) and position. It never deletes anything. It changes only what the command names, and it writes the change to the job's history with who asked for it. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `accepted` | true or false | True when the command ran. A command that cannot run is an error instead. | | `worker_id` | id (text) | The id of the worker. | | `position` | whole number | Where the change landed in the event log. Pass it as `after` on a read to see your own write. | | `closed_balance_id` | id (text) | The id of the closed balance. | | `direction` | text | Which way the money moved. | | `amount` | money (decimal as text) | The amount. In the company's currency. | | `payable` | money (decimal as text) | What the business owes this person (cuts, parts and pay owed to them). In the company's currency. | | `receivable` | money (decimal as text) | What this person owes the business (cash they collected and still hold). In the company's currency. | | `jobs` | whole number | The jobs. | | `entries` | whole number | The entries. | | `balanced` | list of objects | The balanced. | | `balanced[].job_id` | id (text) | The id of the job. | | `balanced[].acted` | true or false | True when the command changed something. False when there was nothing to change. | | `balanced[].reason` | text | The reason given. | ## One payout, both ways A technician owed $700 in cuts who holds $500 of the company's cash is squared by one payout of $200. The close lists every line it took, so each job reads as closed. ## Jobs you name With job_ids, those jobs close whatever their status, and a job held back is put back first. A job outside the credential's companies is refused. Without job_ids, only the jobs in the credential's companies are closed. ## Statuses follow Each job covered moves to the status your money automation names for a closed balance, as it does in the app. ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`read_only`](https://headhoncho.app/docs/api/errors#read_only) | 403 | This credential may read this area but not change it. | | [`not_found`](https://headhoncho.app/docs/api/errors#not_found) | 404 | No such record in the companies this credential reaches. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`missing_idempotency_key`](https://headhoncho.app/docs/api/errors#missing_idempotency_key) | 400 | Send an Idempotency-Key header on every command. | | [`idempotency_mismatch`](https://headhoncho.app/docs/api/errors#idempotency_mismatch) | 409 | This Idempotency-Key was used with a different body. | | [`idempotency_in_progress`](https://headhoncho.app/docs/api/errors#idempotency_in_progress) | 409 | A command with this Idempotency-Key is still running. Wait a moment and send it again. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [Record payout](https://headhoncho.app/docs/api/record_payout): Record money paid to a technician, or paid in by one, that names no jobs. It moves their balance and closes no particular job. - [Void closed balance](https://headhoncho.app/docs/api/void_closed_balance): Undo a balance close or a payout entered wrong. Its jobs open again, and it stays on the list, marked voided, with why. - [Hold back job](https://headhoncho.app/docs/api/hold_back_job): Keep one job out of a technician's balance closes until you put it back, with why. Its cut, parts and cash wait together. - [Put back job](https://headhoncho.app/docs/api/put_back_job): Let a held-back job count in the technician's next balance close again. - [Post monthly pay](https://headhoncho.app/docs/api/post_monthly_pay): Add a month of pay to the balance of every active technician on a monthly rate. A month is posted once, however often this is sent. - The same records in the app: [the Finance panel](https://headhoncho.app/docs/finance). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "accepted": true, "worker_id": "wrk_7a12", "position": 88520, "closed_balance_id": "set_51aa", "direction": "to_worker", "amount": "1800.00", "payable": "3250.00", "receivable": "1450.00", "jobs": 3, "entries": 5, "balanced": [ { "job_id": "job_1138", "acted": true, "reason": "" } ] } ``` ### cURL ```bash curl -X POST "https://api.headhoncho.app/api/v1/commands/close-balance" \ -H "Authorization: Bearer hh_live_..." \ -H "Idempotency-Key: 6f1d2c9e-1b7a-4c1e-9a52-0d3f8e4b7a10" \ -H "Content-Type: application/json" \ -d '{ "worker_id": "wrk_7a12", "job_ids": "1138,1142,1150", "through": "2026-10-31", "method": "other", "reference": "Zelle 8812", "memo": "October" }' ``` ### Python ```python import requests import uuid response = requests.post( "https://api.headhoncho.app/api/v1/commands/close-balance", headers={ "Authorization": "Bearer hh_live_...", "Idempotency-Key": str(uuid.uuid4()), }, json={ "worker_id": "wrk_7a12", "job_ids": "1138,1142,1150", "through": "2026-10-31", "method": "other", "reference": "Zelle 8812", "memo": "October", }, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/commands/close-balance", { method: "POST", headers: { Authorization: "Bearer hh_live_...", "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "worker_id": "wrk_7a12", "job_ids": "1138,1142,1150", "through": "2026-10-31", "method": "other", "reference": "Zelle 8812", "memo": "October" }), }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: close_balance Arguments: worker_id (id, required), job_ids (text, optional), through (date, optional), method (text, optional), reference (text, optional), memo (text, optional) Access: do on Money Hints: readOnly=false, destructive=false, idempotent=false, openWorld=false Try asking: "Using HeadHoncho, close balance with worker_id wrk_7a12 and job_ids 1138,1142,1150." ``` --- # Record payout Record payout is a command in the HeadHoncho API. Record money paid to a technician, or paid in by one, that names no jobs. It moves their balance and closes no particular job. Page: https://headhoncho.app/docs/api/record_payout | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **Record payout**, HeadHoncho API v1. It is a command, sent to the base address `https://api.headhoncho.app`. `POST /api/v1/commands/record-payout` The key needs the **Money** area at **do**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). It runs the app's own command `record-payout`. Send an `Idempotency-Key` header with every call: the same key with the same body returns the first answer and runs nothing twice. See [the model](https://headhoncho.app/docs/api/model#idempotency). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `worker_id` | id, in the JSON body | Yes | The technician, from Who am I's technicians. | `wrk_7a12` | | `direction` | text, in the JSON body | Yes | to_worker (the company paid them) or from_worker (they paid the company). One of `to_worker`, `from_worker`. | `to_worker` | | `amount` | money, in the JSON body | Yes | How much, a number. | `500` | | `method` | text, in the JSON body | Yes | ach, cash, check, card or other. One of `ach`, `cash`, `check`, `card`, `other`. | `cash` | | `paid_at` | datetime, in the JSON body | No | When. Default: now. | `2026-10-20T17:00:00-05:00` | | `reference` | text, in the JSON body | No | A check number or transfer id. | `Check 1042` | | `memo` | text, in the JSON body | No | Anything to remember. | `Advance` | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back accepted, worker_id, closed_balance_id and position. It never deletes anything. It changes only what the command names, and it writes the change to the job's history with who asked for it. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `accepted` | true or false | True when the command ran. A command that cannot run is an error instead. | | `worker_id` | id (text) | The id of the worker. | | `position` | whole number | Where the change landed in the event log. Pass it as `after` on a read to see your own write. | | `closed_balance_id` | id (text) | The id of the closed balance. | ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`read_only`](https://headhoncho.app/docs/api/errors#read_only) | 403 | This credential may read this area but not change it. | | [`not_found`](https://headhoncho.app/docs/api/errors#not_found) | 404 | No such record in the companies this credential reaches. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`missing_idempotency_key`](https://headhoncho.app/docs/api/errors#missing_idempotency_key) | 400 | Send an Idempotency-Key header on every command. | | [`idempotency_mismatch`](https://headhoncho.app/docs/api/errors#idempotency_mismatch) | 409 | This Idempotency-Key was used with a different body. | | [`idempotency_in_progress`](https://headhoncho.app/docs/api/errors#idempotency_in_progress) | 409 | A command with this Idempotency-Key is still running. Wait a moment and send it again. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [Close balance](https://headhoncho.app/docs/api/close_balance): Close what a technician is owed for the jobs you name, or for everything open through a day, as one payout netted against the cash they hold. - [Void closed balance](https://headhoncho.app/docs/api/void_closed_balance): Undo a balance close or a payout entered wrong. Its jobs open again, and it stays on the list, marked voided, with why. - [Hold back job](https://headhoncho.app/docs/api/hold_back_job): Keep one job out of a technician's balance closes until you put it back, with why. Its cut, parts and cash wait together. - [Put back job](https://headhoncho.app/docs/api/put_back_job): Let a held-back job count in the technician's next balance close again. - [Post monthly pay](https://headhoncho.app/docs/api/post_monthly_pay): Add a month of pay to the balance of every active technician on a monthly rate. A month is posted once, however often this is sent. - The same records in the app: [the Finance panel](https://headhoncho.app/docs/finance). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "accepted": true, "worker_id": "wrk_7a12", "position": 88520, "closed_balance_id": "set_52bb" } ``` ### cURL ```bash curl -X POST "https://api.headhoncho.app/api/v1/commands/record-payout" \ -H "Authorization: Bearer hh_live_..." \ -H "Idempotency-Key: 6f1d2c9e-1b7a-4c1e-9a52-0d3f8e4b7a10" \ -H "Content-Type: application/json" \ -d '{ "worker_id": "wrk_7a12", "direction": "to_worker", "amount": 500, "method": "cash", "paid_at": "2026-10-20T17:00:00-05:00", "reference": "Check 1042", "memo": "Advance" }' ``` ### Python ```python import requests import uuid response = requests.post( "https://api.headhoncho.app/api/v1/commands/record-payout", headers={ "Authorization": "Bearer hh_live_...", "Idempotency-Key": str(uuid.uuid4()), }, json={ "worker_id": "wrk_7a12", "direction": "to_worker", "amount": 500, "method": "cash", "paid_at": "2026-10-20T17:00:00-05:00", "reference": "Check 1042", "memo": "Advance", }, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/commands/record-payout", { method: "POST", headers: { Authorization: "Bearer hh_live_...", "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "worker_id": "wrk_7a12", "direction": "to_worker", "amount": 500, "method": "cash", "paid_at": "2026-10-20T17:00:00-05:00", "reference": "Check 1042", "memo": "Advance" }), }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: record_payout Arguments: worker_id (id, required), direction (text, required), amount (money, required), method (text, required), paid_at (datetime, optional), reference (text, optional), memo (text, optional) Access: do on Money Hints: readOnly=false, destructive=false, idempotent=false, openWorld=false Try asking: "Using HeadHoncho, record payout with worker_id wrk_7a12 and direction to_worker and amount 500 and method cash and paid_at 2026-10-20T17:00:00-05:00." ``` --- # Void closed balance Void closed balance is a command in the HeadHoncho API. Undo a balance close or a payout entered wrong. Its jobs open again, and it stays on the list, marked voided, with why. Page: https://headhoncho.app/docs/api/void_closed_balance | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **Void closed balance**, HeadHoncho API v1. It is a command, sent to the base address `https://api.headhoncho.app`. `POST /api/v1/commands/void-closed-balance` The key needs the **Money** area at **do**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). It runs the app's own command `void-closed-balance`. Send an `Idempotency-Key` header with every call: the same key with the same body returns the first answer and runs nothing twice. See [the model](https://headhoncho.app/docs/api/model#idempotency). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `closed_balance_id` | id, in the JSON body | Yes | From Closed balances, or the close's answer. | `set_51aa` | | `reason` | text, in the JSON body | Yes | Why it was wrong. | `Wrong technician` | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back accepted, worker_id, closed_balance_id, released (each line it covered, and how much of it other closes still cover) and position. It never deletes anything. It changes only what the command names, and it writes the change to the job's history with who asked for it. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `accepted` | true or false | True when the command ran. A command that cannot run is an error instead. | | `worker_id` | id (text) | The id of the worker. | | `position` | whole number | Where the change landed in the event log. Pass it as `after` on a read to see your own write. | | `closed_balance_id` | id (text) | The id of the closed balance. | | `released` | list of objects | The released. | | `released[].entry_id` | id (text) | The id of the entry. | | `released[].still_covered` | money (number) | The still covered. In the company's currency. | ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`read_only`](https://headhoncho.app/docs/api/errors#read_only) | 403 | This credential may read this area but not change it. | | [`not_found`](https://headhoncho.app/docs/api/errors#not_found) | 404 | No such record in the companies this credential reaches. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`missing_idempotency_key`](https://headhoncho.app/docs/api/errors#missing_idempotency_key) | 400 | Send an Idempotency-Key header on every command. | | [`idempotency_mismatch`](https://headhoncho.app/docs/api/errors#idempotency_mismatch) | 409 | This Idempotency-Key was used with a different body. | | [`idempotency_in_progress`](https://headhoncho.app/docs/api/errors#idempotency_in_progress) | 409 | A command with this Idempotency-Key is still running. Wait a moment and send it again. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [Close balance](https://headhoncho.app/docs/api/close_balance): Close what a technician is owed for the jobs you name, or for everything open through a day, as one payout netted against the cash they hold. - [Record payout](https://headhoncho.app/docs/api/record_payout): Record money paid to a technician, or paid in by one, that names no jobs. It moves their balance and closes no particular job. - [Hold back job](https://headhoncho.app/docs/api/hold_back_job): Keep one job out of a technician's balance closes until you put it back, with why. Its cut, parts and cash wait together. - [Put back job](https://headhoncho.app/docs/api/put_back_job): Let a held-back job count in the technician's next balance close again. - [Post monthly pay](https://headhoncho.app/docs/api/post_monthly_pay): Add a month of pay to the balance of every active technician on a monthly rate. A month is posted once, however often this is sent. - The same records in the app: [the Finance panel](https://headhoncho.app/docs/finance). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "accepted": true, "worker_id": "wrk_7a12", "position": 88520, "closed_balance_id": "set_51aa", "released": [ { "entry_id": "led_4d0e", "still_covered": 0.0 } ] } ``` ### cURL ```bash curl -X POST "https://api.headhoncho.app/api/v1/commands/void-closed-balance" \ -H "Authorization: Bearer hh_live_..." \ -H "Idempotency-Key: 6f1d2c9e-1b7a-4c1e-9a52-0d3f8e4b7a10" \ -H "Content-Type: application/json" \ -d '{ "closed_balance_id": "set_51aa", "reason": "Wrong technician" }' ``` ### Python ```python import requests import uuid response = requests.post( "https://api.headhoncho.app/api/v1/commands/void-closed-balance", headers={ "Authorization": "Bearer hh_live_...", "Idempotency-Key": str(uuid.uuid4()), }, json={ "closed_balance_id": "set_51aa", "reason": "Wrong technician", }, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/commands/void-closed-balance", { method: "POST", headers: { Authorization: "Bearer hh_live_...", "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "closed_balance_id": "set_51aa", "reason": "Wrong technician" }), }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: void_closed_balance Arguments: closed_balance_id (id, required), reason (text, required) Access: do on Money Hints: readOnly=false, destructive=true, idempotent=true, openWorld=false Try asking: "Using HeadHoncho, void closed balance with closed_balance_id set_51aa and reason Wrong technician." ``` --- # Hold back job Hold back job is a command in the HeadHoncho API. Keep one job out of a technician's balance closes until you put it back, with why. Its cut, parts and cash wait together. Page: https://headhoncho.app/docs/api/hold_back_job | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **Hold back job**, HeadHoncho API v1. It is a command, sent to the base address `https://api.headhoncho.app`. `POST /api/v1/commands/hold-back-job` The key needs the **Money** area at **do**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). It runs the app's own command `hold-back-job`. Send an `Idempotency-Key` header with every call: the same key with the same body returns the first answer and runs nothing twice. See [the model](https://headhoncho.app/docs/api/model#idempotency). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `worker_id` | id, in the JSON body | Yes | The technician, from Who am I's technicians. | `wrk_7a12` | | `job_id` | id, in the JSON body | Yes | The job id, or its number. | `job_1138` | | `reason` | text, in the JSON body | No | Why it waits. | `Customer disputes the bill` | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back accepted, worker_id, job_id, number, hold_id, reason and position. A job already held back is refused, so the reason on it stays the live one. It never deletes anything. It changes only what the command names, and it writes the change to the job's history with who asked for it. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `accepted` | true or false | True when the command ran. A command that cannot run is an error instead. | | `worker_id` | id (text) | The id of the worker. | | `position` | whole number | Where the change landed in the event log. Pass it as `after` on a read to see your own write. | | `job_id` | id (text) | The id of the job. | | `number` | whole number | The number people say out loud, such as the job number. | | `hold_id` | id (text) | The id of the hold. | | `reason` | text | The reason given. | ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`read_only`](https://headhoncho.app/docs/api/errors#read_only) | 403 | This credential may read this area but not change it. | | [`not_found`](https://headhoncho.app/docs/api/errors#not_found) | 404 | No such record in the companies this credential reaches. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`missing_idempotency_key`](https://headhoncho.app/docs/api/errors#missing_idempotency_key) | 400 | Send an Idempotency-Key header on every command. | | [`idempotency_mismatch`](https://headhoncho.app/docs/api/errors#idempotency_mismatch) | 409 | This Idempotency-Key was used with a different body. | | [`idempotency_in_progress`](https://headhoncho.app/docs/api/errors#idempotency_in_progress) | 409 | A command with this Idempotency-Key is still running. Wait a moment and send it again. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [Close balance](https://headhoncho.app/docs/api/close_balance): Close what a technician is owed for the jobs you name, or for everything open through a day, as one payout netted against the cash they hold. - [Record payout](https://headhoncho.app/docs/api/record_payout): Record money paid to a technician, or paid in by one, that names no jobs. It moves their balance and closes no particular job. - [Void closed balance](https://headhoncho.app/docs/api/void_closed_balance): Undo a balance close or a payout entered wrong. Its jobs open again, and it stays on the list, marked voided, with why. - [Put back job](https://headhoncho.app/docs/api/put_back_job): Let a held-back job count in the technician's next balance close again. - [Post monthly pay](https://headhoncho.app/docs/api/post_monthly_pay): Add a month of pay to the balance of every active technician on a monthly rate. A month is posted once, however often this is sent. - The same records in the app: [the Finance panel](https://headhoncho.app/docs/finance). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "accepted": true, "worker_id": "wrk_7a12", "position": 88520, "job_id": "job_1138", "number": 1138, "hold_id": "hld_0c3e", "reason": "Customer disputes the bill" } ``` ### cURL ```bash curl -X POST "https://api.headhoncho.app/api/v1/commands/hold-back-job" \ -H "Authorization: Bearer hh_live_..." \ -H "Idempotency-Key: 6f1d2c9e-1b7a-4c1e-9a52-0d3f8e4b7a10" \ -H "Content-Type: application/json" \ -d '{ "worker_id": "wrk_7a12", "job_id": "job_1138", "reason": "Customer disputes the bill" }' ``` ### Python ```python import requests import uuid response = requests.post( "https://api.headhoncho.app/api/v1/commands/hold-back-job", headers={ "Authorization": "Bearer hh_live_...", "Idempotency-Key": str(uuid.uuid4()), }, json={ "worker_id": "wrk_7a12", "job_id": "job_1138", "reason": "Customer disputes the bill", }, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/commands/hold-back-job", { method: "POST", headers: { Authorization: "Bearer hh_live_...", "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "worker_id": "wrk_7a12", "job_id": "job_1138", "reason": "Customer disputes the bill" }), }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: hold_back_job Arguments: worker_id (id, required), job_id (id, required), reason (text, optional) Access: do on Money Hints: readOnly=false, destructive=false, idempotent=true, openWorld=false Try asking: "Using HeadHoncho, hold back job with worker_id wrk_7a12 and job_id job_1138 and reason Customer disputes the bill." ``` --- # Put back job Put back job is a command in the HeadHoncho API. Let a held-back job count in the technician's next balance close again. Page: https://headhoncho.app/docs/api/put_back_job | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **Put back job**, HeadHoncho API v1. It is a command, sent to the base address `https://api.headhoncho.app`. `POST /api/v1/commands/put-back-job` The key needs the **Money** area at **do**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). It runs the app's own command `put-back-job`. Send an `Idempotency-Key` header with every call: the same key with the same body returns the first answer and runs nothing twice. See [the model](https://headhoncho.app/docs/api/model#idempotency). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `worker_id` | id, in the JSON body | Yes | The technician, from Who am I's technicians. | `wrk_7a12` | | `job_id` | id, in the JSON body | Yes | The job id, or its number. | `job_1138` | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back accepted, worker_id, job_id, number, hold_id and position. A job that is not held back is refused by name. It never deletes anything. It changes only what the command names, and it writes the change to the job's history with who asked for it. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `accepted` | true or false | True when the command ran. A command that cannot run is an error instead. | | `worker_id` | id (text) | The id of the worker. | | `position` | whole number | Where the change landed in the event log. Pass it as `after` on a read to see your own write. | | `job_id` | id (text) | The id of the job. | | `number` | whole number | The number people say out loud, such as the job number. | | `hold_id` | id (text) | The id of the hold. | ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`read_only`](https://headhoncho.app/docs/api/errors#read_only) | 403 | This credential may read this area but not change it. | | [`not_found`](https://headhoncho.app/docs/api/errors#not_found) | 404 | No such record in the companies this credential reaches. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`missing_idempotency_key`](https://headhoncho.app/docs/api/errors#missing_idempotency_key) | 400 | Send an Idempotency-Key header on every command. | | [`idempotency_mismatch`](https://headhoncho.app/docs/api/errors#idempotency_mismatch) | 409 | This Idempotency-Key was used with a different body. | | [`idempotency_in_progress`](https://headhoncho.app/docs/api/errors#idempotency_in_progress) | 409 | A command with this Idempotency-Key is still running. Wait a moment and send it again. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [Close balance](https://headhoncho.app/docs/api/close_balance): Close what a technician is owed for the jobs you name, or for everything open through a day, as one payout netted against the cash they hold. - [Record payout](https://headhoncho.app/docs/api/record_payout): Record money paid to a technician, or paid in by one, that names no jobs. It moves their balance and closes no particular job. - [Void closed balance](https://headhoncho.app/docs/api/void_closed_balance): Undo a balance close or a payout entered wrong. Its jobs open again, and it stays on the list, marked voided, with why. - [Hold back job](https://headhoncho.app/docs/api/hold_back_job): Keep one job out of a technician's balance closes until you put it back, with why. Its cut, parts and cash wait together. - [Post monthly pay](https://headhoncho.app/docs/api/post_monthly_pay): Add a month of pay to the balance of every active technician on a monthly rate. A month is posted once, however often this is sent. - The same records in the app: [the Finance panel](https://headhoncho.app/docs/finance). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "accepted": true, "worker_id": "wrk_7a12", "position": 88520, "job_id": "job_1138", "number": 1138, "hold_id": "hld_0c3e" } ``` ### cURL ```bash curl -X POST "https://api.headhoncho.app/api/v1/commands/put-back-job" \ -H "Authorization: Bearer hh_live_..." \ -H "Idempotency-Key: 6f1d2c9e-1b7a-4c1e-9a52-0d3f8e4b7a10" \ -H "Content-Type: application/json" \ -d '{ "worker_id": "wrk_7a12", "job_id": "job_1138" }' ``` ### Python ```python import requests import uuid response = requests.post( "https://api.headhoncho.app/api/v1/commands/put-back-job", headers={ "Authorization": "Bearer hh_live_...", "Idempotency-Key": str(uuid.uuid4()), }, json={ "worker_id": "wrk_7a12", "job_id": "job_1138", }, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/commands/put-back-job", { method: "POST", headers: { Authorization: "Bearer hh_live_...", "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "worker_id": "wrk_7a12", "job_id": "job_1138" }), }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: put_back_job Arguments: worker_id (id, required), job_id (id, required) Access: do on Money Hints: readOnly=false, destructive=false, idempotent=true, openWorld=false Try asking: "Using HeadHoncho, put back job with worker_id wrk_7a12 and job_id job_1138." ``` --- # Post monthly pay Post monthly pay is a command in the HeadHoncho API. Add a month of pay to the balance of every active technician on a monthly rate. A month is posted once, however often this is sent. Page: https://headhoncho.app/docs/api/post_monthly_pay | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **Post monthly pay**, HeadHoncho API v1. It is a command, sent to the base address `https://api.headhoncho.app`. `POST /api/v1/commands/post-monthly-pay` The key needs the **Money** area at **do**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). It runs the app's own command `post-monthly-pay`. Send an `Idempotency-Key` header with every call: the same key with the same body returns the first answer and runs nothing twice. See [the model](https://headhoncho.app/docs/api/model#idempotency). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `month` | date, in the JSON body | No | Any day in the month. Default: this month. | `2026-10-01` | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back accepted, posted (the new ledger lines), month and position. It never deletes anything. It changes only what the command names, and it writes the change to the job's history with who asked for it. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `accepted` | true or false | True when the command ran. A command that cannot run is an error instead. | | `posted` | list of text | The posted. | | `month` | date (YYYY-MM-DD) | The first day of the month. | | `position` | whole number | Where the change landed in the event log. Pass it as `after` on a read to see your own write. | ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`read_only`](https://headhoncho.app/docs/api/errors#read_only) | 403 | This credential may read this area but not change it. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`missing_idempotency_key`](https://headhoncho.app/docs/api/errors#missing_idempotency_key) | 400 | Send an Idempotency-Key header on every command. | | [`idempotency_mismatch`](https://headhoncho.app/docs/api/errors#idempotency_mismatch) | 409 | This Idempotency-Key was used with a different body. | | [`idempotency_in_progress`](https://headhoncho.app/docs/api/errors#idempotency_in_progress) | 409 | A command with this Idempotency-Key is still running. Wait a moment and send it again. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [Close balance](https://headhoncho.app/docs/api/close_balance): Close what a technician is owed for the jobs you name, or for everything open through a day, as one payout netted against the cash they hold. - [Record payout](https://headhoncho.app/docs/api/record_payout): Record money paid to a technician, or paid in by one, that names no jobs. It moves their balance and closes no particular job. - [Void closed balance](https://headhoncho.app/docs/api/void_closed_balance): Undo a balance close or a payout entered wrong. Its jobs open again, and it stays on the list, marked voided, with why. - [Hold back job](https://headhoncho.app/docs/api/hold_back_job): Keep one job out of a technician's balance closes until you put it back, with why. Its cut, parts and cash wait together. - [Put back job](https://headhoncho.app/docs/api/put_back_job): Let a held-back job count in the technician's next balance close again. - The same records in the app: [the Finance panel](https://headhoncho.app/docs/finance). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "accepted": true, "posted": [ "led_9f01", "led_9f02" ], "month": "2026-10-01", "position": 88530 } ``` ### cURL ```bash curl -X POST "https://api.headhoncho.app/api/v1/commands/post-monthly-pay" \ -H "Authorization: Bearer hh_live_..." \ -H "Idempotency-Key: 6f1d2c9e-1b7a-4c1e-9a52-0d3f8e4b7a10" \ -H "Content-Type: application/json" \ -d '{ "month": "2026-10-01" }' ``` ### Python ```python import requests import uuid response = requests.post( "https://api.headhoncho.app/api/v1/commands/post-monthly-pay", headers={ "Authorization": "Bearer hh_live_...", "Idempotency-Key": str(uuid.uuid4()), }, json={ "month": "2026-10-01", }, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/commands/post-monthly-pay", { method: "POST", headers: { Authorization: "Bearer hh_live_...", "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "month": "2026-10-01" }), }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: post_monthly_pay Arguments: month (date, optional) Access: do on Money Hints: readOnly=false, destructive=false, idempotent=true, openWorld=false Try asking: "Using HeadHoncho, post monthly pay with month 2026-10-01." ``` --- # List tables List tables is a read in the HeadHoncho API. Every raw table, by the provider that produced it, with its columns, its grain and whether this company has it connected. Page: https://headhoncho.app/docs/api/list_tables | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **List tables**, HeadHoncho API v1. It is a read, sent to the base address `https://api.headhoncho.app`. `GET /api/v1/data/tables` The key needs the **Raw data** area at **read**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). Send your key as `Authorization: Bearer hh_live_...`. See [API keys](https://headhoncho.app/docs/api/keys). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `company_id` | id, in the query | No | Default: the first company the credential reaches. | `cmp_14f5` | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back schemas, one per provider (google_ads, meta_ads, microsoft_ads, callrail, headhoncho), each with its tables: key, name, grain, caveat, columns (key, label, kind), the date column if any, and available. It never changes a record. It only reads the companies the key reaches. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `schemas` | list of objects | The schemas. | | `schemas[].key` | text | A short code for this item. Match on it in code. | | `schemas[].label` | text | The name the app shows for it. | | `schemas[].available` | true or false | True when this is connected and can be read. | | `schemas[].tables` | list of objects | The tables. | | `schemas[].tables[].key` | text | A short code for this item. Match on it in code. | | `schemas[].tables[].name` | text | The name, as the app shows it. | | `schemas[].tables[].grain` | text | What one row stands for. | | `schemas[].tables[].date_column` | text | The date column. | | `schemas[].tables[].columns` | list of objects | The columns. | | `schemas[].tables[].columns[].key` | text | A short code for this item. Match on it in code. | | `schemas[].tables[].columns[].label` | text | The name the app shows for it. | | `schemas[].tables[].columns[].kind` | text | What sort of thing this is. | ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`not_found`](https://headhoncho.app/docs/api/errors#not_found) | 404 | No such record in the companies this credential reaches. | | [`out_of_scope`](https://headhoncho.app/docs/api/errors#out_of_scope) | 404 | No such company in the companies this credential reaches. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | | [`not_connected`](https://headhoncho.app/docs/api/errors#not_connected) | 409 | This company has not connected that provider yet. | ## Related - [Read table](https://headhoncho.app/docs/api/read_table): Rows of one raw table for one company and a date range, exactly as the provider reported them. No joins, no derived figures. - [Export table](https://headhoncho.app/docs/api/export_table): One raw table as a CSV file for a company and a date range, up to 50,000 rows, with its caveat in the last lines. - The same records in the app: [the Raw data board](https://headhoncho.app/docs/marketing/raw-data). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "schemas": [ { "key": "google_ads", "label": "Google Ads", "available": true, "tables": [ { "key": "google_ads.spend_by_day", "name": "spend_by_day", "grain": "One row per campaign per day.", "date_column": "date", "columns": [ { "key": "date", "label": "Date", "kind": "date" }, { "key": "campaign_name", "label": "Campaign", "kind": "text" }, { "key": "cost", "label": "Spend", "kind": "money" }, { "key": "clicks", "label": "Clicks", "kind": "number" } ] } ] }, { "key": "callrail", "label": "CallRail", "available": true, "tables": [ { "key": "callrail.calls", "name": "calls", "grain": "One row per tracked call.", "date_column": "started_at", "columns": [ { "key": "started_at", "label": "Started", "kind": "datetime" }, { "key": "customer_phone", "label": "Caller", "kind": "text" }, { "key": "has_identifier", "label": "Click id", "kind": "boolean" } ] } ] } ] } ``` ### cURL ```bash curl "https://api.headhoncho.app/api/v1/data/tables?company_id=cmp_14f5" \ -H "Authorization: Bearer hh_live_..." ``` ### Python ```python import requests response = requests.get( "https://api.headhoncho.app/api/v1/data/tables", headers={"Authorization": "Bearer hh_live_..."}, params={ "company_id": "cmp_14f5", }, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/data/tables?company_id=cmp_14f5", { headers: { Authorization: "Bearer hh_live_..." }, }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: list_tables Arguments: company_id (id, optional) Access: read on Raw data Hints: readOnly=true, destructive=false, idempotent=true, openWorld=false Try asking: "Using HeadHoncho, list tables with company_id cmp_14f5." ``` --- # Read table Read table is a read in the HeadHoncho API. Rows of one raw table for one company and a date range, exactly as the provider reported them. No joins, no derived figures. Page: https://headhoncho.app/docs/api/read_table | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **Read table**, HeadHoncho API v1. It is a read, sent to the base address `https://api.headhoncho.app`. `GET /api/v1/data/tables/{key}` The key needs the **Raw data** area at **read**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). Send your key as `Authorization: Bearer hh_live_...`. See [API keys](https://headhoncho.app/docs/api/keys). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `key` | text, in the path | Yes | A table key from List tables. | `google_ads.spend_by_day` | | `company_id` | id, in the query | No | Default: the first company the credential reaches. | `cmp_14f5` | | `from` | date, in the query | No | For tables with a date column. Default: this month. | `2026-10-01` | | `to` | date, in the query | No | The last day, inclusive. | `2026-10-14` | | `order` | text, in the query | No | A column key. Default: the table's own order. | `date` | | `direction` | text, in the query | No | asc or desc. One of `asc`, `desc`. | `desc` | | `limit` | number, in the query | No | 1 to 1000. Default 200. | `200` | | `offset` | number, in the query | No | Rows to skip. Default 0. | `0` | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back table (its definition), rows, total, limit, offset, and the caveat the screen prints beside this table, because a row that leaves without its sentence will be misread. It never changes a record. It only reads the companies the key reaches. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `table` | object | The table. | | `table.key` | text | A short code for this item. Match on it in code. | | `table.grain` | text | What one row stands for. | | `table.caveat` | text | A warning about how far to trust the figures. | | `rows` | list of objects | The rows. | | `rows[].date` | date (YYYY-MM-DD) | The day this row is for. | | `rows[].campaign_name` | text | The ad campaign's name. | | `rows[].cost` | money (number) | What it cost. In the company's currency. | | `rows[].clicks` | whole number | How many clicks. | | `rows[].impressions` | whole number | How many times the ad was shown. | | `rows[].currency` | text | The three-letter currency code (ISO 4217). Every money value in the answer is in it. | | `total` | whole number | The total, in the company's currency. | | `limit` | whole number | The most rows this page holds. | | `offset` | whole number | How many rows were skipped before this page. | ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`not_found`](https://headhoncho.app/docs/api/errors#not_found) | 404 | No such record in the companies this credential reaches. | | [`out_of_scope`](https://headhoncho.app/docs/api/errors#out_of_scope) | 404 | No such company in the companies this credential reaches. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | | [`not_connected`](https://headhoncho.app/docs/api/errors#not_connected) | 409 | This company has not connected that provider yet. | ## Related - [List tables](https://headhoncho.app/docs/api/list_tables): Every raw table, by the provider that produced it, with its columns, its grain and whether this company has it connected. - [Export table](https://headhoncho.app/docs/api/export_table): One raw table as a CSV file for a company and a date range, up to 50,000 rows, with its caveat in the last lines. - The same records in the app: [the Raw data board](https://headhoncho.app/docs/marketing/raw-data). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "table": { "key": "google_ads.spend_by_day", "grain": "One row per campaign per day.", "caveat": "Spend is what Google reported for the day; it can move for 48 hours." }, "rows": [ { "date": "2026-10-13", "campaign_name": "Moving - Bloomington", "cost": 212.4, "clicks": 41, "impressions": 1904, "currency": "USD" }, { "date": "2026-10-12", "campaign_name": "Moving - Bloomington", "cost": 198.05, "clicks": 37, "impressions": 1771, "currency": "USD" } ], "total": 28, "limit": 200, "offset": 0 } ``` ### cURL ```bash curl "https://api.headhoncho.app/api/v1/data/tables/google_ads.spend_by_day?company_id=cmp_14f5&from=2026-10-01" \ -H "Authorization: Bearer hh_live_..." ``` ### Python ```python import requests response = requests.get( "https://api.headhoncho.app/api/v1/data/tables/google_ads.spend_by_day", headers={"Authorization": "Bearer hh_live_..."}, params={ "company_id": "cmp_14f5", "from": "2026-10-01", }, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/data/tables/google_ads.spend_by_day?company_id=cmp_14f5&from=2026-10-01", { headers: { Authorization: "Bearer hh_live_..." }, }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: read_table Arguments: key (text, required), company_id (id, optional), from (date, optional), to (date, optional), order (text, optional), direction (text, optional), limit (number, optional), offset (number, optional) Access: read on Raw data Hints: readOnly=true, destructive=false, idempotent=true, openWorld=false Try asking: "Using HeadHoncho, read table with key google_ads.spend_by_day and company_id cmp_14f5." ``` --- # Export table Export table is a read in the HeadHoncho API. One raw table as a CSV file for a company and a date range, up to 50,000 rows, with its caveat in the last lines. Page: https://headhoncho.app/docs/api/export_table | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **Export table**, HeadHoncho API v1. It is a read, sent to the base address `https://api.headhoncho.app`. `GET /api/v1/data/tables/{key}/export` The key needs the **Raw data** area at **read**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). Send your key as `Authorization: Bearer hh_live_...`. See [API keys](https://headhoncho.app/docs/api/keys). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `key` | text, in the path | Yes | A table key from List tables. | `callrail.calls` | | `company_id` | id, in the query | No | Default: the first company the credential reaches. | `cmp_14f5` | | `from` | date, in the query | No | Default: this month. | `2026-10-01` | | `to` | date, in the query | No | The last day, inclusive. | `2026-10-14` | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back Over the API: the CSV itself (text/csv). Over MCP: a download link that works once for five minutes, so the file never passes through the AI. It never changes a record. It only reads the companies the key reaches. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `download` | object | The download. | | `download.url` | text | The link. | | `download.expires_in` | whole number | Seconds until the link stops working. | | `download.filename` | text | The name of the file. | ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`not_found`](https://headhoncho.app/docs/api/errors#not_found) | 404 | No such record in the companies this credential reaches. | | [`out_of_scope`](https://headhoncho.app/docs/api/errors#out_of_scope) | 404 | No such company in the companies this credential reaches. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | | [`not_connected`](https://headhoncho.app/docs/api/errors#not_connected) | 409 | This company has not connected that provider yet. | ## Related - [List tables](https://headhoncho.app/docs/api/list_tables): Every raw table, by the provider that produced it, with its columns, its grain and whether this company has it connected. - [Read table](https://headhoncho.app/docs/api/read_table): Rows of one raw table for one company and a date range, exactly as the provider reported them. No joins, no derived figures. - The same records in the app: [the Raw data board](https://headhoncho.app/docs/marketing/raw-data). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer This is the answer over MCP. Over the API the answer is the file itself, as text/csv. ```json { "download": { "url": "https://api.headhoncho.app/api/v1/data/tables/callrail.calls/export?company_id=cmp_14f5&from=2026-10-01&to=2026-10-14&once=k7Qm...", "expires_in": 300, "filename": "callrail-calls-20261014-0915.csv" } } ``` ### cURL ```bash curl "https://api.headhoncho.app/api/v1/data/tables/callrail.calls/export?company_id=cmp_14f5&from=2026-10-01" \ -H "Authorization: Bearer hh_live_..." -o file.csv ``` ### Python ```python import requests response = requests.get( "https://api.headhoncho.app/api/v1/data/tables/callrail.calls/export", headers={"Authorization": "Bearer hh_live_..."}, params={ "company_id": "cmp_14f5", "from": "2026-10-01", }, ) response.raise_for_status() open("file.csv", "wb").write(response.content) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/data/tables/callrail.calls/export?company_id=cmp_14f5&from=2026-10-01", { headers: { Authorization: "Bearer hh_live_..." }, }); const data = await response.text(); console.log(data); ``` ### Your AI ```text Tool: export_table Arguments: key (text, required), company_id (id, optional), from (date, optional), to (date, optional) Access: read on Raw data Hints: readOnly=true, destructive=false, idempotent=true, openWorld=false Try asking: "Using HeadHoncho, export table with key callrail.calls and company_id cmp_14f5." ``` --- # Get job conversion Get job conversion is a read in the HeadHoncho API. What this job told the ad platform it was worth: the click it came from, each conversion sent, its value and its basis, and what Google did with it. Page: https://headhoncho.app/docs/api/get_job_conversion | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **Get job conversion**, HeadHoncho API v1. It is a read, sent to the base address `https://api.headhoncho.app`. `GET /api/v1/jobs/{job_id}/conversion` The key needs the **Click IDs and conversions** area at **read**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). Send your key as `Authorization: Bearer hh_live_...`. See [API keys](https://headhoncho.app/docs/api/keys). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `job_id` | id, in the path | Yes | The job id, or its number. | `job_1138` | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back click: the network, the click id, the tracked call and its time, or null with why when the job came from no click. value_rules: how this company values a booked and a paid job. conversions: one per stage sent, with value, based_on, state (waiting, sent, accepted, refused, too_old, no_credits, taken_back) and at. total_sent is the sum Google accepted. It never changes a record. It only reads the companies the key reaches. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `job` | object | The job. | | `job.id` | id (text) | The id of this record. Ids are opaque text: keep them exactly as given. | | `job.number` | whole number | The number people say out loud, such as the job number. | | `click` | object | The click. | | `click.network` | text | The ad platform the row came from. | | `click.id` | id (text) | The id of this record. Ids are opaque text: keep them exactly as given. | | `click.call_id` | id (text) | The id of the call. | | `click.call_at` | time (ISO 8601, with offset) | When the call happened. Carries its offset from UTC; `Z` is UTC. | | `click.match` | text | Whether the call was matched to a click. | | `value_rules` | object | The value rules. | | `value_rules.booked_job` | text | The booked job. | | `value_rules.paid_job` | text | The paid job. | | `value_rules.paid_when` | text | The paid when. | | `currency` | text | The three-letter currency code (ISO 4217). Every money value in the answer is in it. | | `conversions` | list of objects | The conversions. | | `conversions[].goal` | text | The goal Google Ads is told this job achieved. | | `conversions[].stage` | text | How far along it is, as a code. | | `conversions[].value` | money (number) | The value. In the company's currency. | | `conversions[].based_on` | text | What the figure is based on. | | `conversions[].state` | text | The state or region. | | `conversions[].state_label` | text | The state in words, as the app shows it. | | `conversions[].at` | time (ISO 8601, with offset) | The moment it happened. Carries its offset from UTC; `Z` is UTC. | | `total_sent` | money (number) | The total sent. In the company's currency. | ## No click, no conversion A job that did not come from an ad click answers click: null and a why, for example "The call carried no click id" or "Entered by hand". Nothing is sent for it, and conversions is empty. ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`not_found`](https://headhoncho.app/docs/api/errors#not_found) | 404 | No such record in the companies this credential reaches. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [Get click id report](https://headhoncho.app/docs/api/get_click_id_report): The Google Click ID report: one row per job that opened or closed in the range, with its click id, its tracked call, its total and its profit. - [Export click id report](https://headhoncho.app/docs/api/export_click_id_report): The Google Click ID report as a file: the agency's sheet, or the Google Ads offline conversion upload file, ready to upload. - The same records in the app: [offline conversion tracking](https://headhoncho.app/offline-conversion-tracking). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "job": { "id": "job_1138", "number": 1138 }, "click": { "network": "google_ads", "id": "Cj0KCQjw...", "call_id": "CAL8f2e1", "call_at": "2026-10-11T18:22:03Z", "match": "matched" }, "value_rules": { "booked_job": "fixed", "paid_job": "net_profit", "paid_when": "first_payment" }, "currency": "USD", "conversions": [ { "goal": "Booked job", "stage": "booked", "value": 100.0, "based_on": "a set amount", "state": "accepted", "state_label": "Accepted by Google", "at": "2026-10-12T06:00:00Z" }, { "goal": "Paid job", "stage": "paid", "value": 610.0, "based_on": "profit after the subcontractor", "state": "waiting", "state_label": "Waiting for the first payment", "at": null } ], "total_sent": 1450.0 } ``` ### cURL ```bash curl "https://api.headhoncho.app/api/v1/jobs/job_1138/conversion" \ -H "Authorization: Bearer hh_live_..." ``` ### Python ```python import requests response = requests.get( "https://api.headhoncho.app/api/v1/jobs/job_1138/conversion", headers={"Authorization": "Bearer hh_live_..."}, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/jobs/job_1138/conversion", { headers: { Authorization: "Bearer hh_live_..." }, }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: get_job_conversion Arguments: job_id (id, required) Access: read on Click IDs and conversions Hints: readOnly=true, destructive=false, idempotent=true, openWorld=false Try asking: "Using HeadHoncho, get job conversion with job_id job_1138." ``` --- # Get click id report Get click id report is a read in the HeadHoncho API. The Google Click ID report: one row per job that opened or closed in the range, with its click id, its tracked call, its total and its profit. Page: https://headhoncho.app/docs/api/get_click_id_report | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **Get click id report**, HeadHoncho API v1. It is a read, sent to the base address `https://api.headhoncho.app`. `GET /api/v1/reports/google-click-ids` The key needs the **Click IDs and conversions** area at **read**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). Send your key as `Authorization: Bearer hh_live_...`. See [API keys](https://headhoncho.app/docs/api/keys). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `from` | date, in the query | Yes | The first day. A job is in the range when it opened or closed in it. | `2026-10-01` | | `to` | date, in the query | Yes | The last day, inclusive. | `2026-10-31` | | `company_id` | id, in the query | No | Default: every company the credential reaches. | `cmp_14f5` | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back rows in the agency's sixteen columns, and totals: jobs, closed, with_click_id, with_call, total, company_total; plus calls, calls_with_click_id and calls_without_click_id for the range, because a call with no click id can never be in any file, whatever anyone does downstream. It never changes a record. It only reads the companies the key reaches. Why this report is in the API: Owner, 2026-10-14: the one report in the starter, because the file is handed to Google by the customer and must exist outside the app. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `from` | date (YYYY-MM-DD) | The first day of the range, inclusive. | | `to` | date (YYYY-MM-DD) | The last day of the range, inclusive. | | `rows` | list of objects | The rows. | | `rows[].ticket` | whole number | The job number the ticket shows. | | `rows[].status` | text | The job status. | | `rows[].customer_phone` | text | The customer's phone number. Hidden when the key hides personal details. | | `rows[].start_date` | date and time (company time zone) | The start date. | | `rows[].close_date` | date and time (company time zone) | The close date. | | `rows[].total` | money (number) | The total, in the company's currency. | | `rows[].company_total` | money (number) | The company total. In the company's currency. | | `rows[].job_source` | text | Where the job came from, such as Google Ads. | | `rows[].gclid` | text | The Google click id the call or visit carried. | | `rows[].callrail_call_id` | id (text) | The id of the callrail call. | | `rows[].campaign_id` | id (text) | The ad platform's id for the campaign. | | `rows[].callrail_call_start` | date and time (company time zone) | The callrail call start. | | `rows[].lead_source` | text | How the lead first reached the business. | | `rows[].paid_date` | date (YYYY-MM-DD) | The paid date. | | `rows[].time_zone` | text | The company's time zone name, such as America/Chicago. | | `rows[].callrail_source_name` | text | The callrail source name. | | `totals` | object | The totals. | | `totals.jobs` | whole number | The jobs. | | `totals.closed` | whole number | True when the job is closed. | | `totals.with_click_id` | whole number | The with click id. | | `totals.with_call` | whole number | The with call. | | `totals.total` | money (number) | The total, in the company's currency. | | `totals.company_total` | money (number) | The company total. In the company's currency. | | `calls` | whole number | How many calls. | | `calls_with_click_id` | whole number | The calls with click id. | | `calls_without_click_id` | whole number | The calls without click id. | ## Turned on first The report is off until a person turns it on in Statistics › Reports; until then this call is refused with report_off. While it is on, each job matched to its call or click costs one credit, once, for jobs opened from the day it was first turned on. A job whose match is waiting for credits keeps its row, with gclid and callrail_call_id masked: their first and last characters around an ellipsis. ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`not_found`](https://headhoncho.app/docs/api/errors#not_found) | 404 | No such record in the companies this credential reaches. | | [`out_of_scope`](https://headhoncho.app/docs/api/errors#out_of_scope) | 404 | No such company in the companies this credential reaches. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | | [`report_off`](https://headhoncho.app/docs/api/errors#report_off) | 409 | This report is turned off. Turn it on in Statistics › Reports. | ## Related - [Get job conversion](https://headhoncho.app/docs/api/get_job_conversion): What this job told the ad platform it was worth: the click it came from, each conversion sent, its value and its basis, and what Google did with it. - [Export click id report](https://headhoncho.app/docs/api/export_click_id_report): The Google Click ID report as a file: the agency's sheet, or the Google Ads offline conversion upload file, ready to upload. - The same records in the app: [offline conversion tracking](https://headhoncho.app/offline-conversion-tracking). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "from": "2026-10-01", "to": "2026-10-31", "rows": [ { "ticket": 1138, "status": "Closed", "customer_phone": "+12175550142", "start_date": "2026-10-11 13:25", "close_date": "2026-10-16 11:40", "total": 1450.0, "company_total": 610.0, "job_source": "Google Ads", "gclid": "Cj0KCQjw...", "callrail_call_id": "CAL8f2e1", "campaign_id": "2184930112", "callrail_call_start": "2026-10-11 13:22", "lead_source": "call", "paid_date": "2026-10-16", "time_zone": "America/Chicago", "callrail_source_name": "pool - google ads" } ], "totals": { "jobs": 64, "closed": 41, "with_click_id": 37, "with_call": 52, "total": 71240.0, "company_total": 28410.5 }, "calls": 118, "calls_with_click_id": 69, "calls_without_click_id": 49 } ``` ### cURL ```bash curl "https://api.headhoncho.app/api/v1/reports/google-click-ids?from=2026-10-01&to=2026-10-31&company_id=cmp_14f5" \ -H "Authorization: Bearer hh_live_..." ``` ### Python ```python import requests response = requests.get( "https://api.headhoncho.app/api/v1/reports/google-click-ids", headers={"Authorization": "Bearer hh_live_..."}, params={ "from": "2026-10-01", "to": "2026-10-31", "company_id": "cmp_14f5", }, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/reports/google-click-ids?from=2026-10-01&to=2026-10-31&company_id=cmp_14f5", { headers: { Authorization: "Bearer hh_live_..." }, }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: get_click_id_report Arguments: from (date, required), to (date, required), company_id (id, optional) Access: read on Click IDs and conversions Hints: readOnly=true, destructive=false, idempotent=true, openWorld=false Try asking: "Using HeadHoncho, get click id report with from 2026-10-01 and to 2026-10-31 and company_id cmp_14f5." ``` --- # Export click id report Export click id report is a read in the HeadHoncho API. The Google Click ID report as a file: the agency's sheet, or the Google Ads offline conversion upload file, ready to upload. Page: https://headhoncho.app/docs/api/export_click_id_report | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **Export click id report**, HeadHoncho API v1. It is a read, sent to the base address `https://api.headhoncho.app`. `GET /api/v1/reports/google-click-ids/export` The key needs the **Click IDs and conversions** area at **read**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). Send your key as `Authorization: Bearer hh_live_...`. See [API keys](https://headhoncho.app/docs/api/keys). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `from` | date, in the query | Yes | The first day. | `2026-10-01` | | `to` | date, in the query | Yes | The last day, inclusive. | `2026-10-31` | | `company_id` | id, in the query | No | For google_ads, the one account the file is for. Default: the first company. | `cmp_14f5` | | `output` | text, in the query | No | csv (the agency's sixteen columns, default) or google_ads (the upload file, one company at a time). One of `csv`, `google_ads`. | `csv` | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back Over the API: the file (text/csv). Over MCP: a download link that works once for five minutes. It never changes a record. It only reads the companies the key reaches. Why this report is in the API: Owner, 2026-10-14: same decision as the report. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `download` | object | The download. | | `download.url` | text | The link. | | `download.expires_in` | whole number | Seconds until the link stops working. | | `download.filename` | text | The name of the file. | ## Turned on first The csv output is the Click ID report, so it follows the report's switch: off, the call is refused with report_off. The google_ads output is the upload file and does not. ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`not_found`](https://headhoncho.app/docs/api/errors#not_found) | 404 | No such record in the companies this credential reaches. | | [`out_of_scope`](https://headhoncho.app/docs/api/errors#out_of_scope) | 404 | No such company in the companies this credential reaches. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | | [`report_off`](https://headhoncho.app/docs/api/errors#report_off) | 409 | This report is turned off. Turn it on in Statistics › Reports. | ## Related - [Get job conversion](https://headhoncho.app/docs/api/get_job_conversion): What this job told the ad platform it was worth: the click it came from, each conversion sent, its value and its basis, and what Google did with it. - [Get click id report](https://headhoncho.app/docs/api/get_click_id_report): The Google Click ID report: one row per job that opened or closed in the range, with its click id, its tracked call, its total and its profit. - The same records in the app: [offline conversion tracking](https://headhoncho.app/offline-conversion-tracking). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer This is the answer over MCP. Over the API the answer is the file itself, as text/csv. ```json { "download": { "url": "https://api.headhoncho.app/api/v1/reports/google-click-ids/export?from=2026-10-01&to=2026-10-31&output=google_ads&company_id=cmp_14f5&once=p2Xw...", "expires_in": 300, "filename": "google-ads-conversions-20261014-0915.csv" } } ``` ### cURL ```bash curl "https://api.headhoncho.app/api/v1/reports/google-click-ids/export?from=2026-10-01&to=2026-10-31&company_id=cmp_14f5&output=csv" \ -H "Authorization: Bearer hh_live_..." -o file.csv ``` ### Python ```python import requests response = requests.get( "https://api.headhoncho.app/api/v1/reports/google-click-ids/export", headers={"Authorization": "Bearer hh_live_..."}, params={ "from": "2026-10-01", "to": "2026-10-31", "company_id": "cmp_14f5", "output": "csv", }, ) response.raise_for_status() open("file.csv", "wb").write(response.content) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/reports/google-click-ids/export?from=2026-10-01&to=2026-10-31&company_id=cmp_14f5&output=csv", { headers: { Authorization: "Bearer hh_live_..." }, }); const data = await response.text(); console.log(data); ``` ### Your AI ```text Tool: export_click_id_report Arguments: from (date, required), to (date, required), company_id (id, optional), output (text, optional) Access: read on Click IDs and conversions Hints: readOnly=true, destructive=false, idempotent=true, openWorld=false Try asking: "Using HeadHoncho, export click id report with from 2026-10-01 and to 2026-10-31 and company_id cmp_14f5." ``` --- # List technicians List technicians is a read in the HeadHoncho API. Everyone the company sends jobs to: technicians and subcontractors, with contact details, the job types they take and the cut they work on. Page: https://headhoncho.app/docs/api/list_technicians | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **List technicians**, HeadHoncho API v1. It is a read, sent to the base address `https://api.headhoncho.app`. `GET /api/v1/technicians` The key needs the **Team** area at **read**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). Send your key as `Authorization: Bearer hh_live_...`. See [API keys](https://headhoncho.app/docs/api/keys). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `role` | text, in the query | No | technician or subcontractor. Default: both. One of `technician`, `subcontractor`. | `subcontractor` | | `active` | text, in the query | No | yes for people on the roster now, no for people taken off it. Default: both. One of `yes`, `no`. | `yes` | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back items, one person each in the Get a team member shape, active people first and then by name; count, how many. A technician belongs to the workspace, so the list is the same whichever company the key reaches. It never changes a record. It only reads the companies the key reaches. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `items` | list of objects | The rows on this page. | | `items[].id` | id (text) | The id of this record. Ids are opaque text: keep them exactly as given. | | `items[].role` | text | One of `technician`, `subcontractor`. | | `items[].name` | text | The name, as the app shows it. | | `items[].first_name` | text | The first name. | | `items[].last_name` | text | The last name. | | `items[].email` | text | The email. | | `items[].phone` | text | A phone number. Hidden when the key hides personal details. | | `items[].active` | true or false | One of `yes`, `no`. | | `items[].is_team_lead` | true or false | True when it is team lead. | | `items[].monthly_pay` | value or null | The monthly pay. | | `items[].hired_on` | date (YYYY-MM-DD) | The date it was hired. | | `items[].ended_on` | value or null | The date it was ended. | | `items[].business_name` | text | The business name. | | `items[].default_cut` | object | The default cut. | | `items[].default_cut.basis` | text | The basis. | | `items[].default_cut.value` | money (number) | The value. In the company's currency. | | `items[].default_cut.label` | text | The name the app shows for it. | | `items[].job_types` | list of objects | The job types. | | `items[].job_types[].id` | id (text) | The id of this record. Ids are opaque text: keep them exactly as given. | | `items[].job_types[].name` | text | The name, as the app shows it. | | `items[].any_job_type` | true or false | The any job type. | | `items[].claimed` | true or false | The claimed. | | `items[].open_claim_id` | value or null | The id of the open claim. | | `count` | whole number | How many match in all, across every page. | ## Money is somewhere else What a person is owed is on Balances, and the jobs they are on are on List jobs with worker_id. This list is the person, not their money. ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [Get worker](https://headhoncho.app/docs/api/get_worker): One technician or subcontractor: contact details, role, monthly pay, cut, the job types they take and whether the person has claimed their card. - The same records in the app: [the Team panel](https://headhoncho.app/docs/team). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "items": [ { "id": "wrk_3b90", "role": "technician", "name": "Dana Reyes", "first_name": "Dana", "last_name": "Reyes", "email": "dana@example.com", "phone": "+13095550188", "active": true, "is_team_lead": true, "monthly_pay": null, "hired_on": "2025-03-10", "ended_on": null, "business_name": "", "default_cut": { "basis": "job_profit", "value": 40.0, "label": "40% of job profit" }, "job_types": [ { "id": "jt_02", "name": "Local move" } ], "any_job_type": false, "claimed": true, "open_claim_id": null }, { "id": "wrk_7a12", "role": "subcontractor", "name": "Omar Saleh", "first_name": "Omar", "last_name": "Saleh", "email": "", "phone": "+13095550142", "active": true, "is_team_lead": false, "monthly_pay": null, "hired_on": null, "ended_on": null, "business_name": "Saleh Moving LLC", "default_cut": { "basis": "job_total", "value": 55.0, "label": "55% of job total" }, "job_types": [], "any_job_type": true, "claimed": false, "open_claim_id": null } ], "count": 2 } ``` ### cURL ```bash curl "https://api.headhoncho.app/api/v1/technicians?role=subcontractor&active=yes" \ -H "Authorization: Bearer hh_live_..." ``` ### Python ```python import requests response = requests.get( "https://api.headhoncho.app/api/v1/technicians", headers={"Authorization": "Bearer hh_live_..."}, params={ "role": "subcontractor", "active": "yes", }, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/technicians?role=subcontractor&active=yes", { headers: { Authorization: "Bearer hh_live_..." }, }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: list_technicians Arguments: role (text, optional), active (text, optional) Access: read on Team Hints: readOnly=true, destructive=false, idempotent=true, openWorld=false Try asking: "Using HeadHoncho, list technicians with role subcontractor." ``` --- # Get worker Get worker is a read in the HeadHoncho API. One technician or subcontractor: contact details, role, monthly pay, cut, the job types they take and whether the person has claimed their card. Page: https://headhoncho.app/docs/api/get_worker | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **Get worker**, HeadHoncho API v1. It is a read, sent to the base address `https://api.headhoncho.app`. `GET /api/v1/workers/{worker_id}` The key needs the **Team** area at **read**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). Send your key as `Authorization: Bearer hh_live_...`. See [API keys](https://headhoncho.app/docs/api/keys). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `worker_id` | id, in the path | Yes | The technician or subcontractor, from List technicians. | `wrk_3b90` | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back The person: id, role, name, first_name, last_name, email, phone, active, is_team_lead, monthly_pay (a number, or null when none was agreed), hired_on, ended_on, business_name (subcontractors), default_cut (basis, value and a label, or null), job_types and any_job_type (true when there is no limit), claimed (a login is linked) and open_claim_id. It never changes a record. It only reads the companies the key reaches. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `id` | id (text) | The id of this record. Ids are opaque text: keep them exactly as given. | | `role` | text | The role: what this person does on a job. | | `name` | text | The name, as the app shows it. | | `first_name` | text | The first name. | | `last_name` | text | The last name. | | `email` | text | The email. | | `phone` | text | A phone number. Hidden when the key hides personal details. | | `active` | true or false | The active. | | `is_team_lead` | true or false | True when it is team lead. | | `monthly_pay` | value or null | The monthly pay. | | `hired_on` | date (YYYY-MM-DD) | The date it was hired. | | `ended_on` | value or null | The date it was ended. | | `business_name` | text | The business name. | | `default_cut` | object | The default cut. | | `default_cut.basis` | text | The basis. | | `default_cut.value` | money (number) | The value. In the company's currency. | | `default_cut.label` | text | The name the app shows for it. | | `job_types` | list of objects | The job types. | | `job_types[].id` | id (text) | The id of this record. Ids are opaque text: keep them exactly as given. | | `job_types[].name` | text | The name, as the app shows it. | | `any_job_type` | true or false | The any job type. | | `claimed` | true or false | The claimed. | | `open_claim_id` | value or null | The id of the open claim. | ## What is left out The balance, the dispatch groups, the text-message consent and the logins you could link are not here. They are money, messages and who can sign in, which stay in the app. ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`not_found`](https://headhoncho.app/docs/api/errors#not_found) | 404 | No such record in the companies this credential reaches. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [List technicians](https://headhoncho.app/docs/api/list_technicians): Everyone the company sends jobs to: technicians and subcontractors, with contact details, the job types they take and the cut they work on. - The same records in the app: [the Team panel](https://headhoncho.app/docs/team). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "id": "wrk_3b90", "role": "technician", "name": "Dana Reyes", "first_name": "Dana", "last_name": "Reyes", "email": "dana@example.com", "phone": "+13095550188", "active": true, "is_team_lead": true, "monthly_pay": null, "hired_on": "2025-03-10", "ended_on": null, "business_name": "", "default_cut": { "basis": "job_profit", "value": 40.0, "label": "40% of job profit" }, "job_types": [ { "id": "jt_02", "name": "Local move" } ], "any_job_type": false, "claimed": true, "open_claim_id": null } ``` ### cURL ```bash curl "https://api.headhoncho.app/api/v1/workers/wrk_3b90" \ -H "Authorization: Bearer hh_live_..." ``` ### Python ```python import requests response = requests.get( "https://api.headhoncho.app/api/v1/workers/wrk_3b90", headers={"Authorization": "Bearer hh_live_..."}, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/workers/wrk_3b90", { headers: { Authorization: "Bearer hh_live_..." }, }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: get_worker Arguments: worker_id (id, required) Access: read on Team Hints: readOnly=true, destructive=false, idempotent=true, openWorld=false Try asking: "Using HeadHoncho, get worker with worker_id wrk_3b90." ``` --- # Create worker Create worker is a command in the HeadHoncho API. Add a technician or a subcontractor to the roster. Jobs can go to them at once; they can claim the card later. Page: https://headhoncho.app/docs/api/create_worker | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **Create worker**, HeadHoncho API v1. It is a command, sent to the base address `https://api.headhoncho.app`. `POST /api/v1/commands/create-worker` The key needs the **Team** area at **do**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). It runs the app's own command `create-worker`. Send an `Idempotency-Key` header with every call: the same key with the same body returns the first answer and runs nothing twice. See [the model](https://headhoncho.app/docs/api/model#idempotency). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `role` | text, in the JSON body | No | technician (default) or subcontractor. One of `technician`, `subcontractor`. | `technician` | | `first_name` | text, in the JSON body | Yes | Required. | `Sam` | | `last_name` | text, in the JSON body | No | Optional. | `Kowalski` | | `phone` | text, in the JSON body | No | Any format; stored as E.164. Two people cannot share one. | `+13095550177` | | `email` | text, in the JSON body | No | Two people cannot share one. | `sam@example.com` | | `is_team_lead` | boolean, in the JSON body | No | Technicians only. | `false` | | `monthly_pay` | money, in the JSON body | No | A standing monthly rate, a number. Technicians only. | `3200` | | `hired_on` | date, in the JSON body | No | Technicians only. | `2026-10-26` | | `business_name` | text, in the JSON body | No | The subcontractor's business. Subcontractors only. | `Saleh Moving LLC` | | `default_cut_basis` | text, in the JSON body | No | job_total or job_profit (a percent), or fixed_amount (dollars per job). Send with default_cut_value, or neither. One of `job_total`, `job_profit`, `fixed_amount`. | `job_profit` | | `default_cut_value` | money, in the JSON body | No | The percent, 0 to 100, or the dollars. | `40` | | `job_type_ids` | text, in the JSON body | No | Job types they take, ids comma separated, from Who am I. Empty: all of them. | `jt_02,jt_05` | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back accepted, worker_id, name, role and position. The 6th person on the Free plan is refused with the plan limit sentence, as in the app. It never deletes anything. It changes only what the command names, and it writes the change to the job's history with who asked for it. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `accepted` | true or false | True when the command ran. A command that cannot run is an error instead. | | `worker_id` | id (text) | The id of the worker. | | `position` | whole number | Where the change landed in the event log. Pass it as `after` on a read to see your own write. | | `name` | text | The name, as the app shows it. | | `role` | text | One of `technician`, `subcontractor`. | ## Same rules as the Team panel A phone or email another person already has is refused, and a cut needs both its basis and its value. ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`read_only`](https://headhoncho.app/docs/api/errors#read_only) | 403 | This credential may read this area but not change it. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`missing_idempotency_key`](https://headhoncho.app/docs/api/errors#missing_idempotency_key) | 400 | Send an Idempotency-Key header on every command. | | [`idempotency_mismatch`](https://headhoncho.app/docs/api/errors#idempotency_mismatch) | 409 | This Idempotency-Key was used with a different body. | | [`idempotency_in_progress`](https://headhoncho.app/docs/api/errors#idempotency_in_progress) | 409 | A command with this Idempotency-Key is still running. Wait a moment and send it again. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [Update worker](https://headhoncho.app/docs/api/update_worker): Change a technician or subcontractor: name, contact, pay, cut, job types, or take them off the roster. Only the fields you send change. - The same records in the app: [the Team panel](https://headhoncho.app/docs/team). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "accepted": true, "worker_id": "wrk_9c41", "position": 88601, "name": "Sam Kowalski", "role": "technician" } ``` ### cURL ```bash curl -X POST "https://api.headhoncho.app/api/v1/commands/create-worker" \ -H "Authorization: Bearer hh_live_..." \ -H "Idempotency-Key: 6f1d2c9e-1b7a-4c1e-9a52-0d3f8e4b7a10" \ -H "Content-Type: application/json" \ -d '{ "role": "technician", "first_name": "Sam", "last_name": "Kowalski", "phone": "+13095550177", "email": "sam@example.com", "is_team_lead": false, "monthly_pay": 3200, "hired_on": "2026-10-26", "business_name": "Saleh Moving LLC", "default_cut_basis": "job_profit", "default_cut_value": 40, "job_type_ids": "jt_02,jt_05" }' ``` ### Python ```python import requests import uuid response = requests.post( "https://api.headhoncho.app/api/v1/commands/create-worker", headers={ "Authorization": "Bearer hh_live_...", "Idempotency-Key": str(uuid.uuid4()), }, json={ "role": "technician", "first_name": "Sam", "last_name": "Kowalski", "phone": "+13095550177", "email": "sam@example.com", "is_team_lead": False, "monthly_pay": 3200, "hired_on": "2026-10-26", "business_name": "Saleh Moving LLC", "default_cut_basis": "job_profit", "default_cut_value": 40, "job_type_ids": "jt_02,jt_05", }, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/commands/create-worker", { method: "POST", headers: { Authorization: "Bearer hh_live_...", "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "role": "technician", "first_name": "Sam", "last_name": "Kowalski", "phone": "+13095550177", "email": "sam@example.com", "is_team_lead": false, "monthly_pay": 3200, "hired_on": "2026-10-26", "business_name": "Saleh Moving LLC", "default_cut_basis": "job_profit", "default_cut_value": 40, "job_type_ids": "jt_02,jt_05" }), }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: create_worker Arguments: role (text, optional), first_name (text, required), last_name (text, optional), phone (text, optional), email (text, optional), is_team_lead (boolean, optional), monthly_pay (money, optional), hired_on (date, optional), business_name (text, optional), default_cut_basis (text, optional), default_cut_value (money, optional), job_type_ids (text, optional) Access: do on Team Hints: readOnly=false, destructive=false, idempotent=false, openWorld=false Try asking: "Using HeadHoncho, create worker with first_name Sam and role technician." ``` --- # Update worker Update worker is a command in the HeadHoncho API. Change a technician or subcontractor: name, contact, pay, cut, job types, or take them off the roster. Only the fields you send change. Page: https://headhoncho.app/docs/api/update_worker | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **Update worker**, HeadHoncho API v1. It is a command, sent to the base address `https://api.headhoncho.app`. `POST /api/v1/commands/update-worker` The key needs the **Team** area at **do**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). It runs the app's own command `update-worker`. Send an `Idempotency-Key` header with every call: the same key with the same body returns the first answer and runs nothing twice. See [the model](https://headhoncho.app/docs/api/model#idempotency). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `worker_id` | id, in the JSON body | Yes | The technician or subcontractor, from List technicians. | `wrk_3b90` | | `first_name` | text, in the JSON body | No | The first name. | `Samuel` | | `last_name` | text, in the JSON body | No | The last name. | None | | `phone` | text, in the JSON body | No | Any format; stored as E.164. Empty clears it. | None | | `email` | text, in the JSON body | No | The email. Empty clears it. | None | | `active` | boolean, in the JSON body | No | false takes them off the roster. true puts them back. | `false` | | `is_team_lead` | boolean, in the JSON body | No | Technicians only. | None | | `monthly_pay` | money, in the JSON body | No | A standing monthly rate. Null clears it. Technicians only. | `3400` | | `hired_on` | date, in the JSON body | No | Technicians only. Null clears it. | None | | `ended_on` | date, in the JSON body | No | Technicians only. Null clears it. | None | | `business_name` | text, in the JSON body | No | The subcontractor's business. Subcontractors only. | None | | `default_cut_basis` | text, in the JSON body | No | job_total, job_profit or fixed_amount. Send with default_cut_value. One of `job_total`, `job_profit`, `fixed_amount`. | None | | `default_cut_value` | money, in the JSON body | No | The percent, 0 to 100, or the dollars. | None | | `job_type_ids` | text, in the JSON body | No | Replaces the job types they take, ids comma separated. Empty: all of them. | None | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back accepted, worker_id, name, changed (the fields you sent) and position. A field that does not fit the person's role, such as monthly_pay on a subcontractor, is refused by name. The role itself cannot change. It never deletes anything. It changes only what the command names, and it writes the change to the job's history with who asked for it. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `accepted` | true or false | True when the command ran. A command that cannot run is an error instead. | | `worker_id` | id (text) | The id of the worker. | | `position` | whole number | Where the change landed in the event log. Pass it as `after` on a read to see your own write. | | `name` | text | The name, as the app shows it. | | `changed` | list of text | The changed. | ## Taking someone off the roster Setting active to false stops tickets going to a subcontractor's group, as it does in the app. Their past jobs and balance stay. ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`read_only`](https://headhoncho.app/docs/api/errors#read_only) | 403 | This credential may read this area but not change it. | | [`not_found`](https://headhoncho.app/docs/api/errors#not_found) | 404 | No such record in the companies this credential reaches. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`missing_idempotency_key`](https://headhoncho.app/docs/api/errors#missing_idempotency_key) | 400 | Send an Idempotency-Key header on every command. | | [`idempotency_mismatch`](https://headhoncho.app/docs/api/errors#idempotency_mismatch) | 409 | This Idempotency-Key was used with a different body. | | [`idempotency_in_progress`](https://headhoncho.app/docs/api/errors#idempotency_in_progress) | 409 | A command with this Idempotency-Key is still running. Wait a moment and send it again. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [Create worker](https://headhoncho.app/docs/api/create_worker): Add a technician or a subcontractor to the roster. Jobs can go to them at once; they can claim the card later. - The same records in the app: [the Team panel](https://headhoncho.app/docs/team). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "accepted": true, "worker_id": "wrk_3b90", "position": 88601, "name": "Dana Reyes", "changed": [ "monthly_pay", "active" ] } ``` ### cURL ```bash curl -X POST "https://api.headhoncho.app/api/v1/commands/update-worker" \ -H "Authorization: Bearer hh_live_..." \ -H "Idempotency-Key: 6f1d2c9e-1b7a-4c1e-9a52-0d3f8e4b7a10" \ -H "Content-Type: application/json" \ -d '{ "worker_id": "wrk_3b90", "first_name": "Samuel", "active": false, "monthly_pay": 3400 }' ``` ### Python ```python import requests import uuid response = requests.post( "https://api.headhoncho.app/api/v1/commands/update-worker", headers={ "Authorization": "Bearer hh_live_...", "Idempotency-Key": str(uuid.uuid4()), }, json={ "worker_id": "wrk_3b90", "first_name": "Samuel", "active": False, "monthly_pay": 3400, }, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/commands/update-worker", { method: "POST", headers: { Authorization: "Bearer hh_live_...", "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "worker_id": "wrk_3b90", "first_name": "Samuel", "active": false, "monthly_pay": 3400 }), }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: update_worker Arguments: worker_id (id, required), first_name (text, optional), last_name (text, optional), phone (text, optional), email (text, optional), active (boolean, optional), is_team_lead (boolean, optional), monthly_pay (money, optional), hired_on (date, optional), ended_on (date, optional), business_name (text, optional), default_cut_basis (text, optional), default_cut_value (money, optional), job_type_ids (text, optional) Access: do on Team Hints: readOnly=false, destructive=false, idempotent=true, openWorld=false Try asking: "Using HeadHoncho, update worker with worker_id wrk_3b90 and first_name Samuel." ``` --- # List companies List companies is a read in the HeadHoncho API. The companies this credential reaches, each with its name, time zone, country and service area. The same ids every other call takes as company_id. Page: https://headhoncho.app/docs/api/list_companies | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **List companies**, HeadHoncho API v1. It is a read, sent to the base address `https://api.headhoncho.app`. `GET /api/v1/companies` Any key can call it. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). Send your key as `Authorization: Bearer hh_live_...`. See [API keys](https://headhoncho.app/docs/api/keys). ## Parameters This call takes no parameters. ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back items, one company each: id, name, time_zone, country, service_area and status (active or archived); count, how many in all. Only companies this credential reaches are listed. Who am I carries the same ids with the lookups a command needs. It never changes a record. It only reads the companies the key reaches. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `items` | list of objects | The rows on this page. | | `items[].id` | id (text) | The id of this record. Ids are opaque text: keep them exactly as given. | | `items[].name` | text | The name, as the app shows it. | | `items[].time_zone` | text | The company's time zone name, such as America/Chicago. | | `items[].country` | text | The country. | | `items[].service_area` | text | The service area. | | `items[].status` | text | The job status. | | `count` | whole number | How many match in all, across every page. | ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [Whoami](https://headhoncho.app/docs/api/whoami): Who this key or app acts as, which companies it reaches, what it may do, and the words to use in commands: statuses, job types and technicians. - [Get company](https://headhoncho.app/docs/api/get_company): One company this credential reaches: its name, time zone, country and service area. - [Get usage](https://headhoncho.app/docs/api/get_usage): What the plan has used, what API calls cost and what this credential called, by day or by endpoint, with the credits left. - [Get credits](https://headhoncho.app/docs/api/get_credits): This month's credits: the plan's grant, what rolled over, what was bought, what was used and what is left. - [List plans](https://headhoncho.app/docs/api/list_plans): The plans on offer, with price and what each includes, and which one this workspace is on. - The same records in the app: [Multiple companies](https://headhoncho.app/docs/companies). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "items": [ { "id": "cmp_14f5", "name": "Sunrise Moving", "time_zone": "America/Chicago", "country": "US", "service_area": "Bloomington and 30 miles around it", "status": "active" }, { "id": "cmp_8a21", "name": "Capital Roofing", "time_zone": "America/New_York", "country": "US", "service_area": "", "status": "active" } ], "count": 2 } ``` ### cURL ```bash curl "https://api.headhoncho.app/api/v1/companies" \ -H "Authorization: Bearer hh_live_..." ``` ### Python ```python import requests response = requests.get( "https://api.headhoncho.app/api/v1/companies", headers={"Authorization": "Bearer hh_live_..."}, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/companies", { headers: { Authorization: "Bearer hh_live_..." }, }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: list_companies Arguments: none Access: any key Hints: readOnly=true, destructive=false, idempotent=true, openWorld=false Try asking: "Using HeadHoncho, list companies." ``` --- # Get company Get company is a read in the HeadHoncho API. One company this credential reaches: its name, time zone, country and service area. Page: https://headhoncho.app/docs/api/get_company | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **Get company**, HeadHoncho API v1. It is a read, sent to the base address `https://api.headhoncho.app`. `GET /api/v1/companies/{company_id}` Any key can call it. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). Send your key as `Authorization: Bearer hh_live_...`. See [API keys](https://headhoncho.app/docs/api/keys). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `company_id` | id, in the path | Yes | The company id, from List companies or Who am I. | `cmp_14f5` | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back The company: id, name, time_zone, country, service_area and status. A company this credential does not reach answers 404, the same as one that does not exist. It never changes a record. It only reads the companies the key reaches. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `id` | id (text) | The id of this record. Ids are opaque text: keep them exactly as given. | | `name` | text | The name, as the app shows it. | | `time_zone` | text | The company's time zone name, such as America/Chicago. | | `country` | text | The country. | | `service_area` | text | The service area. | | `status` | text | The job status. | ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`not_found`](https://headhoncho.app/docs/api/errors#not_found) | 404 | No such record in the companies this credential reaches. | | [`out_of_scope`](https://headhoncho.app/docs/api/errors#out_of_scope) | 404 | No such company in the companies this credential reaches. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [Whoami](https://headhoncho.app/docs/api/whoami): Who this key or app acts as, which companies it reaches, what it may do, and the words to use in commands: statuses, job types and technicians. - [List companies](https://headhoncho.app/docs/api/list_companies): The companies this credential reaches, each with its name, time zone, country and service area. The same ids every other call takes as company_id. - [Get usage](https://headhoncho.app/docs/api/get_usage): What the plan has used, what API calls cost and what this credential called, by day or by endpoint, with the credits left. - [Get credits](https://headhoncho.app/docs/api/get_credits): This month's credits: the plan's grant, what rolled over, what was bought, what was used and what is left. - [List plans](https://headhoncho.app/docs/api/list_plans): The plans on offer, with price and what each includes, and which one this workspace is on. - The same records in the app: [Multiple companies](https://headhoncho.app/docs/companies). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "id": "cmp_14f5", "name": "Sunrise Moving", "time_zone": "America/Chicago", "country": "US", "service_area": "Bloomington and 30 miles around it", "status": "active" } ``` ### cURL ```bash curl "https://api.headhoncho.app/api/v1/companies/cmp_14f5" \ -H "Authorization: Bearer hh_live_..." ``` ### Python ```python import requests response = requests.get( "https://api.headhoncho.app/api/v1/companies/cmp_14f5", headers={"Authorization": "Bearer hh_live_..."}, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/companies/cmp_14f5", { headers: { Authorization: "Bearer hh_live_..." }, }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: get_company Arguments: company_id (id, required) Access: any key Hints: readOnly=true, destructive=false, idempotent=true, openWorld=false Try asking: "Using HeadHoncho, get company with company_id cmp_14f5." ``` --- # Get usage Get usage is a read in the HeadHoncho API. What the plan has used, what API calls cost and what this credential called, by day or by endpoint, with the credits left. Page: https://headhoncho.app/docs/api/get_usage | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **Get usage**, HeadHoncho API v1. It is a read, sent to the base address `https://api.headhoncho.app`. `GET /api/v1/usage` Any key can call it. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). Send your key as `Authorization: Bearer hh_live_...`. See [API keys](https://headhoncho.app/docs/api/keys). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `from` | date, in the query | No | First day of the API calls to count. Default: the first of this month. | `2026-10-01` | | `to` | date, in the query | No | Last day, inclusive. Default: today. | `2026-10-26` | | `by` | text, in the query | No | day (default) or endpoint: how to group the API calls. One of `day`, `endpoint`. | `day` | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back credits: what is left and what one call costs. plan: the plan in force, and plan_usage: what the workspace holds against it (companies, subs, jobs this month, devices, numbers). this_credential: calls_today, counted by UTC day, and its last calls, newest first, up to 50 from the past 7 days. workspace_calls: every API call the workspace paid for in the range, with calls and credits per day or per endpoint. Days are in the workspace's own time zone. It never changes a record. It only reads the companies the key reaches. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `from` | date (YYYY-MM-DD) | The first day of the range, inclusive. | | `to` | date (YYYY-MM-DD) | The last day of the range, inclusive. | | `by` | text | One of `day`, `endpoint`. | | `credits` | object | The credits. | | `credits.left` | number | Credits left in the workspace. | | `credits.per_call` | number | Credits one answered call costs. | | `plan` | object | The plan. | | `plan.code` | text | The code. | | `plan.name` | text | The name, as the app shows it. | | `plan.status` | text | The job status. | | `plan_usage` | object | The plan usage. | | `plan_usage.companies` | whole number | The companies. | | `plan_usage.subs` | whole number | The subs. | | `plan_usage.jobs_per_month` | whole number | The jobs per month. | | `plan_usage.automation_devices` | whole number | The automation devices. | | `plan_usage.numbers` | whole number | The numbers. | | `this_credential` | object | The this credential. | | `this_credential.name` | text | The name, as the app shows it. | | `this_credential.calls_today` | whole number | The calls today. | | `this_credential.recent` | list of objects | The recent. | | `this_credential.recent[].at` | time (ISO 8601, with offset) | The moment it happened. Carries its offset from UTC; `Z` is UTC. | | `this_credential.recent[].endpoint` | text | The endpoint. | | `this_credential.recent[].status` | whole number | The job status. | | `this_credential.recent[].door` | text | The door. | | `this_credential.recent[].credits` | text | The credits. | | `workspace_calls` | object | The workspace calls. | | `workspace_calls.calls` | whole number | How many calls. | | `workspace_calls.credits` | number | The credits. | | `workspace_calls.rows` | list of objects | The rows. | | `workspace_calls.rows[].day` | date (YYYY-MM-DD) | The day. | | `workspace_calls.rows[].calls` | whole number | How many calls. | | `workspace_calls.rows[].credits` | number | The credits. | ## One credit a call Every answered call costs the credits shown in per_call, this one included. A call that changes many jobs at once costs that for each job it changed. A refused call and a retried command cost nothing. There is no limit per minute or per month: the balance is the only brake. ## Whose calls this_credential is the calls made with the key or app asking. workspace_calls is every key and app of the workspace, as the credit ledger holds them. It names no job, customer or company. ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [Whoami](https://headhoncho.app/docs/api/whoami): Who this key or app acts as, which companies it reaches, what it may do, and the words to use in commands: statuses, job types and technicians. - [List companies](https://headhoncho.app/docs/api/list_companies): The companies this credential reaches, each with its name, time zone, country and service area. The same ids every other call takes as company_id. - [Get company](https://headhoncho.app/docs/api/get_company): One company this credential reaches: its name, time zone, country and service area. - [Get credits](https://headhoncho.app/docs/api/get_credits): This month's credits: the plan's grant, what rolled over, what was bought, what was used and what is left. - [List plans](https://headhoncho.app/docs/api/list_plans): The plans on offer, with price and what each includes, and which one this workspace is on. - The same records in the app: [Multiple companies](https://headhoncho.app/docs/companies). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "from": "2026-10-01", "to": "2026-10-26", "by": "day", "credits": { "left": 612.0, "per_call": 1.0 }, "plan": { "code": "core", "name": "Core", "status": "active" }, "plan_usage": { "companies": 2, "subs": 3, "jobs_per_month": 128, "automation_devices": 1, "numbers": 2 }, "this_credential": { "name": "Reporting laptop", "calls_today": 14, "recent": [ { "at": "2026-10-26T14:02:11Z", "endpoint": "list_jobs", "status": 200, "door": "rest", "credits": "1" } ] }, "workspace_calls": { "calls": 412, "credits": 412.0, "rows": [ { "day": "2026-10-25", "calls": 61, "credits": 61.0 }, { "day": "2026-10-26", "calls": 14, "credits": 14.0 } ] } } ``` ### cURL ```bash curl "https://api.headhoncho.app/api/v1/usage?from=2026-10-01&to=2026-10-26" \ -H "Authorization: Bearer hh_live_..." ``` ### Python ```python import requests response = requests.get( "https://api.headhoncho.app/api/v1/usage", headers={"Authorization": "Bearer hh_live_..."}, params={ "from": "2026-10-01", "to": "2026-10-26", }, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/usage?from=2026-10-01&to=2026-10-26", { headers: { Authorization: "Bearer hh_live_..." }, }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: get_usage Arguments: from (date, optional), to (date, optional), by (text, optional) Access: any key Hints: readOnly=true, destructive=false, idempotent=true, openWorld=false Try asking: "Using HeadHoncho, get usage with from 2026-10-01." ``` --- # Get credits Get credits is a read in the HeadHoncho API. This month's credits: the plan's grant, what rolled over, what was bought, what was used and what is left. Page: https://headhoncho.app/docs/api/get_credits | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **Get credits**, HeadHoncho API v1. It is a read, sent to the base address `https://api.headhoncho.app`. `GET /api/v1/credits` Any key can call it. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). Send your key as `Authorization: Bearer hh_live_...`. See [API keys](https://headhoncho.app/docs/api/keys). ## Parameters This call takes no parameters. ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back available (grant, rolled_over, carried and topped_up, less used), granted, used, month (YYYY-MM, in the workspace's time zone), renews_on, plan, plan_status and per_call, the credits one API call costs. The same figures the app's credits box shows. Card details and buying credits stay in the app. It never changes a record. It only reads the companies the key reaches. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `available` | number | True when this is connected and can be read. | | `granted` | number | The granted. | | `used` | number | The used. | | `month` | text | The first day of the month. | | `plan` | text | The plan. | | `plan_status` | text | The plan status. | | `renews_on` | date (YYYY-MM-DD) | The date it was renews. | | `grant` | number | The grant. | | `rolled_over` | number | The rolled over. | | `carried` | number | The carried. | | `topped_up` | number | The topped up. | | `per_call` | number | Credits one answered call costs. | ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [Whoami](https://headhoncho.app/docs/api/whoami): Who this key or app acts as, which companies it reaches, what it may do, and the words to use in commands: statuses, job types and technicians. - [List companies](https://headhoncho.app/docs/api/list_companies): The companies this credential reaches, each with its name, time zone, country and service area. The same ids every other call takes as company_id. - [Get company](https://headhoncho.app/docs/api/get_company): One company this credential reaches: its name, time zone, country and service area. - [Get usage](https://headhoncho.app/docs/api/get_usage): What the plan has used, what API calls cost and what this credential called, by day or by endpoint, with the credits left. - [List plans](https://headhoncho.app/docs/api/list_plans): The plans on offer, with price and what each includes, and which one this workspace is on. - The same records in the app: [Multiple companies](https://headhoncho.app/docs/companies). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "available": 612.0, "granted": 1500.0, "used": 888.0, "month": "2026-10", "plan": "core", "plan_status": "active", "renews_on": "2026-11-01", "grant": 1500.0, "rolled_over": 0.0, "carried": 0.0, "topped_up": 0.0, "per_call": 1.0 } ``` ### cURL ```bash curl "https://api.headhoncho.app/api/v1/credits" \ -H "Authorization: Bearer hh_live_..." ``` ### Python ```python import requests response = requests.get( "https://api.headhoncho.app/api/v1/credits", headers={"Authorization": "Bearer hh_live_..."}, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/credits", { headers: { Authorization: "Bearer hh_live_..." }, }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: get_credits Arguments: none Access: any key Hints: readOnly=true, destructive=false, idempotent=true, openWorld=false Try asking: "Using HeadHoncho, get credits." ``` --- # List plans List plans is a read in the HeadHoncho API. The plans on offer, with price and what each includes, and which one this workspace is on. Page: https://headhoncho.app/docs/api/list_plans | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **List plans**, HeadHoncho API v1. It is a read, sent to the base address `https://api.headhoncho.app`. `GET /api/v1/plans` Any key can call it. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). Send your key as `Authorization: Bearer hh_live_...`. See [API keys](https://headhoncho.app/docs/api/keys). ## Parameters This call takes no parameters. ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back plans, in the order the app prints them: code, name, monthly_price_cents (null when you must talk to us), self_serve, is_recommended, entitlements (unit_code, unit_name, included, unlimited, custom), the extra credit pack if the plan has one, history_months, scheduled_reports and api_access. every_plan: what is unlimited on all of them. current: the plan in force. pack: the credit pack this workspace may buy, or null. It never changes a record. It only reads the companies the key reaches. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `plans` | list of objects | The plans. | | `plans[].code` | text | The code. | | `plans[].name` | text | The name, as the app shows it. | | `plans[].monthly_price_cents` | whole number | The monthly price cents. | | `plans[].self_serve` | true or false | The self serve. | | `plans[].is_recommended` | true or false | True when it is recommended. | | `plans[].entitlements` | list of objects | The entitlements. | | `plans[].entitlements[].unit_code` | text | The unit code. | | `plans[].entitlements[].unit_name` | text | The unit name. | | `plans[].entitlements[].included` | whole number | The included. | | `plans[].entitlements[].unlimited` | true or false | The unlimited. | | `plans[].entitlements[].custom` | true or false | The custom. | | `plans[].pack` | value or null | The pack. | | `plans[].history_months` | whole number | The history months. | | `plans[].scheduled_reports` | true or false | The scheduled reports. | | `plans[].api_access` | true or false | The api access. | | `every_plan` | list of objects | The every plan. | | `every_plan[].unit_code` | text | The unit code. | | `every_plan[].unit_name` | text | The unit name. | | `current` | object | The current. | | `current.code` | text | The code. | | `current.name` | text | The name, as the app shows it. | | `current.status` | text | The job status. | | `pack` | value or null | The pack. | ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [Whoami](https://headhoncho.app/docs/api/whoami): Who this key or app acts as, which companies it reaches, what it may do, and the words to use in commands: statuses, job types and technicians. - [List companies](https://headhoncho.app/docs/api/list_companies): The companies this credential reaches, each with its name, time zone, country and service area. The same ids every other call takes as company_id. - [Get company](https://headhoncho.app/docs/api/get_company): One company this credential reaches: its name, time zone, country and service area. - [Get usage](https://headhoncho.app/docs/api/get_usage): What the plan has used, what API calls cost and what this credential called, by day or by endpoint, with the credits left. - [Get credits](https://headhoncho.app/docs/api/get_credits): This month's credits: the plan's grant, what rolled over, what was bought, what was used and what is left. - The same records in the app: [Multiple companies](https://headhoncho.app/docs/companies). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "plans": [ { "code": "free", "name": "Free", "monthly_price_cents": 0, "self_serve": true, "is_recommended": false, "entitlements": [ { "unit_code": "companies", "unit_name": "Companies", "included": 1, "unlimited": false, "custom": false } ], "pack": null, "history_months": 3, "scheduled_reports": false, "api_access": true }, { "code": "core", "name": "Core", "monthly_price_cents": 14900, "self_serve": true, "is_recommended": true, "entitlements": [ { "unit_code": "companies", "unit_name": "Companies", "included": 5, "unlimited": false, "custom": false } ], "pack": null, "history_months": 12, "scheduled_reports": true, "api_access": true } ], "every_plan": [ { "unit_code": "campaigns", "unit_name": "Campaigns" } ], "current": { "code": "core", "name": "Core", "status": "active" }, "pack": null } ``` ### cURL ```bash curl "https://api.headhoncho.app/api/v1/plans" \ -H "Authorization: Bearer hh_live_..." ``` ### Python ```python import requests response = requests.get( "https://api.headhoncho.app/api/v1/plans", headers={"Authorization": "Bearer hh_live_..."}, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/plans", { headers: { Authorization: "Bearer hh_live_..." }, }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: list_plans Arguments: none Access: any key Hints: readOnly=true, destructive=false, idempotent=true, openWorld=false Try asking: "Using HeadHoncho, list plans." ``` --- # List events List events is a read in the HeadHoncho API. What changed on jobs since a cursor: a job opened, moved, assigned or paid, with who did it. Send back next to get the rest. Page: https://headhoncho.app/docs/api/list_events | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **List events**, HeadHoncho API v1. It is a read, sent to the base address `https://api.headhoncho.app`. `GET /api/v1/events` The key needs the **Jobs** area at **read**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). Send your key as `Authorization: Bearer hh_live_...`. See [API keys](https://headhoncho.app/docs/api/keys). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `cursor` | number, in the query | No | The next from your last answer. Leave it out the first time to get the latest changes and a cursor to start from. | `88400` | | `company_id` | id, in the query | No | One company. Default: every company the credential reaches. | `cmp_14f5` | | `limit` | number, in the query | No | 1 to 200. Default 50. | `50` | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back items, oldest first: position, event (a type from the Event catalog), at, by (a person, or "Reporting laptop, for Ariel T." when a key acted), job (id, number, company_id) and data, a few plain facts about the change. next: send it as cursor to continue; it is always safe to keep, even with no items. more: true when there is more to read now. Only jobs this credential reaches appear, and jobs in Trash never do. Money amounts, customer details and message text are never carried: read the job for those. It never changes a record. It only reads the companies the key reaches. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `items` | list of objects | The rows on this page. | | `items[].position` | whole number | Where the change landed in the event log. Pass it as `after` on a read to see your own write. | | `items[].event` | text | The kind of event, as a code. | | `items[].at` | time (ISO 8601, with offset) | The moment it happened. Carries its offset from UTC; `Z` is UTC. | | `items[].by` | text | Who did it. A key shows as its name, then "for" and the member it acts as. | | `items[].job` | object | The job. | | `items[].job.id` | id (text) | The id of this record. Ids are opaque text: keep them exactly as given. | | `items[].job.number` | whole number | The number people say out loud, such as the job number. | | `items[].job.company_id` | id (text) | The id of the company. | | `items[].data` | object | The data. | | `items[].data.status` | text | The job status. | | `items[].data.status_slug` | text | The status slug. | | `items[].data.previous_status` | text | The previous status. | | `next` | whole number | The cursor for the next page, or null on the last page. Pass it back as `cursor`. | | `more` | true or false | The more. | ## Reading in order Call with the cursor you were given, handle the items, keep next. A call with no cursor returns the latest changes, not all of history. The feed holds back a change until the app has finished recording it, so a change you just made may show a moment later: use after= with the position your command answered to wait for it. ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`not_found`](https://headhoncho.app/docs/api/errors#not_found) | 404 | No such record in the companies this credential reaches. | | [`out_of_scope`](https://headhoncho.app/docs/api/errors#out_of_scope) | 404 | No such company in the companies this credential reaches. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [List event types](https://headhoncho.app/docs/api/list_event_types): Every kind of change the Changes feed can carry, in plain words, and the facts each one puts in data. - The same records in the app: [the Jobs panel](https://headhoncho.app/docs/jobs). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "items": [ { "position": 88402, "event": "job.status_changed", "at": "2026-10-26T14:02:11Z", "by": "Reporting laptop, for Ariel T.", "job": { "id": "job_1138", "number": 1138, "company_id": "cmp_14f5" }, "data": { "status": "Dispatched", "status_slug": "dispatched", "previous_status": "Scheduled" } } ], "next": 88402, "more": false } ``` ### cURL ```bash curl "https://api.headhoncho.app/api/v1/events?cursor=88400&company_id=cmp_14f5" \ -H "Authorization: Bearer hh_live_..." ``` ### Python ```python import requests response = requests.get( "https://api.headhoncho.app/api/v1/events", headers={"Authorization": "Bearer hh_live_..."}, params={ "cursor": "88400", "company_id": "cmp_14f5", }, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/events?cursor=88400&company_id=cmp_14f5", { headers: { Authorization: "Bearer hh_live_..." }, }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: list_events Arguments: cursor (number, optional), company_id (id, optional), limit (number, optional) Access: read on Jobs Hints: readOnly=true, destructive=false, idempotent=true, openWorld=false Try asking: "Using HeadHoncho, list events with cursor 88400." ``` --- # List event types List event types is a read in the HeadHoncho API. Every kind of change the Changes feed can carry, in plain words, and the facts each one puts in data. Page: https://headhoncho.app/docs/api/list_event_types | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **List event types**, HeadHoncho API v1. It is a read, sent to the base address `https://api.headhoncho.app`. `GET /api/v1/event-types` The key needs the **Jobs** area at **read**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). Send your key as `Authorization: Bearer hh_live_...`. See [API keys](https://headhoncho.app/docs/api/keys). ## Parameters This call takes no parameters. ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back items: event (the name used in the feed), says (what happened, in a sentence) and data (the keys that change carries, which can be empty). It never changes a record. It only reads the companies the key reaches. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `items` | list of objects | The rows on this page. | | `items[].event` | text | The kind of event, as a code. | | `items[].says` | text | The text to show a person. | | `items[].data` | list of text | The data. | ## Pushed instead of polled The same kinds are what a webhook sends. Add one to have each change sent to your address, signed, instead of asking for it. ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [List events](https://headhoncho.app/docs/api/list_events): What changed on jobs since a cursor: a job opened, moved, assigned or paid, with who did it. Send back next to get the rest. - The same records in the app: [the Jobs panel](https://headhoncho.app/docs/jobs). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "items": [ { "event": "job.created", "says": "A job or a lead was opened.", "data": [ "status", "job_type", "quoted", "scheduled_start", "scheduled_end", "source" ] }, { "event": "job.details_changed", "says": "A job's facts changed: the customer, the address, the schedule, the price, the type or the notes.", "data": [ "job_type", "quoted", "scheduled_start", "scheduled_end" ] }, { "event": "job.status_changed", "says": "A job moved to another status.", "data": [ "status", "status_slug", "previous_status" ] }, { "event": "job.assigned", "says": "A technician or subcontractor was put on a job.", "data": [ "technician_id", "technician" ] }, { "event": "job.unassigned", "says": "A technician or subcontractor was taken off a job.", "data": [ "technician_id", "technician" ] }, { "event": "job.archived", "says": "A job was archived.", "data": [] }, { "event": "job.unarchived", "says": "A job was taken out of the archive.", "data": [] }, { "event": "job.restored", "says": "A job came back from Trash.", "data": [] }, { "event": "job_note.added", "says": "A note was added to a job. Read the job's history for the words.", "data": [] }, { "event": "job_payment.recorded", "says": "A payment was recorded on a job. Read the job's money for the amount.", "data": [] } ] } ``` ### cURL ```bash curl "https://api.headhoncho.app/api/v1/event-types" \ -H "Authorization: Bearer hh_live_..." ``` ### Python ```python import requests response = requests.get( "https://api.headhoncho.app/api/v1/event-types", headers={"Authorization": "Bearer hh_live_..."}, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/event-types", { headers: { Authorization: "Bearer hh_live_..." }, }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: list_event_types Arguments: none Access: read on Jobs Hints: readOnly=true, destructive=false, idempotent=true, openWorld=false Try asking: "Using HeadHoncho, list event types." ``` --- # List webhooks List webhooks is a read in the HeadHoncho API. The addresses this key asked us to call when jobs change, with the kinds of change each wants and whether it is paused. Page: https://headhoncho.app/docs/api/list_webhooks | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **List webhooks**, HeadHoncho API v1. It is a read, sent to the base address `https://api.headhoncho.app`. `GET /api/v1/webhooks` The key needs the **Company settings** area at **read**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). Send your key as `Authorization: Bearer hh_live_...`. See [API keys](https://headhoncho.app/docs/api/keys). ## Parameters This call takes no parameters. ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back items, one webhook each: id, name, url, kinds (event names from the Event catalog), companies and all_companies, secret_hint (the last four characters of the signing secret, never the secret), paused with paused_reason, created_by and created_at. count is how many. It never changes a record. It only reads the companies the key reaches. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `items` | list of objects | The rows on this page. | | `items[].id` | id (text) | The id of this record. Ids are opaque text: keep them exactly as given. | | `items[].name` | text | The name, as the app shows it. | | `items[].url` | text | The link. | | `items[].kinds` | list of text | The kinds. | | `items[].companies` | list | The companies. | | `items[].all_companies` | true or false | The all companies. | | `items[].secret_hint` | text | The secret hint. | | `items[].paused` | true or false | The paused. | | `items[].paused_reason` | text | The paused reason. | | `items[].created_by` | text | The created by. | | `items[].created_at` | time (ISO 8601, with offset) | When it was created. Carries its offset from UTC; `Z` is UTC. | | `count` | whole number | How many match in all, across every page. | ## Only this key's A key sees the webhooks it made. Webhooks made by another key are not listed, even in the same workspace. ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [Get webhook](https://headhoncho.app/docs/api/get_webhook): One webhook: its address, the kinds of change it wants, its companies, and whether it is paused and why. - [List webhook deliveries](https://headhoncho.app/docs/api/list_webhook_deliveries): The last changes sent to one webhook, newest first, with the answer code and time of every try. - The same records in the app: [Settings](https://headhoncho.app/docs/settings). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "items": [ { "id": "whk_6d21", "name": "Zapier, new jobs", "url": "https://hooks.zapier.com/hooks/catch/123456/abcdef/", "kinds": [ "job.created", "job.status_changed" ], "companies": [], "all_companies": true, "secret_hint": "9fQd", "paused": false, "paused_reason": "", "created_by": "Ariel T.", "created_at": "2026-10-27T14:02:11Z" } ], "count": 1 } ``` ### cURL ```bash curl "https://api.headhoncho.app/api/v1/webhooks" \ -H "Authorization: Bearer hh_live_..." ``` ### Python ```python import requests response = requests.get( "https://api.headhoncho.app/api/v1/webhooks", headers={"Authorization": "Bearer hh_live_..."}, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/webhooks", { headers: { Authorization: "Bearer hh_live_..." }, }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: list_webhooks Arguments: none Access: read on Company settings Hints: readOnly=true, destructive=false, idempotent=true, openWorld=false Try asking: "Using HeadHoncho, list webhooks." ``` --- # Get webhook Get webhook is a read in the HeadHoncho API. One webhook: its address, the kinds of change it wants, its companies, and whether it is paused and why. Page: https://headhoncho.app/docs/api/get_webhook | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **Get webhook**, HeadHoncho API v1. It is a read, sent to the base address `https://api.headhoncho.app`. `GET /api/v1/webhooks/{webhook_id}` The key needs the **Company settings** area at **read**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). Send your key as `Authorization: Bearer hh_live_...`. See [API keys](https://headhoncho.app/docs/api/keys). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `webhook_id` | id, in the path | Yes | The webhook, from List webhooks. | `whk_6d21` | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back The webhook in the List webhooks shape. paused_reason is by_hand, no_credits (the workspace ran out of credits), failing (the address kept failing) or access_revoked (the key was revoked). It never changes a record. It only reads the companies the key reaches. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `id` | id (text) | The id of this record. Ids are opaque text: keep them exactly as given. | | `name` | text | The name, as the app shows it. | | `url` | text | The link. | | `kinds` | list of text | The kinds. | | `companies` | list | The companies. | | `all_companies` | true or false | The all companies. | | `secret_hint` | text | The secret hint. | | `paused` | true or false | The paused. | | `paused_reason` | text | The paused reason. | | `created_by` | text | The created by. | | `created_at` | time (ISO 8601, with offset) | When it was created. Carries its offset from UTC; `Z` is UTC. | ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`not_found`](https://headhoncho.app/docs/api/errors#not_found) | 404 | No such record in the companies this credential reaches. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [List webhooks](https://headhoncho.app/docs/api/list_webhooks): The addresses this key asked us to call when jobs change, with the kinds of change each wants and whether it is paused. - [List webhook deliveries](https://headhoncho.app/docs/api/list_webhook_deliveries): The last changes sent to one webhook, newest first, with the answer code and time of every try. - The same records in the app: [Settings](https://headhoncho.app/docs/settings). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "id": "whk_6d21", "name": "Zapier, new jobs", "url": "https://hooks.zapier.com/hooks/catch/123456/abcdef/", "kinds": [ "job.created", "job.status_changed" ], "companies": [], "all_companies": true, "secret_hint": "9fQd", "paused": false, "paused_reason": "", "created_by": "Ariel T.", "created_at": "2026-10-27T14:02:11Z" } ``` ### cURL ```bash curl "https://api.headhoncho.app/api/v1/webhooks/whk_6d21" \ -H "Authorization: Bearer hh_live_..." ``` ### Python ```python import requests response = requests.get( "https://api.headhoncho.app/api/v1/webhooks/whk_6d21", headers={"Authorization": "Bearer hh_live_..."}, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/webhooks/whk_6d21", { headers: { Authorization: "Bearer hh_live_..." }, }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: get_webhook Arguments: webhook_id (id, required) Access: read on Company settings Hints: readOnly=true, destructive=false, idempotent=true, openWorld=false Try asking: "Using HeadHoncho, get webhook with webhook_id whk_6d21." ``` --- # List webhook deliveries List webhook deliveries is a read in the HeadHoncho API. The last changes sent to one webhook, newest first, with the answer code and time of every try. Page: https://headhoncho.app/docs/api/list_webhook_deliveries | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **List webhook deliveries**, HeadHoncho API v1. It is a read, sent to the base address `https://api.headhoncho.app`. `GET /api/v1/webhooks/{webhook_id}/deliveries` The key needs the **Company settings** area at **read**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). Send your key as `Authorization: Bearer hh_live_...`. See [API keys](https://headhoncho.app/docs/api/keys). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `webhook_id` | id, in the path | Yes | The webhook, from List webhooks. | `whk_6d21` | | `status` | text, in the query | No | Only deliveries in this state. One of `pending`, `delivered`, `failed`. | `failed` | | `limit` | number, in the query | No | 1 to 200. Default 50. | `50` | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back items, one delivery each: id, event_id (the id sent in X-HeadHoncho-Event-Id), event, job, status (pending, delivered or failed), attempts, last_attempt_at, next_attempt_at (when a pending one is tried again), response_code, error, and attempt_log: every try with its number n, at, code (null when nothing answered), ms and error. It never changes a record. It only reads the companies the key reaches. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `items` | list of objects | The rows on this page. | | `items[].id` | id (text) | The id of this record. Ids are opaque text: keep them exactly as given. | | `items[].event_id` | id (text) | The id of the event. | | `items[].event` | text | The kind of event, as a code. | | `items[].job` | object | The job. | | `items[].job.id` | id (text) | The id of this record. Ids are opaque text: keep them exactly as given. | | `items[].job.number` | whole number | The number people say out loud, such as the job number. | | `items[].status` | text | One of `pending`, `delivered`, `failed`. | | `items[].attempts` | whole number | The attempts. | | `items[].last_attempt_at` | time (ISO 8601, with offset) | When the last attempt happened. Carries its offset from UTC; `Z` is UTC. | | `items[].next_attempt_at` | time or null | When the next attempt happened. | | `items[].response_code` | whole number | The response code. | | `items[].error` | text | The error. | | `items[].attempt_log` | list of objects | The attempt log. | | `items[].attempt_log[].n` | whole number | The n. | | `items[].attempt_log[].at` | time (ISO 8601, with offset) | The moment it happened. Carries its offset from UTC; `Z` is UTC. | | `items[].attempt_log[].code` | whole number | The code. | | `items[].attempt_log[].ms` | whole number | The ms. | | `items[].attempt_log[].error` | text | The error. | | `count` | whole number | How many match in all, across every page. | ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`not_found`](https://headhoncho.app/docs/api/errors#not_found) | 404 | No such record in the companies this credential reaches. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [List webhooks](https://headhoncho.app/docs/api/list_webhooks): The addresses this key asked us to call when jobs change, with the kinds of change each wants and whether it is paused. - [Get webhook](https://headhoncho.app/docs/api/get_webhook): One webhook: its address, the kinds of change it wants, its companies, and whether it is paused and why. - The same records in the app: [Settings](https://headhoncho.app/docs/settings). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "items": [ { "id": "dlv_41c8", "event_id": "88402", "event": "job.status_changed", "job": { "id": "job_1138", "number": 1138 }, "status": "delivered", "attempts": 2, "last_attempt_at": "2026-10-27T14:03:41Z", "next_attempt_at": null, "response_code": 200, "error": "", "attempt_log": [ { "n": 1, "at": "2026-10-27T14:03:11Z", "code": 503, "ms": 412, "error": "HTTP 503" }, { "n": 2, "at": "2026-10-27T14:03:41Z", "code": 200, "ms": 138, "error": "" } ] } ], "count": 1 } ``` ### cURL ```bash curl "https://api.headhoncho.app/api/v1/webhooks/whk_6d21/deliveries?status=failed&limit=50" \ -H "Authorization: Bearer hh_live_..." ``` ### Python ```python import requests response = requests.get( "https://api.headhoncho.app/api/v1/webhooks/whk_6d21/deliveries", headers={"Authorization": "Bearer hh_live_..."}, params={ "status": "failed", "limit": "50", }, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/webhooks/whk_6d21/deliveries?status=failed&limit=50", { headers: { Authorization: "Bearer hh_live_..." }, }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: list_webhook_deliveries Arguments: webhook_id (id, required), status (text, optional), limit (number, optional) Access: read on Company settings Hints: readOnly=true, destructive=false, idempotent=true, openWorld=false Try asking: "Using HeadHoncho, list webhook deliveries with webhook_id whk_6d21 and status failed." ``` --- # Add webhook Add webhook is a command in the HeadHoncho API. Give us an address and the kinds of change you want. We call it for each change, signed, and retry what fails. The signing secret is shown once. Page: https://headhoncho.app/docs/api/add_webhook | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **Add webhook**, HeadHoncho API v1. It is a command, sent to the base address `https://api.headhoncho.app`. `POST /api/v1/commands/add-webhook` The key needs the **Company settings** area at **do**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). It runs the app's own command `add-webhook`. Send an `Idempotency-Key` header with every call: the same key with the same body returns the first answer and runs nothing twice. See [the model](https://headhoncho.app/docs/api/model#idempotency). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `url` | text, in the JSON body | Yes | Where to send changes. https only, and a public address: no private network, no redirects followed. | `https://example.com/hooks/headhoncho` | | `kinds` | text, in the JSON body | Yes | The kinds of change to send, comma separated, from the Event catalog. | `job.created,job.status_changed` | | `name` | text, in the JSON body | No | What to call it. Default: the address's host. | `Zapier, new jobs` | | `company_ids` | text, in the JSON body | No | Limit it to these companies, comma separated. Default: every company this key reaches. | `cmp_14f5` | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back accepted, position, webhook_id, name, url, kinds, company_ids, secret_hint and secret: the signing secret, shown this once. Changes made from now on are sent; the past is not. It never deletes anything. It changes only what the command names, and it writes the change to the job's history with who asked for it. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `accepted` | true or false | True when the command ran. A command that cannot run is an error instead. | | `position` | whole number | Where the change landed in the event log. Pass it as `after` on a read to see your own write. | | `webhook_id` | id (text) | The id of the webhook. | | `name` | text | The name, as the app shows it. | | `url` | text | The link. | | `kinds` | list of text | The kinds. | | `company_ids` | list | The company ids. | | `secret_hint` | text | The secret hint. | | `secret` | text | The secret. | ## Every plan Webhooks come with every plan, Free included, like keys. A plan that has none refuses the call with plan_limit. ## One credit per change Each change we deliver costs one credit, however many tries it takes. At zero credits we hold the changes and pause the webhook; it resumes by itself when credits are back. ## Save the secret It is the only time we show it. Lose it and use Change a webhook with rotate_secret. ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`read_only`](https://headhoncho.app/docs/api/errors#read_only) | 403 | This credential may read this area but not change it. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`missing_idempotency_key`](https://headhoncho.app/docs/api/errors#missing_idempotency_key) | 400 | Send an Idempotency-Key header on every command. | | [`idempotency_mismatch`](https://headhoncho.app/docs/api/errors#idempotency_mismatch) | 409 | This Idempotency-Key was used with a different body. | | [`idempotency_in_progress`](https://headhoncho.app/docs/api/errors#idempotency_in_progress) | 409 | A command with this Idempotency-Key is still running. Wait a moment and send it again. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [Change webhook](https://headhoncho.app/docs/api/change_webhook): Rename a webhook, move it to another address, change its kinds or companies, pause or resume it, or replace its secret. Send only what changes. - [Remove webhook](https://headhoncho.app/docs/api/remove_webhook): Stop calling an address for good. Its past deliveries stay readable. - [Send webhook test](https://headhoncho.app/docs/api/send_webhook_test): Send a signed test event to one webhook now and say what the address answered. It is not retried and costs no delivery credit. - [Redeliver webhook](https://headhoncho.app/docs/api/redeliver_webhook): Send one delivery again, from a webhook's list of deliveries. It goes out within a minute. A change already paid for is not paid for twice. - The same records in the app: [Settings](https://headhoncho.app/docs/settings). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "accepted": true, "position": 88701, "webhook_id": "whk_6d21", "name": "Zapier, new jobs", "url": "https://hooks.zapier.com/hooks/catch/123456/abcdef/", "kinds": [ "job.created", "job.status_changed" ], "company_ids": [], "secret_hint": "9fQd", "secret": "whsec_Kq3m...9fQd" } ``` ### cURL ```bash curl -X POST "https://api.headhoncho.app/api/v1/commands/add-webhook" \ -H "Authorization: Bearer hh_live_..." \ -H "Idempotency-Key: 6f1d2c9e-1b7a-4c1e-9a52-0d3f8e4b7a10" \ -H "Content-Type: application/json" \ -d '{ "url": "https://example.com/hooks/headhoncho", "kinds": "job.created,job.status_changed", "name": "Zapier, new jobs", "company_ids": "cmp_14f5" }' ``` ### Python ```python import requests import uuid response = requests.post( "https://api.headhoncho.app/api/v1/commands/add-webhook", headers={ "Authorization": "Bearer hh_live_...", "Idempotency-Key": str(uuid.uuid4()), }, json={ "url": "https://example.com/hooks/headhoncho", "kinds": "job.created,job.status_changed", "name": "Zapier, new jobs", "company_ids": "cmp_14f5", }, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/commands/add-webhook", { method: "POST", headers: { Authorization: "Bearer hh_live_...", "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://example.com/hooks/headhoncho", "kinds": "job.created,job.status_changed", "name": "Zapier, new jobs", "company_ids": "cmp_14f5" }), }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: add_webhook Arguments: url (text, required), kinds (text, required), name (text, optional), company_ids (text, optional) Access: do on Company settings Hints: readOnly=false, destructive=false, idempotent=false, openWorld=false Try asking: "Using HeadHoncho, add webhook with url https://example.com/hooks/headhoncho and kinds job.created,job.status_changed and name Zapier, new jobs." ``` --- # Change webhook Change webhook is a command in the HeadHoncho API. Rename a webhook, move it to another address, change its kinds or companies, pause or resume it, or replace its secret. Send only what changes. Page: https://headhoncho.app/docs/api/change_webhook | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **Change webhook**, HeadHoncho API v1. It is a command, sent to the base address `https://api.headhoncho.app`. `POST /api/v1/commands/change-webhook` The key needs the **Company settings** area at **do**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). It runs the app's own command `change-webhook`. Send an `Idempotency-Key` header with every call: the same key with the same body returns the first answer and runs nothing twice. See [the model](https://headhoncho.app/docs/api/model#idempotency). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `webhook_id` | id, in the JSON body | Yes | The webhook, from List webhooks. | `whk_6d21` | | `name` | text, in the JSON body | No | A new name. | `Zapier, all jobs` | | `url` | text, in the JSON body | No | A new address. The same rules as when adding. | `https://example.com/hooks/v2` | | `kinds` | text, in the JSON body | No | The kinds of change, comma separated. They replace the list. | `job.created,job.assigned` | | `company_ids` | text, in the JSON body | No | The companies, comma separated. They replace the list; an empty value means every company the key reaches. | `cmp_14f5` | | `paused` | boolean, in the JSON body | No | true pauses it, false resumes it. What it missed while paused is sent in order on resume. | `false` | | `rotate_secret` | boolean, in the JSON body | No | true replaces the signing secret and shows the new one this once. The old one stops signing at once. | `false` | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back accepted, position, webhook_id, name, url, kinds, company_ids, paused and, when rotate_secret was true, secret and secret_hint. It never deletes anything. It changes only what the command names, and it writes the change to the job's history with who asked for it. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `accepted` | true or false | True when the command ran. A command that cannot run is an error instead. | | `position` | whole number | Where the change landed in the event log. Pass it as `after` on a read to see your own write. | | `webhook_id` | id (text) | The id of the webhook. | | `name` | text | The name, as the app shows it. | | `url` | text | The link. | | `kinds` | list of text | The kinds. | | `company_ids` | list | The company ids. | | `paused` | true or false | The paused. | ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`read_only`](https://headhoncho.app/docs/api/errors#read_only) | 403 | This credential may read this area but not change it. | | [`not_found`](https://headhoncho.app/docs/api/errors#not_found) | 404 | No such record in the companies this credential reaches. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`missing_idempotency_key`](https://headhoncho.app/docs/api/errors#missing_idempotency_key) | 400 | Send an Idempotency-Key header on every command. | | [`idempotency_mismatch`](https://headhoncho.app/docs/api/errors#idempotency_mismatch) | 409 | This Idempotency-Key was used with a different body. | | [`idempotency_in_progress`](https://headhoncho.app/docs/api/errors#idempotency_in_progress) | 409 | A command with this Idempotency-Key is still running. Wait a moment and send it again. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [Add webhook](https://headhoncho.app/docs/api/add_webhook): Give us an address and the kinds of change you want. We call it for each change, signed, and retry what fails. The signing secret is shown once. - [Remove webhook](https://headhoncho.app/docs/api/remove_webhook): Stop calling an address for good. Its past deliveries stay readable. - [Send webhook test](https://headhoncho.app/docs/api/send_webhook_test): Send a signed test event to one webhook now and say what the address answered. It is not retried and costs no delivery credit. - [Redeliver webhook](https://headhoncho.app/docs/api/redeliver_webhook): Send one delivery again, from a webhook's list of deliveries. It goes out within a minute. A change already paid for is not paid for twice. - The same records in the app: [Settings](https://headhoncho.app/docs/settings). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "accepted": true, "position": 88701, "webhook_id": "whk_6d21", "name": "Zapier, all jobs", "url": "https://hooks.zapier.com/hooks/catch/123456/abcdef/", "kinds": [ "job.created", "job.status_changed" ], "company_ids": [], "paused": false } ``` ### cURL ```bash curl -X POST "https://api.headhoncho.app/api/v1/commands/change-webhook" \ -H "Authorization: Bearer hh_live_..." \ -H "Idempotency-Key: 6f1d2c9e-1b7a-4c1e-9a52-0d3f8e4b7a10" \ -H "Content-Type: application/json" \ -d '{ "webhook_id": "whk_6d21", "name": "Zapier, all jobs", "url": "https://example.com/hooks/v2", "kinds": "job.created,job.assigned", "company_ids": "cmp_14f5", "paused": false, "rotate_secret": false }' ``` ### Python ```python import requests import uuid response = requests.post( "https://api.headhoncho.app/api/v1/commands/change-webhook", headers={ "Authorization": "Bearer hh_live_...", "Idempotency-Key": str(uuid.uuid4()), }, json={ "webhook_id": "whk_6d21", "name": "Zapier, all jobs", "url": "https://example.com/hooks/v2", "kinds": "job.created,job.assigned", "company_ids": "cmp_14f5", "paused": False, "rotate_secret": False, }, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/commands/change-webhook", { method: "POST", headers: { Authorization: "Bearer hh_live_...", "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "webhook_id": "whk_6d21", "name": "Zapier, all jobs", "url": "https://example.com/hooks/v2", "kinds": "job.created,job.assigned", "company_ids": "cmp_14f5", "paused": false, "rotate_secret": false }), }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: change_webhook Arguments: webhook_id (id, required), name (text, optional), url (text, optional), kinds (text, optional), company_ids (text, optional), paused (boolean, optional), rotate_secret (boolean, optional) Access: do on Company settings Hints: readOnly=false, destructive=false, idempotent=true, openWorld=false Try asking: "Using HeadHoncho, change webhook with webhook_id whk_6d21 and name Zapier, all jobs." ``` --- # Remove webhook Remove webhook is a command in the HeadHoncho API. Stop calling an address for good. Its past deliveries stay readable. Page: https://headhoncho.app/docs/api/remove_webhook | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **Remove webhook**, HeadHoncho API v1. It is a command, sent to the base address `https://api.headhoncho.app`. `POST /api/v1/commands/remove-webhook` The key needs the **Company settings** area at **do**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). It runs the app's own command `remove-webhook`. Send an `Idempotency-Key` header with every call: the same key with the same body returns the first answer and runs nothing twice. See [the model](https://headhoncho.app/docs/api/model#idempotency). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `webhook_id` | id, in the JSON body | Yes | The webhook, from List webhooks. | `whk_6d21` | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back accepted, position, webhook_id and removed: true. It never deletes anything. It changes only what the command names, and it writes the change to the job's history with who asked for it. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `accepted` | true or false | True when the command ran. A command that cannot run is an error instead. | | `position` | whole number | Where the change landed in the event log. Pass it as `after` on a read to see your own write. | | `webhook_id` | id (text) | The id of the webhook. | | `removed` | true or false | The removed. | ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`read_only`](https://headhoncho.app/docs/api/errors#read_only) | 403 | This credential may read this area but not change it. | | [`not_found`](https://headhoncho.app/docs/api/errors#not_found) | 404 | No such record in the companies this credential reaches. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`missing_idempotency_key`](https://headhoncho.app/docs/api/errors#missing_idempotency_key) | 400 | Send an Idempotency-Key header on every command. | | [`idempotency_mismatch`](https://headhoncho.app/docs/api/errors#idempotency_mismatch) | 409 | This Idempotency-Key was used with a different body. | | [`idempotency_in_progress`](https://headhoncho.app/docs/api/errors#idempotency_in_progress) | 409 | A command with this Idempotency-Key is still running. Wait a moment and send it again. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [Add webhook](https://headhoncho.app/docs/api/add_webhook): Give us an address and the kinds of change you want. We call it for each change, signed, and retry what fails. The signing secret is shown once. - [Change webhook](https://headhoncho.app/docs/api/change_webhook): Rename a webhook, move it to another address, change its kinds or companies, pause or resume it, or replace its secret. Send only what changes. - [Send webhook test](https://headhoncho.app/docs/api/send_webhook_test): Send a signed test event to one webhook now and say what the address answered. It is not retried and costs no delivery credit. - [Redeliver webhook](https://headhoncho.app/docs/api/redeliver_webhook): Send one delivery again, from a webhook's list of deliveries. It goes out within a minute. A change already paid for is not paid for twice. - The same records in the app: [Settings](https://headhoncho.app/docs/settings). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "accepted": true, "position": 88701, "webhook_id": "whk_6d21", "removed": true } ``` ### cURL ```bash curl -X POST "https://api.headhoncho.app/api/v1/commands/remove-webhook" \ -H "Authorization: Bearer hh_live_..." \ -H "Idempotency-Key: 6f1d2c9e-1b7a-4c1e-9a52-0d3f8e4b7a10" \ -H "Content-Type: application/json" \ -d '{ "webhook_id": "whk_6d21" }' ``` ### Python ```python import requests import uuid response = requests.post( "https://api.headhoncho.app/api/v1/commands/remove-webhook", headers={ "Authorization": "Bearer hh_live_...", "Idempotency-Key": str(uuid.uuid4()), }, json={ "webhook_id": "whk_6d21", }, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/commands/remove-webhook", { method: "POST", headers: { Authorization: "Bearer hh_live_...", "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "webhook_id": "whk_6d21" }), }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: remove_webhook Arguments: webhook_id (id, required) Access: do on Company settings Hints: readOnly=false, destructive=true, idempotent=true, openWorld=false Try asking: "Using HeadHoncho, remove webhook with webhook_id whk_6d21." ``` --- # Send webhook test Send webhook test is a command in the HeadHoncho API. Send a signed test event to one webhook now and say what the address answered. It is not retried and costs no delivery credit. Page: https://headhoncho.app/docs/api/send_webhook_test | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **Send webhook test**, HeadHoncho API v1. It is a command, sent to the base address `https://api.headhoncho.app`. `POST /api/v1/commands/test-webhook` The key needs the **Company settings** area at **do**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). It runs the app's own command `test-webhook`. Send an `Idempotency-Key` header with every call: the same key with the same body returns the first answer and runs nothing twice. See [the model](https://headhoncho.app/docs/api/model#idempotency). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `webhook_id` | id, in the JSON body | Yes | The webhook, from List webhooks. | `whk_6d21` | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back accepted, position, webhook_id, delivery_id, event_id, delivered (true when the address answered 2xx), response_code (null when nothing answered), duration_ms and error. It never deletes anything. It changes only what the command names, and it writes the change to the job's history with who asked for it. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `accepted` | true or false | True when the command ran. A command that cannot run is an error instead. | | `position` | whole number | Where the change landed in the event log. Pass it as `after` on a read to see your own write. | | `webhook_id` | id (text) | The id of the webhook. | | `delivery_id` | id (text) | The id of the delivery. | | `event_id` | id (text) | The id of the event. | | `delivered` | true or false | The delivered. | | `response_code` | whole number | The response code. | | `duration_ms` | whole number | The duration ms. | | `error` | text | The error. | ## What it sends An event named webhook.test, signed like any other, so you can check your signature code before a real change arrives. ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`read_only`](https://headhoncho.app/docs/api/errors#read_only) | 403 | This credential may read this area but not change it. | | [`not_found`](https://headhoncho.app/docs/api/errors#not_found) | 404 | No such record in the companies this credential reaches. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`missing_idempotency_key`](https://headhoncho.app/docs/api/errors#missing_idempotency_key) | 400 | Send an Idempotency-Key header on every command. | | [`idempotency_mismatch`](https://headhoncho.app/docs/api/errors#idempotency_mismatch) | 409 | This Idempotency-Key was used with a different body. | | [`idempotency_in_progress`](https://headhoncho.app/docs/api/errors#idempotency_in_progress) | 409 | A command with this Idempotency-Key is still running. Wait a moment and send it again. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [Add webhook](https://headhoncho.app/docs/api/add_webhook): Give us an address and the kinds of change you want. We call it for each change, signed, and retry what fails. The signing secret is shown once. - [Change webhook](https://headhoncho.app/docs/api/change_webhook): Rename a webhook, move it to another address, change its kinds or companies, pause or resume it, or replace its secret. Send only what changes. - [Remove webhook](https://headhoncho.app/docs/api/remove_webhook): Stop calling an address for good. Its past deliveries stay readable. - [Redeliver webhook](https://headhoncho.app/docs/api/redeliver_webhook): Send one delivery again, from a webhook's list of deliveries. It goes out within a minute. A change already paid for is not paid for twice. - The same records in the app: [Settings](https://headhoncho.app/docs/settings). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "accepted": true, "position": 88701, "webhook_id": "whk_6d21", "delivery_id": "dlv_90ab", "event_id": "test_8f2c41a0b7d35e69", "delivered": true, "response_code": 200, "duration_ms": 138, "error": "" } ``` ### cURL ```bash curl -X POST "https://api.headhoncho.app/api/v1/commands/test-webhook" \ -H "Authorization: Bearer hh_live_..." \ -H "Idempotency-Key: 6f1d2c9e-1b7a-4c1e-9a52-0d3f8e4b7a10" \ -H "Content-Type: application/json" \ -d '{ "webhook_id": "whk_6d21" }' ``` ### Python ```python import requests import uuid response = requests.post( "https://api.headhoncho.app/api/v1/commands/test-webhook", headers={ "Authorization": "Bearer hh_live_...", "Idempotency-Key": str(uuid.uuid4()), }, json={ "webhook_id": "whk_6d21", }, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/commands/test-webhook", { method: "POST", headers: { Authorization: "Bearer hh_live_...", "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "webhook_id": "whk_6d21" }), }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: send_webhook_test Arguments: webhook_id (id, required) Access: do on Company settings Hints: readOnly=false, destructive=false, idempotent=false, openWorld=false Try asking: "Using HeadHoncho, send webhook test with webhook_id whk_6d21." ``` --- # Redeliver webhook Redeliver webhook is a command in the HeadHoncho API. Send one delivery again, from a webhook's list of deliveries. It goes out within a minute. A change already paid for is not paid for twice. Page: https://headhoncho.app/docs/api/redeliver_webhook | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **Redeliver webhook**, HeadHoncho API v1. It is a command, sent to the base address `https://api.headhoncho.app`. `POST /api/v1/commands/redeliver-webhook` The key needs the **Company settings** area at **do**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). It runs the app's own command `redeliver-webhook`. Send an `Idempotency-Key` header with every call: the same key with the same body returns the first answer and runs nothing twice. See [the model](https://headhoncho.app/docs/api/model#idempotency). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `webhook_id` | id, in the JSON body | Yes | The webhook, from List webhooks. | `whk_6d21` | | `delivery_id` | id, in the JSON body | Yes | The delivery, from A webhook's deliveries. | `dlv_41c8` | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back accepted, position, webhook_id, delivery_id and status: pending until the next try answers. It never deletes anything. It changes only what the command names, and it writes the change to the job's history with who asked for it. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `accepted` | true or false | True when the command ran. A command that cannot run is an error instead. | | `position` | whole number | Where the change landed in the event log. Pass it as `after` on a read to see your own write. | | `webhook_id` | id (text) | The id of the webhook. | | `delivery_id` | id (text) | The id of the delivery. | | `status` | text | The job status. | ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`read_only`](https://headhoncho.app/docs/api/errors#read_only) | 403 | This credential may read this area but not change it. | | [`not_found`](https://headhoncho.app/docs/api/errors#not_found) | 404 | No such record in the companies this credential reaches. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`missing_idempotency_key`](https://headhoncho.app/docs/api/errors#missing_idempotency_key) | 400 | Send an Idempotency-Key header on every command. | | [`idempotency_mismatch`](https://headhoncho.app/docs/api/errors#idempotency_mismatch) | 409 | This Idempotency-Key was used with a different body. | | [`idempotency_in_progress`](https://headhoncho.app/docs/api/errors#idempotency_in_progress) | 409 | A command with this Idempotency-Key is still running. Wait a moment and send it again. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [Add webhook](https://headhoncho.app/docs/api/add_webhook): Give us an address and the kinds of change you want. We call it for each change, signed, and retry what fails. The signing secret is shown once. - [Change webhook](https://headhoncho.app/docs/api/change_webhook): Rename a webhook, move it to another address, change its kinds or companies, pause or resume it, or replace its secret. Send only what changes. - [Remove webhook](https://headhoncho.app/docs/api/remove_webhook): Stop calling an address for good. Its past deliveries stay readable. - [Send webhook test](https://headhoncho.app/docs/api/send_webhook_test): Send a signed test event to one webhook now and say what the address answered. It is not retried and costs no delivery credit. - The same records in the app: [Settings](https://headhoncho.app/docs/settings). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "accepted": true, "position": 88701, "webhook_id": "whk_6d21", "delivery_id": "dlv_41c8", "status": "pending" } ``` ### cURL ```bash curl -X POST "https://api.headhoncho.app/api/v1/commands/redeliver-webhook" \ -H "Authorization: Bearer hh_live_..." \ -H "Idempotency-Key: 6f1d2c9e-1b7a-4c1e-9a52-0d3f8e4b7a10" \ -H "Content-Type: application/json" \ -d '{ "webhook_id": "whk_6d21", "delivery_id": "dlv_41c8" }' ``` ### Python ```python import requests import uuid response = requests.post( "https://api.headhoncho.app/api/v1/commands/redeliver-webhook", headers={ "Authorization": "Bearer hh_live_...", "Idempotency-Key": str(uuid.uuid4()), }, json={ "webhook_id": "whk_6d21", "delivery_id": "dlv_41c8", }, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/commands/redeliver-webhook", { method: "POST", headers: { Authorization: "Bearer hh_live_...", "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "webhook_id": "whk_6d21", "delivery_id": "dlv_41c8" }), }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: redeliver_webhook Arguments: webhook_id (id, required), delivery_id (id, required) Access: do on Company settings Hints: readOnly=false, destructive=false, idempotent=true, openWorld=false Try asking: "Using HeadHoncho, redeliver webhook with webhook_id whk_6d21 and delivery_id dlv_41c8." ``` --- # List job photos List job photos is a read in the HeadHoncho API. The photos stored on a job, oldest first, each with a link that opens it for one minute. Page: https://headhoncho.app/docs/api/list_job_photos | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **List job photos**, HeadHoncho API v1. It is a read, sent to the base address `https://api.headhoncho.app`. `GET /api/v1/jobs/{job_id}/photos` The key needs the **Jobs** area at **read**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). Send your key as `Authorization: Bearer hh_live_...`. See [API keys](https://headhoncho.app/docs/api/keys). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `job_id` | id, in the path | Yes | The job id, or its number. | `job_1138` | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back job (id and number), items and count. Each item is a photo: id, content_type, byte_size, stored_at, note_id (the note it sits under, or null) and url, a link that works for expires_in seconds. Ask again for a new link. With personal details hidden, url is left empty, because a photo can show a street or a face. It never changes a record. It only reads the companies the key reaches. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `job` | object | The job. | | `job.id` | id (text) | The id of this record. Ids are opaque text: keep them exactly as given. | | `job.number` | whole number | The number people say out loud, such as the job number. | | `items` | list of objects | The rows on this page. | | `items[].id` | id (text) | The id of this record. Ids are opaque text: keep them exactly as given. | | `items[].content_type` | text | The content type. | | `items[].byte_size` | whole number | The byte size. | | `items[].stored_at` | time (ISO 8601, with offset) | When it was stored. Carries its offset from UTC; `Z` is UTC. | | `items[].note_id` | value or null | The id of the note. | | `items[].url` | text | The link. | | `items[].expires_in` | whole number | Seconds until the link stops working. | | `count` | whole number | How many match in all, across every page. | ## Photos the technician sent by text A photo that came in on a text is counted on the job but never stored, so it is not listed here. Only photos someone uploaded are. ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`not_found`](https://headhoncho.app/docs/api/errors#not_found) | 404 | No such record in the companies this credential reaches. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [List jobs](https://headhoncho.app/docs/api/list_jobs): Jobs and leads in the companies this credential reaches, newest first, with status, technician, schedule, money and the ad click each came from. - [Get job](https://headhoncho.app/docs/api/get_job): One job or lead: who, where, when, which status, which technicians, the money on it and the ad click it came from. - [Get job history](https://headhoncho.app/docs/api/get_job_history): Everything that happened to a job, in order, with who did it: created, moved, assigned, noted, paid. The same log the job page shows. - [Get job log](https://headhoncho.app/docs/api/get_job_log): A job's timeline in plain words, one line per thing that happened: notes, moves, texts, money, the rules and the AI, each with who did it. - [List situations](https://headhoncho.app/docs/api/list_situations): The situations the AI dispatcher is working on jobs now: what came up, the plan, and which step it is on. - [Get photo](https://headhoncho.app/docs/api/get_photo): One stored photo and a fresh link to its file. The link works for one minute. - [Get calendar](https://headhoncho.app/docs/api/get_calendar): Every job with a booked time between two days, earliest first. Canceled and closed jobs are left out, as on the app's calendar. - [List unscheduled jobs](https://headhoncho.app/docs/api/list_unscheduled_jobs): Open jobs and leads that have no booked time yet, the ones that waited longest first. - [Export jobs](https://headhoncho.app/docs/api/export_jobs): Jobs as a CSV file, newest first, up to 10,000 rows: ticket, technicians, status, dates, address, customer and price. - [Search jobs](https://headhoncho.app/docs/api/search_jobs): Find jobs by ticket number, customer, address or technician name, and technicians by name. - [Get automatic status](https://headhoncho.app/docs/api/get_automatic_status): Whether a person set this job's status by hand, why its facts do not hold it, and where Back to automatic would put it. - [Get job detour](https://headhoncho.app/docs/api/get_job_detour): Whether a job is on a detour, such as Waiting on parts, and where Resolve would put it. - [List job reassignments](https://headhoncho.app/docs/api/list_job_reassignments): The times this job was handed from one technician to another, oldest first, and how far each one got. - [List calendar reassignments](https://headhoncho.app/docs/api/list_calendar_reassignments): Every reassignment on a job booked in a window: open ones, and ones that closed today. - The same records in the app: [the Jobs panel](https://headhoncho.app/docs/jobs). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "job": { "id": "job_1138", "number": 1138 }, "items": [ { "id": "pho_5d21", "content_type": "image/jpeg", "byte_size": 2481220, "stored_at": "2026-10-16T11:42:10Z", "note_id": null, "url": "https://files.headhoncho.app/photos/pho_5d21.jpg?signature=k7Qm...", "expires_in": 60 } ], "count": 1 } ``` ### cURL ```bash curl "https://api.headhoncho.app/api/v1/jobs/job_1138/photos" \ -H "Authorization: Bearer hh_live_..." ``` ### Python ```python import requests response = requests.get( "https://api.headhoncho.app/api/v1/jobs/job_1138/photos", headers={"Authorization": "Bearer hh_live_..."}, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/jobs/job_1138/photos", { headers: { Authorization: "Bearer hh_live_..." }, }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: list_job_photos Arguments: job_id (id, required) Access: read on Jobs Hints: readOnly=true, destructive=false, idempotent=true, openWorld=false Try asking: "Using HeadHoncho, list job photos with job_id job_1138." ``` --- # Get photo Get photo is a read in the HeadHoncho API. One stored photo and a fresh link to its file. The link works for one minute. Page: https://headhoncho.app/docs/api/get_photo | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **Get photo**, HeadHoncho API v1. It is a read, sent to the base address `https://api.headhoncho.app`. `GET /api/v1/photos/{photo_id}` The key needs the **Jobs** area at **read**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). Send your key as `Authorization: Bearer hh_live_...`. See [API keys](https://headhoncho.app/docs/api/keys). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `photo_id` | id, in the path | Yes | The photo id, from A job's photos. | `pho_5d21` | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back The photo: id, job (id and number), content_type, byte_size, stored_at, note_id and url, a link to the file that works for expires_in seconds. A photo on a job in Trash is not found. A credential that hides personal details is refused here, because the file can show a street or a face. It never changes a record. It only reads the companies the key reaches. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `id` | id (text) | The id of this record. Ids are opaque text: keep them exactly as given. | | `content_type` | text | The content type. | | `byte_size` | whole number | The byte size. | | `stored_at` | time (ISO 8601, with offset) | When it was stored. Carries its offset from UTC; `Z` is UTC. | | `note_id` | value or null | The id of the note. | | `url` | text | The link. | | `expires_in` | whole number | Seconds until the link stops working. | | `job` | object | The job. | | `job.id` | id (text) | The id of this record. Ids are opaque text: keep them exactly as given. | | `job.number` | whole number | The number people say out loud, such as the job number. | ## The file itself The answer is a link, never the picture. Open the link with a plain GET, before it expires. Do not send your key to it. ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`not_found`](https://headhoncho.app/docs/api/errors#not_found) | 404 | No such record in the companies this credential reaches. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [List jobs](https://headhoncho.app/docs/api/list_jobs): Jobs and leads in the companies this credential reaches, newest first, with status, technician, schedule, money and the ad click each came from. - [Get job](https://headhoncho.app/docs/api/get_job): One job or lead: who, where, when, which status, which technicians, the money on it and the ad click it came from. - [Get job history](https://headhoncho.app/docs/api/get_job_history): Everything that happened to a job, in order, with who did it: created, moved, assigned, noted, paid. The same log the job page shows. - [Get job log](https://headhoncho.app/docs/api/get_job_log): A job's timeline in plain words, one line per thing that happened: notes, moves, texts, money, the rules and the AI, each with who did it. - [List situations](https://headhoncho.app/docs/api/list_situations): The situations the AI dispatcher is working on jobs now: what came up, the plan, and which step it is on. - [List job photos](https://headhoncho.app/docs/api/list_job_photos): The photos stored on a job, oldest first, each with a link that opens it for one minute. - [Get calendar](https://headhoncho.app/docs/api/get_calendar): Every job with a booked time between two days, earliest first. Canceled and closed jobs are left out, as on the app's calendar. - [List unscheduled jobs](https://headhoncho.app/docs/api/list_unscheduled_jobs): Open jobs and leads that have no booked time yet, the ones that waited longest first. - [Export jobs](https://headhoncho.app/docs/api/export_jobs): Jobs as a CSV file, newest first, up to 10,000 rows: ticket, technicians, status, dates, address, customer and price. - [Search jobs](https://headhoncho.app/docs/api/search_jobs): Find jobs by ticket number, customer, address or technician name, and technicians by name. - [Get automatic status](https://headhoncho.app/docs/api/get_automatic_status): Whether a person set this job's status by hand, why its facts do not hold it, and where Back to automatic would put it. - [Get job detour](https://headhoncho.app/docs/api/get_job_detour): Whether a job is on a detour, such as Waiting on parts, and where Resolve would put it. - [List job reassignments](https://headhoncho.app/docs/api/list_job_reassignments): The times this job was handed from one technician to another, oldest first, and how far each one got. - [List calendar reassignments](https://headhoncho.app/docs/api/list_calendar_reassignments): Every reassignment on a job booked in a window: open ones, and ones that closed today. - The same records in the app: [the Jobs panel](https://headhoncho.app/docs/jobs). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "id": "pho_5d21", "content_type": "image/jpeg", "byte_size": 2481220, "stored_at": "2026-10-16T11:42:10Z", "note_id": null, "url": "https://files.headhoncho.app/photos/pho_5d21.jpg?signature=k7Qm...", "expires_in": 60, "job": { "id": "job_1138", "number": 1138 } } ``` ### cURL ```bash curl "https://api.headhoncho.app/api/v1/photos/pho_5d21" \ -H "Authorization: Bearer hh_live_..." ``` ### Python ```python import requests response = requests.get( "https://api.headhoncho.app/api/v1/photos/pho_5d21", headers={"Authorization": "Bearer hh_live_..."}, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/photos/pho_5d21", { headers: { Authorization: "Bearer hh_live_..." }, }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: get_photo Arguments: photo_id (id, required) Access: read on Jobs Hints: readOnly=true, destructive=false, idempotent=true, openWorld=false Try asking: "Using HeadHoncho, get photo with photo_id pho_5d21." ``` --- # Get calendar Get calendar is a read in the HeadHoncho API. Every job with a booked time between two days, earliest first. Canceled and closed jobs are left out, as on the app's calendar. Page: https://headhoncho.app/docs/api/get_calendar | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **Get calendar**, HeadHoncho API v1. It is a read, sent to the base address `https://api.headhoncho.app`. `GET /api/v1/calendar` The key needs the **Jobs** area at **read**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). Send your key as `Authorization: Bearer hh_live_...`. See [API keys](https://headhoncho.app/docs/api/keys). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `company_id` | id, in the query | No | One company. Default: every company the credential reaches. | `cmp_14f5` | | `from` | date, in the query | No | The first day, in the company's time zone. Default: the first of this month. | `2026-10-01` | | `to` | date, in the query | No | The last day, inclusive. Default: the end of that month. At most 500 days. | `2026-10-31` | | `limit` | number, in the query | No | 1 to 1000. Default 500. | `500` | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back from and to (the days read), time_zone, items (one job each in the Get a job shape, earliest booked time first), and count, how many jobs are booked in the window in all. The day is read on the clock of the company named, or of the first company when none is named. Trashed jobs are never listed. It never changes a record. It only reads the companies the key reaches. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `from` | date (YYYY-MM-DD) | The first day of the range, inclusive. | | `to` | date (YYYY-MM-DD) | The last day of the range, inclusive. | | `time_zone` | text | The company's time zone name, such as America/Chicago. | | `items` | list of objects | The rows on this page. | | `items[].id` | id (text) | The id of this record. Ids are opaque text: keep them exactly as given. | | `items[].number` | whole number | The number people say out loud, such as the job number. | | `items[].company` | object | The company. | | `items[].company.id` | id (text) | The id of this record. Ids are opaque text: keep them exactly as given. | | `items[].company.name` | text | The name, as the app shows it. | | `items[].client` | object | The client. | | `items[].client.id` | id (text) | The id of this record. Ids are opaque text: keep them exactly as given. | | `items[].client.name` | text | The name, as the app shows it. | | `items[].client.phone` | text | A phone number. Hidden when the key hides personal details. | | `items[].client.second_phone` | text | A second phone number. Hidden when the key hides personal details. | | `items[].address` | object | The address. | | `items[].address.line1` | text | The street address. Hidden when the key hides personal details. | | `items[].address.line2` | text | The apartment or suite line. Hidden when the key hides personal details. | | `items[].address.city` | text | The city. | | `items[].address.state` | text | The state or region. | | `items[].address.postal_code` | text | The postal code. | | `items[].address.one_line` | text | The whole address on one line. Hidden when the key hides personal details. | | `items[].job_type` | object | The job type. | | `items[].job_type.id` | id (text) | The id of this record. Ids are opaque text: keep them exactly as given. | | `items[].job_type.name` | text | The name, as the app shows it. | | `items[].status` | object | The job status. | | `items[].status.id` | id (text) | The id of this record. Ids are opaque text: keep them exactly as given. | | `items[].status.name` | text | The name, as the app shows it. | | `items[].status.slug` | text | The same name as a lowercase code word. Match on this, not on the name. | | `items[].status.since` | time (ISO 8601, with offset) | From when this has been true. Carries its offset from UTC; `Z` is UTC. | | `items[].technicians` | list of objects | The technicians. | | `items[].technicians[].id` | id (text) | The id of this record. Ids are opaque text: keep them exactly as given. | | `items[].technicians[].name` | text | The name, as the app shows it. | | `items[].scheduled_start` | time (ISO 8601, with offset) | When the visit is planned to start. Carries its offset from UTC; `Z` is UTC. | | `items[].scheduled_end` | time (ISO 8601, with offset) | When the visit is planned to end. Carries its offset from UTC; `Z` is UTC. | | `items[].collected` | money (number) | The money received on the job so far. In the company's currency. | | `items[].profit` | money (number) | The job's profit, worked out the way the app works it out. In the company's currency. | | `items[].currency` | text | The three-letter currency code (ISO 4217). Every money value in the answer is in it. | | `items[].source` | object | The source. | | `items[].source.label` | text | The name the app shows for it. | | `items[].source.filled_by` | text | How the job source was filled in: `call`, `form` or by hand. | | `items[].source.click_id` | id (text) | The Google click id (gclid) the call or visit carried. | | `items[].source.call_id` | id (text) | The id of the call. | | `items[].source.call_at` | time (ISO 8601, with offset) | When the call happened. Carries its offset from UTC; `Z` is UTC. | | `items[].source.campaign` | text | The ad campaign's name. | | `items[].is_lead` | true or false | True while the job is still a lead. | | `items[].notes` | text | Free-text notes. | | `items[].created_at` | time (ISO 8601, with offset) | When it was created. Carries its offset from UTC; `Z` is UTC. | | `items[].closed_at` | time or null | When it was closed. | | `items[].canceled_at` | time or null | When it was canceled. | | `items[].archived_at` | time or null | When it was archived. | | `items[].trashed_at` | time or null | When it was trashed. | | `count` | whole number | How many match in all, across every page. | ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`not_found`](https://headhoncho.app/docs/api/errors#not_found) | 404 | No such record in the companies this credential reaches. | | [`out_of_scope`](https://headhoncho.app/docs/api/errors#out_of_scope) | 404 | No such company in the companies this credential reaches. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [List jobs](https://headhoncho.app/docs/api/list_jobs): Jobs and leads in the companies this credential reaches, newest first, with status, technician, schedule, money and the ad click each came from. - [Get job](https://headhoncho.app/docs/api/get_job): One job or lead: who, where, when, which status, which technicians, the money on it and the ad click it came from. - [Get job history](https://headhoncho.app/docs/api/get_job_history): Everything that happened to a job, in order, with who did it: created, moved, assigned, noted, paid. The same log the job page shows. - [Get job log](https://headhoncho.app/docs/api/get_job_log): A job's timeline in plain words, one line per thing that happened: notes, moves, texts, money, the rules and the AI, each with who did it. - [List situations](https://headhoncho.app/docs/api/list_situations): The situations the AI dispatcher is working on jobs now: what came up, the plan, and which step it is on. - [List job photos](https://headhoncho.app/docs/api/list_job_photos): The photos stored on a job, oldest first, each with a link that opens it for one minute. - [Get photo](https://headhoncho.app/docs/api/get_photo): One stored photo and a fresh link to its file. The link works for one minute. - [List unscheduled jobs](https://headhoncho.app/docs/api/list_unscheduled_jobs): Open jobs and leads that have no booked time yet, the ones that waited longest first. - [Export jobs](https://headhoncho.app/docs/api/export_jobs): Jobs as a CSV file, newest first, up to 10,000 rows: ticket, technicians, status, dates, address, customer and price. - [Search jobs](https://headhoncho.app/docs/api/search_jobs): Find jobs by ticket number, customer, address or technician name, and technicians by name. - [Get automatic status](https://headhoncho.app/docs/api/get_automatic_status): Whether a person set this job's status by hand, why its facts do not hold it, and where Back to automatic would put it. - [Get job detour](https://headhoncho.app/docs/api/get_job_detour): Whether a job is on a detour, such as Waiting on parts, and where Resolve would put it. - [List job reassignments](https://headhoncho.app/docs/api/list_job_reassignments): The times this job was handed from one technician to another, oldest first, and how far each one got. - [List calendar reassignments](https://headhoncho.app/docs/api/list_calendar_reassignments): Every reassignment on a job booked in a window: open ones, and ones that closed today. - The same records in the app: [the Jobs panel](https://headhoncho.app/docs/jobs). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "from": "2026-10-01", "to": "2026-10-31", "time_zone": "America/Chicago", "items": [ { "id": "job_1138", "number": 1138, "company": { "id": "cmp_14f5", "name": "Sunrise Moving" }, "client": { "id": "cli_77a0", "name": "R. Azoulay", "phone": "+12175550142", "second_phone": "" }, "address": { "line1": "2590 Main St", "line2": "", "city": "Bloomington", "state": "IL", "postal_code": "61701", "one_line": "2590 Main St, Bloomington, IL 61701" }, "job_type": { "id": "jt_02", "name": "Local move" }, "status": { "id": "st_02", "name": "Scheduled", "slug": "scheduled", "since": "2026-10-12T15:04:10Z" }, "technicians": [ { "id": "wrk_3b90", "name": "Dana R." } ], "scheduled_start": "2026-10-16T09:00:00-05:00", "scheduled_end": "2026-10-16T11:00:00-05:00", "collected": 0.0, "profit": 0.0, "currency": "USD", "source": { "label": "Google Ads", "filled_by": "call", "click_id": "Cj0KCQjw...", "call_id": "CAL8f2e1", "call_at": "2026-10-11T18:22:03Z", "campaign": "Moving - Bloomington" }, "is_lead": false, "notes": "Two flights of stairs", "created_at": "2026-10-11T18:25:40Z", "closed_at": null, "canceled_at": null, "archived_at": null, "trashed_at": null } ], "count": 1 } ``` ### cURL ```bash curl "https://api.headhoncho.app/api/v1/calendar?company_id=cmp_14f5&from=2026-10-01" \ -H "Authorization: Bearer hh_live_..." ``` ### Python ```python import requests response = requests.get( "https://api.headhoncho.app/api/v1/calendar", headers={"Authorization": "Bearer hh_live_..."}, params={ "company_id": "cmp_14f5", "from": "2026-10-01", }, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/calendar?company_id=cmp_14f5&from=2026-10-01", { headers: { Authorization: "Bearer hh_live_..." }, }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: get_calendar Arguments: company_id (id, optional), from (date, optional), to (date, optional), limit (number, optional) Access: read on Jobs Hints: readOnly=true, destructive=false, idempotent=true, openWorld=false Try asking: "Using HeadHoncho, get calendar with company_id cmp_14f5." ``` --- # List unscheduled jobs List unscheduled jobs is a read in the HeadHoncho API. Open jobs and leads that have no booked time yet, the ones that waited longest first. Page: https://headhoncho.app/docs/api/list_unscheduled_jobs | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **List unscheduled jobs**, HeadHoncho API v1. It is a read, sent to the base address `https://api.headhoncho.app`. `GET /api/v1/jobs/unscheduled` The key needs the **Jobs** area at **read**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). Send your key as `Authorization: Bearer hh_live_...`. See [API keys](https://headhoncho.app/docs/api/keys). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `company_id` | id, in the query | No | One company. Default: every company the credential reaches. | `cmp_14f5` | | `limit` | number, in the query | No | 1 to 200. Default 200. | `200` | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back items, one job each in the Get a job shape plus waited_days (whole days since it was opened), oldest first; count, how many wait in all; time_zone and today. Canceled and closed jobs are left out. Trashed jobs are never listed. It never changes a record. It only reads the companies the key reaches. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `items` | list of objects | The rows on this page. | | `items[].id` | id (text) | The id of this record. Ids are opaque text: keep them exactly as given. | | `items[].number` | whole number | The number people say out loud, such as the job number. | | `items[].company` | object | The company. | | `items[].company.id` | id (text) | The id of this record. Ids are opaque text: keep them exactly as given. | | `items[].company.name` | text | The name, as the app shows it. | | `items[].client` | object | The client. | | `items[].client.id` | id (text) | The id of this record. Ids are opaque text: keep them exactly as given. | | `items[].client.name` | text | The name, as the app shows it. | | `items[].client.phone` | text | A phone number. Hidden when the key hides personal details. | | `items[].client.second_phone` | text | A second phone number. Hidden when the key hides personal details. | | `items[].address` | object | The address. | | `items[].address.line1` | text | The street address. Hidden when the key hides personal details. | | `items[].address.line2` | text | The apartment or suite line. Hidden when the key hides personal details. | | `items[].address.city` | text | The city. | | `items[].address.state` | text | The state or region. | | `items[].address.postal_code` | text | The postal code. | | `items[].address.one_line` | text | The whole address on one line. Hidden when the key hides personal details. | | `items[].job_type` | object | The job type. | | `items[].job_type.id` | id (text) | The id of this record. Ids are opaque text: keep them exactly as given. | | `items[].job_type.name` | text | The name, as the app shows it. | | `items[].status` | object | The job status. | | `items[].status.id` | id (text) | The id of this record. Ids are opaque text: keep them exactly as given. | | `items[].status.name` | text | The name, as the app shows it. | | `items[].status.slug` | text | The same name as a lowercase code word. Match on this, not on the name. | | `items[].status.since` | time (ISO 8601, with offset) | From when this has been true. Carries its offset from UTC; `Z` is UTC. | | `items[].technicians` | list of objects | The technicians. | | `items[].technicians[].id` | id (text) | The id of this record. Ids are opaque text: keep them exactly as given. | | `items[].technicians[].name` | text | The name, as the app shows it. | | `items[].scheduled_start` | value or null | When the visit is planned to start. | | `items[].scheduled_end` | value or null | When the visit is planned to end. | | `items[].collected` | money (number) | The money received on the job so far. In the company's currency. | | `items[].profit` | money (number) | The job's profit, worked out the way the app works it out. In the company's currency. | | `items[].currency` | text | The three-letter currency code (ISO 4217). Every money value in the answer is in it. | | `items[].source` | object | The source. | | `items[].source.label` | text | The name the app shows for it. | | `items[].source.filled_by` | text | How the job source was filled in: `call`, `form` or by hand. | | `items[].source.click_id` | id (text) | The Google click id (gclid) the call or visit carried. | | `items[].source.call_id` | id (text) | The id of the call. | | `items[].source.call_at` | time (ISO 8601, with offset) | When the call happened. Carries its offset from UTC; `Z` is UTC. | | `items[].source.campaign` | text | The ad campaign's name. | | `items[].is_lead` | true or false | True while the job is still a lead. | | `items[].notes` | text | Free-text notes. | | `items[].created_at` | time (ISO 8601, with offset) | When it was created. Carries its offset from UTC; `Z` is UTC. | | `items[].closed_at` | time or null | When it was closed. | | `items[].canceled_at` | time or null | When it was canceled. | | `items[].archived_at` | time or null | When it was archived. | | `items[].trashed_at` | time or null | When it was trashed. | | `items[].waited_days` | whole number | The waited days. | | `count` | whole number | How many match in all, across every page. | | `time_zone` | text | The company's time zone name, such as America/Chicago. | | `today` | date (YYYY-MM-DD) | The today. | ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`not_found`](https://headhoncho.app/docs/api/errors#not_found) | 404 | No such record in the companies this credential reaches. | | [`out_of_scope`](https://headhoncho.app/docs/api/errors#out_of_scope) | 404 | No such company in the companies this credential reaches. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [List jobs](https://headhoncho.app/docs/api/list_jobs): Jobs and leads in the companies this credential reaches, newest first, with status, technician, schedule, money and the ad click each came from. - [Get job](https://headhoncho.app/docs/api/get_job): One job or lead: who, where, when, which status, which technicians, the money on it and the ad click it came from. - [Get job history](https://headhoncho.app/docs/api/get_job_history): Everything that happened to a job, in order, with who did it: created, moved, assigned, noted, paid. The same log the job page shows. - [Get job log](https://headhoncho.app/docs/api/get_job_log): A job's timeline in plain words, one line per thing that happened: notes, moves, texts, money, the rules and the AI, each with who did it. - [List situations](https://headhoncho.app/docs/api/list_situations): The situations the AI dispatcher is working on jobs now: what came up, the plan, and which step it is on. - [List job photos](https://headhoncho.app/docs/api/list_job_photos): The photos stored on a job, oldest first, each with a link that opens it for one minute. - [Get photo](https://headhoncho.app/docs/api/get_photo): One stored photo and a fresh link to its file. The link works for one minute. - [Get calendar](https://headhoncho.app/docs/api/get_calendar): Every job with a booked time between two days, earliest first. Canceled and closed jobs are left out, as on the app's calendar. - [Export jobs](https://headhoncho.app/docs/api/export_jobs): Jobs as a CSV file, newest first, up to 10,000 rows: ticket, technicians, status, dates, address, customer and price. - [Search jobs](https://headhoncho.app/docs/api/search_jobs): Find jobs by ticket number, customer, address or technician name, and technicians by name. - [Get automatic status](https://headhoncho.app/docs/api/get_automatic_status): Whether a person set this job's status by hand, why its facts do not hold it, and where Back to automatic would put it. - [Get job detour](https://headhoncho.app/docs/api/get_job_detour): Whether a job is on a detour, such as Waiting on parts, and where Resolve would put it. - [List job reassignments](https://headhoncho.app/docs/api/list_job_reassignments): The times this job was handed from one technician to another, oldest first, and how far each one got. - [List calendar reassignments](https://headhoncho.app/docs/api/list_calendar_reassignments): Every reassignment on a job booked in a window: open ones, and ones that closed today. - The same records in the app: [the Jobs panel](https://headhoncho.app/docs/jobs). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "items": [ { "id": "job_1138", "number": 1138, "company": { "id": "cmp_14f5", "name": "Sunrise Moving" }, "client": { "id": "cli_77a0", "name": "R. Azoulay", "phone": "+12175550142", "second_phone": "" }, "address": { "line1": "2590 Main St", "line2": "", "city": "Bloomington", "state": "IL", "postal_code": "61701", "one_line": "2590 Main St, Bloomington, IL 61701" }, "job_type": { "id": "jt_02", "name": "Local move" }, "status": { "id": "st_01", "name": "Draft", "slug": "draft", "since": "2026-10-20T15:04:10Z" }, "technicians": [ { "id": "wrk_3b90", "name": "Dana R." } ], "scheduled_start": null, "scheduled_end": null, "collected": 0.0, "profit": 0.0, "currency": "USD", "source": { "label": "Google Ads", "filled_by": "call", "click_id": "Cj0KCQjw...", "call_id": "CAL8f2e1", "call_at": "2026-10-11T18:22:03Z", "campaign": "Moving - Bloomington" }, "is_lead": true, "notes": "Two flights of stairs", "created_at": "2026-10-11T18:25:40Z", "closed_at": null, "canceled_at": null, "archived_at": null, "trashed_at": null, "waited_days": 6 } ], "count": 12, "time_zone": "America/Chicago", "today": "2026-10-26" } ``` ### cURL ```bash curl "https://api.headhoncho.app/api/v1/jobs/unscheduled?company_id=cmp_14f5&limit=200" \ -H "Authorization: Bearer hh_live_..." ``` ### Python ```python import requests response = requests.get( "https://api.headhoncho.app/api/v1/jobs/unscheduled", headers={"Authorization": "Bearer hh_live_..."}, params={ "company_id": "cmp_14f5", "limit": "200", }, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/jobs/unscheduled?company_id=cmp_14f5&limit=200", { headers: { Authorization: "Bearer hh_live_..." }, }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: list_unscheduled_jobs Arguments: company_id (id, optional), limit (number, optional) Access: read on Jobs Hints: readOnly=true, destructive=false, idempotent=true, openWorld=false Try asking: "Using HeadHoncho, list unscheduled jobs with company_id cmp_14f5." ``` --- # Export jobs Export jobs is a read in the HeadHoncho API. Jobs as a CSV file, newest first, up to 10,000 rows: ticket, technicians, status, dates, address, customer and price. Page: https://headhoncho.app/docs/api/export_jobs | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **Export jobs**, HeadHoncho API v1. It is a read, sent to the base address `https://api.headhoncho.app`. `GET /api/v1/jobs/export` The key needs the **Jobs** area at **read**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). Send your key as `Authorization: Bearer hh_live_...`. See [API keys](https://headhoncho.app/docs/api/keys). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `company_id` | id, in the query | No | One company. Default: every company the credential reaches. | `cmp_14f5` | | `status` | text, in the query | No | A status name or slug from Who am I. | `scheduled` | | `worker_id` | id, in the query | No | Jobs this technician or subcontractor is on. | `wrk_3b90` | | `from` | date, in the query | No | Created on or after this day, in the company's time zone. | `2026-10-01` | | `to` | date, in the query | No | Created on or before this day. | `2026-10-31` | | `leads` | text, in the query | No | include (default), only, or exclude. One of `include`, `only`, `exclude`. | `include` | | `bin` | text, in the query | No | open (default), active or archived. Trash is never exported. One of `open`, `active`, `archived`. | `open` | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back Over the API: the CSV itself (text/csv). Over MCP: a download link that works once for five minutes, so the file never passes through the AI. One row per job; the columns are the ones the app's own jobs export prints. With personal details hidden, names become initials, phones keep four digits and addresses are empty. It never changes a record. It only reads the companies the key reaches. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `download` | object | The download. | | `download.url` | text | The link. | | `download.expires_in` | whole number | Seconds until the link stops working. | | `download.filename` | text | The name of the file. | ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`not_found`](https://headhoncho.app/docs/api/errors#not_found) | 404 | No such record in the companies this credential reaches. | | [`out_of_scope`](https://headhoncho.app/docs/api/errors#out_of_scope) | 404 | No such company in the companies this credential reaches. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [List jobs](https://headhoncho.app/docs/api/list_jobs): Jobs and leads in the companies this credential reaches, newest first, with status, technician, schedule, money and the ad click each came from. - [Get job](https://headhoncho.app/docs/api/get_job): One job or lead: who, where, when, which status, which technicians, the money on it and the ad click it came from. - [Get job history](https://headhoncho.app/docs/api/get_job_history): Everything that happened to a job, in order, with who did it: created, moved, assigned, noted, paid. The same log the job page shows. - [Get job log](https://headhoncho.app/docs/api/get_job_log): A job's timeline in plain words, one line per thing that happened: notes, moves, texts, money, the rules and the AI, each with who did it. - [List situations](https://headhoncho.app/docs/api/list_situations): The situations the AI dispatcher is working on jobs now: what came up, the plan, and which step it is on. - [List job photos](https://headhoncho.app/docs/api/list_job_photos): The photos stored on a job, oldest first, each with a link that opens it for one minute. - [Get photo](https://headhoncho.app/docs/api/get_photo): One stored photo and a fresh link to its file. The link works for one minute. - [Get calendar](https://headhoncho.app/docs/api/get_calendar): Every job with a booked time between two days, earliest first. Canceled and closed jobs are left out, as on the app's calendar. - [List unscheduled jobs](https://headhoncho.app/docs/api/list_unscheduled_jobs): Open jobs and leads that have no booked time yet, the ones that waited longest first. - [Search jobs](https://headhoncho.app/docs/api/search_jobs): Find jobs by ticket number, customer, address or technician name, and technicians by name. - [Get automatic status](https://headhoncho.app/docs/api/get_automatic_status): Whether a person set this job's status by hand, why its facts do not hold it, and where Back to automatic would put it. - [Get job detour](https://headhoncho.app/docs/api/get_job_detour): Whether a job is on a detour, such as Waiting on parts, and where Resolve would put it. - [List job reassignments](https://headhoncho.app/docs/api/list_job_reassignments): The times this job was handed from one technician to another, oldest first, and how far each one got. - [List calendar reassignments](https://headhoncho.app/docs/api/list_calendar_reassignments): Every reassignment on a job booked in a window: open ones, and ones that closed today. - The same records in the app: [the Jobs panel](https://headhoncho.app/docs/jobs). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer This is the answer over MCP. Over the API the answer is the file itself, as text/csv. ```json { "download": { "url": "https://api.headhoncho.app/api/v1/jobs/export?company_id=cmp_14f5&from=2026-10-01&to=2026-10-31&once=Zq8d...", "expires_in": 300, "filename": "jobs-20261026-0915.csv" } } ``` ### cURL ```bash curl "https://api.headhoncho.app/api/v1/jobs/export?company_id=cmp_14f5&status=scheduled" \ -H "Authorization: Bearer hh_live_..." -o file.csv ``` ### Python ```python import requests response = requests.get( "https://api.headhoncho.app/api/v1/jobs/export", headers={"Authorization": "Bearer hh_live_..."}, params={ "company_id": "cmp_14f5", "status": "scheduled", }, ) response.raise_for_status() open("file.csv", "wb").write(response.content) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/jobs/export?company_id=cmp_14f5&status=scheduled", { headers: { Authorization: "Bearer hh_live_..." }, }); const data = await response.text(); console.log(data); ``` ### Your AI ```text Tool: export_jobs Arguments: company_id (id, optional), status (text, optional), worker_id (id, optional), from (date, optional), to (date, optional), leads (text, optional), bin (text, optional) Access: read on Jobs Hints: readOnly=true, destructive=false, idempotent=true, openWorld=false Try asking: "Using HeadHoncho, export jobs with company_id cmp_14f5." ``` --- # Search jobs Search jobs is a read in the HeadHoncho API. Find jobs by ticket number, customer, address or technician name, and technicians by name. Page: https://headhoncho.app/docs/api/search_jobs | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **Search jobs**, HeadHoncho API v1. It is a read, sent to the base address `https://api.headhoncho.app`. `GET /api/v1/search` The key needs the **Jobs** area at **read**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). Send your key as `Authorization: Bearer hh_live_...`. See [API keys](https://headhoncho.app/docs/api/keys). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `q` | text, in the query | Yes | What to look for, up to 100 characters. A ticket number such as 1138 or #1138 finds that job. Other text needs a word of three letters or more; every word must match. | `azoulay oak` | | `company_id` | id, in the query | No | One company. Default: every company the credential reaches. | `cmp_14f5` | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back query, jobs (up to 8, newest first, one job each in the Get a job shape; archived jobs are found, Trash is not), technicians (up to 5: id, name, role) and timed_out, true when the search was cut short and the lists may be empty for that reason. This finds; it does not filter a list. It never changes a record. It only reads the companies the key reaches. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `query` | text | The query. | | `jobs` | list of objects | The jobs. | | `jobs[].id` | id (text) | The id of this record. Ids are opaque text: keep them exactly as given. | | `jobs[].number` | whole number | The number people say out loud, such as the job number. | | `jobs[].company` | object | The company. | | `jobs[].company.id` | id (text) | The id of this record. Ids are opaque text: keep them exactly as given. | | `jobs[].company.name` | text | The name, as the app shows it. | | `jobs[].client` | object | The client. | | `jobs[].client.id` | id (text) | The id of this record. Ids are opaque text: keep them exactly as given. | | `jobs[].client.name` | text | The name, as the app shows it. | | `jobs[].client.phone` | text | A phone number. Hidden when the key hides personal details. | | `jobs[].client.second_phone` | text | A second phone number. Hidden when the key hides personal details. | | `jobs[].address` | object | The address. | | `jobs[].address.line1` | text | The street address. Hidden when the key hides personal details. | | `jobs[].address.line2` | text | The apartment or suite line. Hidden when the key hides personal details. | | `jobs[].address.city` | text | The city. | | `jobs[].address.state` | text | The state or region. | | `jobs[].address.postal_code` | text | The postal code. | | `jobs[].address.one_line` | text | The whole address on one line. Hidden when the key hides personal details. | | `jobs[].job_type` | object | The job type. | | `jobs[].job_type.id` | id (text) | The id of this record. Ids are opaque text: keep them exactly as given. | | `jobs[].job_type.name` | text | The name, as the app shows it. | | `jobs[].status` | object | The job status. | | `jobs[].status.id` | id (text) | The id of this record. Ids are opaque text: keep them exactly as given. | | `jobs[].status.name` | text | The name, as the app shows it. | | `jobs[].status.slug` | text | The same name as a lowercase code word. Match on this, not on the name. | | `jobs[].status.since` | time (ISO 8601, with offset) | From when this has been true. Carries its offset from UTC; `Z` is UTC. | | `jobs[].technicians` | list of objects | The technicians. | | `jobs[].technicians[].id` | id (text) | The id of this record. Ids are opaque text: keep them exactly as given. | | `jobs[].technicians[].name` | text | The name, as the app shows it. | | `jobs[].scheduled_start` | time (ISO 8601, with offset) | When the visit is planned to start. Carries its offset from UTC; `Z` is UTC. | | `jobs[].scheduled_end` | time (ISO 8601, with offset) | When the visit is planned to end. Carries its offset from UTC; `Z` is UTC. | | `jobs[].collected` | money (number) | The money received on the job so far. In the company's currency. | | `jobs[].profit` | money (number) | The job's profit, worked out the way the app works it out. In the company's currency. | | `jobs[].currency` | text | The three-letter currency code (ISO 4217). Every money value in the answer is in it. | | `jobs[].source` | object | The source. | | `jobs[].source.label` | text | The name the app shows for it. | | `jobs[].source.filled_by` | text | How the job source was filled in: `call`, `form` or by hand. | | `jobs[].source.click_id` | id (text) | The Google click id (gclid) the call or visit carried. | | `jobs[].source.call_id` | id (text) | The id of the call. | | `jobs[].source.call_at` | time (ISO 8601, with offset) | When the call happened. Carries its offset from UTC; `Z` is UTC. | | `jobs[].source.campaign` | text | The ad campaign's name. | | `jobs[].is_lead` | true or false | True while the job is still a lead. | | `jobs[].notes` | text | Free-text notes. | | `jobs[].created_at` | time (ISO 8601, with offset) | When it was created. Carries its offset from UTC; `Z` is UTC. | | `jobs[].closed_at` | time or null | When it was closed. | | `jobs[].canceled_at` | time or null | When it was canceled. | | `jobs[].archived_at` | time or null | When it was archived. | | `jobs[].trashed_at` | time or null | When it was trashed. | | `technicians` | list of objects | The technicians. | | `technicians[].id` | id (text) | The id of this record. Ids are opaque text: keep them exactly as given. | | `technicians[].name` | text | The name, as the app shows it. | | `technicians[].role` | text | The role: what this person does on a job. | | `timed_out` | true or false | The timed out. | ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`not_found`](https://headhoncho.app/docs/api/errors#not_found) | 404 | No such record in the companies this credential reaches. | | [`out_of_scope`](https://headhoncho.app/docs/api/errors#out_of_scope) | 404 | No such company in the companies this credential reaches. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [List jobs](https://headhoncho.app/docs/api/list_jobs): Jobs and leads in the companies this credential reaches, newest first, with status, technician, schedule, money and the ad click each came from. - [Get job](https://headhoncho.app/docs/api/get_job): One job or lead: who, where, when, which status, which technicians, the money on it and the ad click it came from. - [Get job history](https://headhoncho.app/docs/api/get_job_history): Everything that happened to a job, in order, with who did it: created, moved, assigned, noted, paid. The same log the job page shows. - [Get job log](https://headhoncho.app/docs/api/get_job_log): A job's timeline in plain words, one line per thing that happened: notes, moves, texts, money, the rules and the AI, each with who did it. - [List situations](https://headhoncho.app/docs/api/list_situations): The situations the AI dispatcher is working on jobs now: what came up, the plan, and which step it is on. - [List job photos](https://headhoncho.app/docs/api/list_job_photos): The photos stored on a job, oldest first, each with a link that opens it for one minute. - [Get photo](https://headhoncho.app/docs/api/get_photo): One stored photo and a fresh link to its file. The link works for one minute. - [Get calendar](https://headhoncho.app/docs/api/get_calendar): Every job with a booked time between two days, earliest first. Canceled and closed jobs are left out, as on the app's calendar. - [List unscheduled jobs](https://headhoncho.app/docs/api/list_unscheduled_jobs): Open jobs and leads that have no booked time yet, the ones that waited longest first. - [Export jobs](https://headhoncho.app/docs/api/export_jobs): Jobs as a CSV file, newest first, up to 10,000 rows: ticket, technicians, status, dates, address, customer and price. - [Get automatic status](https://headhoncho.app/docs/api/get_automatic_status): Whether a person set this job's status by hand, why its facts do not hold it, and where Back to automatic would put it. - [Get job detour](https://headhoncho.app/docs/api/get_job_detour): Whether a job is on a detour, such as Waiting on parts, and where Resolve would put it. - [List job reassignments](https://headhoncho.app/docs/api/list_job_reassignments): The times this job was handed from one technician to another, oldest first, and how far each one got. - [List calendar reassignments](https://headhoncho.app/docs/api/list_calendar_reassignments): Every reassignment on a job booked in a window: open ones, and ones that closed today. - The same records in the app: [the Jobs panel](https://headhoncho.app/docs/jobs). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "query": "azoulay", "jobs": [ { "id": "job_1138", "number": 1138, "company": { "id": "cmp_14f5", "name": "Sunrise Moving" }, "client": { "id": "cli_77a0", "name": "R. Azoulay", "phone": "+12175550142", "second_phone": "" }, "address": { "line1": "2590 Main St", "line2": "", "city": "Bloomington", "state": "IL", "postal_code": "61701", "one_line": "2590 Main St, Bloomington, IL 61701" }, "job_type": { "id": "jt_02", "name": "Local move" }, "status": { "id": "st_02", "name": "Scheduled", "slug": "scheduled", "since": "2026-10-12T15:04:10Z" }, "technicians": [ { "id": "wrk_3b90", "name": "Dana R." } ], "scheduled_start": "2026-10-16T09:00:00-05:00", "scheduled_end": "2026-10-16T11:00:00-05:00", "collected": 0.0, "profit": 0.0, "currency": "USD", "source": { "label": "Google Ads", "filled_by": "call", "click_id": "Cj0KCQjw...", "call_id": "CAL8f2e1", "call_at": "2026-10-11T18:22:03Z", "campaign": "Moving - Bloomington" }, "is_lead": false, "notes": "Two flights of stairs", "created_at": "2026-10-11T18:25:40Z", "closed_at": null, "canceled_at": null, "archived_at": null, "trashed_at": null } ], "technicians": [ { "id": "wrk_3b90", "name": "Dana R.", "role": "technician" } ], "timed_out": false } ``` ### cURL ```bash curl "https://api.headhoncho.app/api/v1/search?q=azoulay+oak&company_id=cmp_14f5" \ -H "Authorization: Bearer hh_live_..." ``` ### Python ```python import requests response = requests.get( "https://api.headhoncho.app/api/v1/search", headers={"Authorization": "Bearer hh_live_..."}, params={ "q": "azoulay oak", "company_id": "cmp_14f5", }, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/search?q=azoulay+oak&company_id=cmp_14f5", { headers: { Authorization: "Bearer hh_live_..." }, }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: search_jobs Arguments: q (text, required), company_id (id, optional) Access: read on Jobs Hints: readOnly=true, destructive=false, idempotent=true, openWorld=false Try asking: "Using HeadHoncho, search jobs with q azoulay oak and company_id cmp_14f5." ``` --- # Get automatic status Get automatic status is a read in the HeadHoncho API. Whether a person set this job's status by hand, why its facts do not hold it, and where Back to automatic would put it. Page: https://headhoncho.app/docs/api/get_automatic_status | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **Get automatic status**, HeadHoncho API v1. It is a read, sent to the base address `https://api.headhoncho.app`. `GET /api/v1/jobs/{job_id}/automatic-status` The key needs the **Jobs** area at **read**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). Send your key as `Authorization: Bearer hh_live_...`. See [API keys](https://headhoncho.app/docs/api/keys). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `job_id` | id, in the path | Yes | The job id, or its number. | `job_1138` | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back job, set_by_hand (true when a person moved the status), set_by_hand_at, kept (true when the status was kept on purpose), why (a sentence on what the job's facts say) and release_to (id and name of the status Back to automatic would move it to, or null when there is nothing to hand back). It is a rehearsal: nothing is changed or sent. It never changes a record. It only reads the companies the key reaches. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `job` | object | The job. | | `job.id` | id (text) | The id of this record. Ids are opaque text: keep them exactly as given. | | `job.number` | whole number | The number people say out loud, such as the job number. | | `set_by_hand` | true or false | The set by hand. | | `set_by_hand_at` | time (ISO 8601, with offset) | When the set by hand happened. Carries its offset from UTC; `Z` is UTC. | | `kept` | true or false | The kept. | | `why` | text | The why. | | `release_to` | object | The release to. | | `release_to.id` | id (text) | The id of this record. Ids are opaque text: keep them exactly as given. | | `release_to.name` | text | The name, as the app shows it. | ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`not_found`](https://headhoncho.app/docs/api/errors#not_found) | 404 | No such record in the companies this credential reaches. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [List jobs](https://headhoncho.app/docs/api/list_jobs): Jobs and leads in the companies this credential reaches, newest first, with status, technician, schedule, money and the ad click each came from. - [Get job](https://headhoncho.app/docs/api/get_job): One job or lead: who, where, when, which status, which technicians, the money on it and the ad click it came from. - [Get job history](https://headhoncho.app/docs/api/get_job_history): Everything that happened to a job, in order, with who did it: created, moved, assigned, noted, paid. The same log the job page shows. - [Get job log](https://headhoncho.app/docs/api/get_job_log): A job's timeline in plain words, one line per thing that happened: notes, moves, texts, money, the rules and the AI, each with who did it. - [List situations](https://headhoncho.app/docs/api/list_situations): The situations the AI dispatcher is working on jobs now: what came up, the plan, and which step it is on. - [List job photos](https://headhoncho.app/docs/api/list_job_photos): The photos stored on a job, oldest first, each with a link that opens it for one minute. - [Get photo](https://headhoncho.app/docs/api/get_photo): One stored photo and a fresh link to its file. The link works for one minute. - [Get calendar](https://headhoncho.app/docs/api/get_calendar): Every job with a booked time between two days, earliest first. Canceled and closed jobs are left out, as on the app's calendar. - [List unscheduled jobs](https://headhoncho.app/docs/api/list_unscheduled_jobs): Open jobs and leads that have no booked time yet, the ones that waited longest first. - [Export jobs](https://headhoncho.app/docs/api/export_jobs): Jobs as a CSV file, newest first, up to 10,000 rows: ticket, technicians, status, dates, address, customer and price. - [Search jobs](https://headhoncho.app/docs/api/search_jobs): Find jobs by ticket number, customer, address or technician name, and technicians by name. - [Get job detour](https://headhoncho.app/docs/api/get_job_detour): Whether a job is on a detour, such as Waiting on parts, and where Resolve would put it. - [List job reassignments](https://headhoncho.app/docs/api/list_job_reassignments): The times this job was handed from one technician to another, oldest first, and how far each one got. - [List calendar reassignments](https://headhoncho.app/docs/api/list_calendar_reassignments): Every reassignment on a job booked in a window: open ones, and ones that closed today. - The same records in the app: [the Jobs panel](https://headhoncho.app/docs/jobs). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "job": { "id": "job_1138", "number": 1138 }, "set_by_hand": true, "set_by_hand_at": "2026-10-16T09:12:00Z", "kept": false, "why": "The job has a technician and a booked time, so the automation would hold it at Scheduled.", "release_to": { "id": "st_02", "name": "Scheduled" } } ``` ### cURL ```bash curl "https://api.headhoncho.app/api/v1/jobs/job_1138/automatic-status" \ -H "Authorization: Bearer hh_live_..." ``` ### Python ```python import requests response = requests.get( "https://api.headhoncho.app/api/v1/jobs/job_1138/automatic-status", headers={"Authorization": "Bearer hh_live_..."}, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/jobs/job_1138/automatic-status", { headers: { Authorization: "Bearer hh_live_..." }, }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: get_automatic_status Arguments: job_id (id, required) Access: read on Jobs Hints: readOnly=true, destructive=false, idempotent=true, openWorld=false Try asking: "Using HeadHoncho, get automatic status with job_id job_1138." ``` --- # Get job detour Get job detour is a read in the HeadHoncho API. Whether a job is on a detour, such as Waiting on parts, and where Resolve would put it. Page: https://headhoncho.app/docs/api/get_job_detour | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **Get job detour**, HeadHoncho API v1. It is a read, sent to the base address `https://api.headhoncho.app`. `GET /api/v1/jobs/{job_id}/detour` The key needs the **Jobs** area at **read**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). Send your key as `Authorization: Bearer hh_live_...`. See [API keys](https://headhoncho.app/docs/api/keys). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `job_id` | id, in the path | Yes | The job id, or its number. | `job_1138` | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back job, on_detour (true or false), detour (id and name of the status it is on), returns_to (the status it left, or null), lands_on (where it would stand after Resolve, once the automation has moved it, or null), automatic (true when the automation would move it on) and refusal (a sentence when Resolve would be refused, otherwise empty). It is a rehearsal: nothing is changed or sent. It never changes a record. It only reads the companies the key reaches. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `job` | object | The job. | | `job.id` | id (text) | The id of this record. Ids are opaque text: keep them exactly as given. | | `job.number` | whole number | The number people say out loud, such as the job number. | | `on_detour` | true or false | The on detour. | | `detour` | object | Why the job is waiting, in words. | | `detour.id` | id (text) | The id of this record. Ids are opaque text: keep them exactly as given. | | `detour.name` | text | The name, as the app shows it. | | `returns_to` | object | The returns to. | | `returns_to.id` | id (text) | The id of this record. Ids are opaque text: keep them exactly as given. | | `returns_to.name` | text | The name, as the app shows it. | | `lands_on` | object | The date it was lands. | | `lands_on.id` | id (text) | The id of this record. Ids are opaque text: keep them exactly as given. | | `lands_on.name` | text | The name, as the app shows it. | | `automatic` | true or false | The automatic. | | `refusal` | text | The refusal. | ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`not_found`](https://headhoncho.app/docs/api/errors#not_found) | 404 | No such record in the companies this credential reaches. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [List jobs](https://headhoncho.app/docs/api/list_jobs): Jobs and leads in the companies this credential reaches, newest first, with status, technician, schedule, money and the ad click each came from. - [Get job](https://headhoncho.app/docs/api/get_job): One job or lead: who, where, when, which status, which technicians, the money on it and the ad click it came from. - [Get job history](https://headhoncho.app/docs/api/get_job_history): Everything that happened to a job, in order, with who did it: created, moved, assigned, noted, paid. The same log the job page shows. - [Get job log](https://headhoncho.app/docs/api/get_job_log): A job's timeline in plain words, one line per thing that happened: notes, moves, texts, money, the rules and the AI, each with who did it. - [List situations](https://headhoncho.app/docs/api/list_situations): The situations the AI dispatcher is working on jobs now: what came up, the plan, and which step it is on. - [List job photos](https://headhoncho.app/docs/api/list_job_photos): The photos stored on a job, oldest first, each with a link that opens it for one minute. - [Get photo](https://headhoncho.app/docs/api/get_photo): One stored photo and a fresh link to its file. The link works for one minute. - [Get calendar](https://headhoncho.app/docs/api/get_calendar): Every job with a booked time between two days, earliest first. Canceled and closed jobs are left out, as on the app's calendar. - [List unscheduled jobs](https://headhoncho.app/docs/api/list_unscheduled_jobs): Open jobs and leads that have no booked time yet, the ones that waited longest first. - [Export jobs](https://headhoncho.app/docs/api/export_jobs): Jobs as a CSV file, newest first, up to 10,000 rows: ticket, technicians, status, dates, address, customer and price. - [Search jobs](https://headhoncho.app/docs/api/search_jobs): Find jobs by ticket number, customer, address or technician name, and technicians by name. - [Get automatic status](https://headhoncho.app/docs/api/get_automatic_status): Whether a person set this job's status by hand, why its facts do not hold it, and where Back to automatic would put it. - [List job reassignments](https://headhoncho.app/docs/api/list_job_reassignments): The times this job was handed from one technician to another, oldest first, and how far each one got. - [List calendar reassignments](https://headhoncho.app/docs/api/list_calendar_reassignments): Every reassignment on a job booked in a window: open ones, and ones that closed today. - The same records in the app: [the Jobs panel](https://headhoncho.app/docs/jobs). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "job": { "id": "job_1138", "number": 1138 }, "on_detour": true, "detour": { "id": "st_08", "name": "Waiting on parts" }, "returns_to": { "id": "st_02", "name": "Scheduled" }, "lands_on": { "id": "st_02", "name": "Scheduled" }, "automatic": true, "refusal": "" } ``` ### cURL ```bash curl "https://api.headhoncho.app/api/v1/jobs/job_1138/detour" \ -H "Authorization: Bearer hh_live_..." ``` ### Python ```python import requests response = requests.get( "https://api.headhoncho.app/api/v1/jobs/job_1138/detour", headers={"Authorization": "Bearer hh_live_..."}, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/jobs/job_1138/detour", { headers: { Authorization: "Bearer hh_live_..." }, }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: get_job_detour Arguments: job_id (id, required) Access: read on Jobs Hints: readOnly=true, destructive=false, idempotent=true, openWorld=false Try asking: "Using HeadHoncho, get job detour with job_id job_1138." ``` --- # List job reassignments List job reassignments is a read in the HeadHoncho API. The times this job was handed from one technician to another, oldest first, and how far each one got. Page: https://headhoncho.app/docs/api/list_job_reassignments | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **List job reassignments**, HeadHoncho API v1. It is a read, sent to the base address `https://api.headhoncho.app`. `GET /api/v1/jobs/{job_id}/reassignment` The key needs the **Jobs** area at **read**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). Send your key as `Authorization: Bearer hh_live_...`. See [API keys](https://headhoncho.app/docs/api/keys). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `job_id` | id, in the path | Yes | The job id, or its number. | `job_1138` | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back job and items. Each item is one reassignment: id, from and to (worker id and name), reason, note, state, step (in words: Letting go, Taking it, Confirmed, Objected, Released, not placed or Cancelled), open (true until it ends), who started it and when, and when each step was asked and answered. An empty list means the job was never reassigned. Starting a reassignment is done in the app only. It never changes a record. It only reads the companies the key reaches. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `job` | object | The job. | | `job.id` | id (text) | The id of this record. Ids are opaque text: keep them exactly as given. | | `job.number` | whole number | The number people say out loud, such as the job number. | | `items` | list of objects | The rows on this page. | | `items[].id` | id (text) | The id of this record. Ids are opaque text: keep them exactly as given. | | `items[].from_worker_id` | id (text) | The id of the from worker. | | `items[].from_worker_name` | text | The from worker name. | | `items[].to_worker_id` | id (text) | The id of the to worker. | | `items[].to_worker_name` | text | The to worker name. | | `items[].reason` | text | The reason given. | | `items[].note` | text | The note. | | `items[].state` | text | The state or region. | | `items[].step` | text | The step. | | `items[].open` | true or false | The open. | | `items[].started_by_name` | text | The started by name. | | `items[].started_at` | time (ISO 8601, with offset) | When it was started. Carries its offset from UTC; `Z` is UTC. | | `items[].release_asked_at` | time (ISO 8601, with offset) | When it was release asked. Carries its offset from UTC; `Z` is UTC. | | `items[].release_word` | text | The release word. | | `items[].release_confirmed_at` | time (ISO 8601, with offset) | When it was release confirmed. Carries its offset from UTC; `Z` is UTC. | | `items[].take_asked_at` | time (ISO 8601, with offset) | When it was take asked. Carries its offset from UTC; `Z` is UTC. | | `items[].take_word` | text | The take word. | | `items[].take_confirmed_at` | time or null | When it was take confirmed. | | `items[].dismissed_at` | time or null | When it was dismissed. | | `items[].closed_at` | time or null | When it was closed. | | `items[].close_reason` | text | The close reason. | | `items[].detail` | text | The detail. | ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`not_found`](https://headhoncho.app/docs/api/errors#not_found) | 404 | No such record in the companies this credential reaches. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [List jobs](https://headhoncho.app/docs/api/list_jobs): Jobs and leads in the companies this credential reaches, newest first, with status, technician, schedule, money and the ad click each came from. - [Get job](https://headhoncho.app/docs/api/get_job): One job or lead: who, where, when, which status, which technicians, the money on it and the ad click it came from. - [Get job history](https://headhoncho.app/docs/api/get_job_history): Everything that happened to a job, in order, with who did it: created, moved, assigned, noted, paid. The same log the job page shows. - [Get job log](https://headhoncho.app/docs/api/get_job_log): A job's timeline in plain words, one line per thing that happened: notes, moves, texts, money, the rules and the AI, each with who did it. - [List situations](https://headhoncho.app/docs/api/list_situations): The situations the AI dispatcher is working on jobs now: what came up, the plan, and which step it is on. - [List job photos](https://headhoncho.app/docs/api/list_job_photos): The photos stored on a job, oldest first, each with a link that opens it for one minute. - [Get photo](https://headhoncho.app/docs/api/get_photo): One stored photo and a fresh link to its file. The link works for one minute. - [Get calendar](https://headhoncho.app/docs/api/get_calendar): Every job with a booked time between two days, earliest first. Canceled and closed jobs are left out, as on the app's calendar. - [List unscheduled jobs](https://headhoncho.app/docs/api/list_unscheduled_jobs): Open jobs and leads that have no booked time yet, the ones that waited longest first. - [Export jobs](https://headhoncho.app/docs/api/export_jobs): Jobs as a CSV file, newest first, up to 10,000 rows: ticket, technicians, status, dates, address, customer and price. - [Search jobs](https://headhoncho.app/docs/api/search_jobs): Find jobs by ticket number, customer, address or technician name, and technicians by name. - [Get automatic status](https://headhoncho.app/docs/api/get_automatic_status): Whether a person set this job's status by hand, why its facts do not hold it, and where Back to automatic would put it. - [Get job detour](https://headhoncho.app/docs/api/get_job_detour): Whether a job is on a detour, such as Waiting on parts, and where Resolve would put it. - [List calendar reassignments](https://headhoncho.app/docs/api/list_calendar_reassignments): Every reassignment on a job booked in a window: open ones, and ones that closed today. - The same records in the app: [the Jobs panel](https://headhoncho.app/docs/jobs). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "job": { "id": "job_1138", "number": 1138 }, "items": [ { "id": "rea_41b0", "from_worker_id": "wrk_3b90", "from_worker_name": "Dana R.", "to_worker_id": "wrk_7a12", "to_worker_name": "Omar S.", "reason": "Truck in the shop", "note": "", "state": "taking", "step": "Taking it", "open": true, "started_by_name": "Ariel T.", "started_at": "2026-10-16T08:50:00-05:00", "release_asked_at": "2026-10-16T08:50:02-05:00", "release_word": "OK", "release_confirmed_at": "2026-10-16T08:53:40-05:00", "take_asked_at": "2026-10-16T08:53:41-05:00", "take_word": "", "take_confirmed_at": null, "dismissed_at": null, "closed_at": null, "close_reason": "", "detail": "" } ] } ``` ### cURL ```bash curl "https://api.headhoncho.app/api/v1/jobs/job_1138/reassignment" \ -H "Authorization: Bearer hh_live_..." ``` ### Python ```python import requests response = requests.get( "https://api.headhoncho.app/api/v1/jobs/job_1138/reassignment", headers={"Authorization": "Bearer hh_live_..."}, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/jobs/job_1138/reassignment", { headers: { Authorization: "Bearer hh_live_..." }, }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: list_job_reassignments Arguments: job_id (id, required) Access: read on Jobs Hints: readOnly=true, destructive=false, idempotent=true, openWorld=false Try asking: "Using HeadHoncho, list job reassignments with job_id job_1138." ``` --- # List calendar reassignments List calendar reassignments is a read in the HeadHoncho API. Every reassignment on a job booked in a window: open ones, and ones that closed today. Page: https://headhoncho.app/docs/api/list_calendar_reassignments | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **List calendar reassignments**, HeadHoncho API v1. It is a read, sent to the base address `https://api.headhoncho.app`. `GET /api/v1/calendar/reassignments` The key needs the **Jobs** area at **read**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). Send your key as `Authorization: Bearer hh_live_...`. See [API keys](https://headhoncho.app/docs/api/keys). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `company_id` | id, in the query | No | One company. Default: every company the credential reaches. | `cmp_14f5` | | `from` | date, in the query | No | The first day. Default: the first of this month. | `2026-10-01` | | `to` | date, in the query | No | The last day, inclusive. Default: the end of that month. | `2026-10-31` | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back from, to and items, earliest first. Each item: pair (a number, counted in this answer), job_id, job_number, from and to (worker id and name), reason, state, step, open, started_at and closed_at. A reassignment that ended on an earlier day is not listed; read it on the job. It never changes a record. It only reads the companies the key reaches. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `from` | date (YYYY-MM-DD) | The first day of the range, inclusive. | | `to` | date (YYYY-MM-DD) | The last day of the range, inclusive. | | `items` | list of objects | The rows on this page. | | `items[].pair` | whole number | The pair. | | `items[].job_id` | id (text) | The id of the job. | | `items[].job_number` | whole number | The job number people say out loud. | | `items[].from_worker_id` | id (text) | The id of the from worker. | | `items[].from_worker_name` | text | The from worker name. | | `items[].to_worker_id` | id (text) | The id of the to worker. | | `items[].to_worker_name` | text | The to worker name. | | `items[].reason` | text | The reason given. | | `items[].state` | text | The state or region. | | `items[].step` | text | The step. | | `items[].open` | true or false | The open. | | `items[].started_at` | time (ISO 8601, with offset) | When it was started. Carries its offset from UTC; `Z` is UTC. | | `items[].closed_at` | time or null | When it was closed. | ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`not_found`](https://headhoncho.app/docs/api/errors#not_found) | 404 | No such record in the companies this credential reaches. | | [`out_of_scope`](https://headhoncho.app/docs/api/errors#out_of_scope) | 404 | No such company in the companies this credential reaches. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [List jobs](https://headhoncho.app/docs/api/list_jobs): Jobs and leads in the companies this credential reaches, newest first, with status, technician, schedule, money and the ad click each came from. - [Get job](https://headhoncho.app/docs/api/get_job): One job or lead: who, where, when, which status, which technicians, the money on it and the ad click it came from. - [Get job history](https://headhoncho.app/docs/api/get_job_history): Everything that happened to a job, in order, with who did it: created, moved, assigned, noted, paid. The same log the job page shows. - [Get job log](https://headhoncho.app/docs/api/get_job_log): A job's timeline in plain words, one line per thing that happened: notes, moves, texts, money, the rules and the AI, each with who did it. - [List situations](https://headhoncho.app/docs/api/list_situations): The situations the AI dispatcher is working on jobs now: what came up, the plan, and which step it is on. - [List job photos](https://headhoncho.app/docs/api/list_job_photos): The photos stored on a job, oldest first, each with a link that opens it for one minute. - [Get photo](https://headhoncho.app/docs/api/get_photo): One stored photo and a fresh link to its file. The link works for one minute. - [Get calendar](https://headhoncho.app/docs/api/get_calendar): Every job with a booked time between two days, earliest first. Canceled and closed jobs are left out, as on the app's calendar. - [List unscheduled jobs](https://headhoncho.app/docs/api/list_unscheduled_jobs): Open jobs and leads that have no booked time yet, the ones that waited longest first. - [Export jobs](https://headhoncho.app/docs/api/export_jobs): Jobs as a CSV file, newest first, up to 10,000 rows: ticket, technicians, status, dates, address, customer and price. - [Search jobs](https://headhoncho.app/docs/api/search_jobs): Find jobs by ticket number, customer, address or technician name, and technicians by name. - [Get automatic status](https://headhoncho.app/docs/api/get_automatic_status): Whether a person set this job's status by hand, why its facts do not hold it, and where Back to automatic would put it. - [Get job detour](https://headhoncho.app/docs/api/get_job_detour): Whether a job is on a detour, such as Waiting on parts, and where Resolve would put it. - [List job reassignments](https://headhoncho.app/docs/api/list_job_reassignments): The times this job was handed from one technician to another, oldest first, and how far each one got. - The same records in the app: [the Jobs panel](https://headhoncho.app/docs/jobs). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "from": "2026-10-01", "to": "2026-10-31", "items": [ { "pair": 1, "job_id": "job_1138", "job_number": 1138, "from_worker_id": "wrk_3b90", "from_worker_name": "Dana R.", "to_worker_id": "wrk_7a12", "to_worker_name": "Omar S.", "reason": "Truck in the shop", "state": "taking", "step": "Taking it", "open": true, "started_at": "2026-10-16T08:50:00-05:00", "closed_at": null } ] } ``` ### cURL ```bash curl "https://api.headhoncho.app/api/v1/calendar/reassignments?company_id=cmp_14f5&from=2026-10-01" \ -H "Authorization: Bearer hh_live_..." ``` ### Python ```python import requests response = requests.get( "https://api.headhoncho.app/api/v1/calendar/reassignments", headers={"Authorization": "Bearer hh_live_..."}, params={ "company_id": "cmp_14f5", "from": "2026-10-01", }, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/calendar/reassignments?company_id=cmp_14f5&from=2026-10-01", { headers: { Authorization: "Bearer hh_live_..." }, }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: list_calendar_reassignments Arguments: company_id (id, optional), from (date, optional), to (date, optional) Access: read on Jobs Hints: readOnly=true, destructive=false, idempotent=true, openWorld=false Try asking: "Using HeadHoncho, list calendar reassignments with company_id cmp_14f5." ``` --- # Upload photo Upload photo is a command in the HeadHoncho API. Put one photo on a job. Send the picture as base64 text; it is stored and confirmed in one call. Page: https://headhoncho.app/docs/api/upload_photo | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **Upload photo**, HeadHoncho API v1. It is a command, sent to the base address `https://api.headhoncho.app`. `POST /api/v1/commands/request-job-photo` The key needs the **Jobs** area at **do**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). It runs the app's own command `request-job-photo`. Send an `Idempotency-Key` header with every call: the same key with the same body returns the first answer and runs nothing twice. See [the model](https://headhoncho.app/docs/api/model#idempotency). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `job_id` | id, in the JSON body | Yes | The job id, or its number. | `job_1138` | | `content_type` | text, in the JSON body | Yes | image/jpeg, image/png, image/webp or image/heic. One of `image/jpeg`, `image/png`, `image/webp`, `image/heic`. | `image/jpeg` | | `content_base64` | text, in the JSON body | Yes | The picture, base64 encoded, up to 15 MB once decoded. | `/9j/4AAQSkZJRgABAQ...` | | `note_id` | id, in the JSON body | No | A note on the same job to file the photo under. | `note_5c21` | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back accepted, job_id, number, photo_id, state (stored) and position. A job holds at most 50 photos. The type is checked again against the stored file, and a file that is not the image it says it is removed and refused. It never deletes anything. It changes only what the command names, and it writes the change to the job's history with who asked for it. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `accepted` | true or false | True when the command ran. A command that cannot run is an error instead. | | `job_id` | id (text) | The id of the job. | | `number` | whole number | The number people say out loud, such as the job number. | | `position` | whole number | Where the change landed in the event log. Pass it as `after` on a read to see your own write. | | `photo_id` | id (text) | The id of the photo. | | `state` | text | The state or region. | ## How the app does it The app asks for permission, sends the file to storage and then confirms. This call does the three steps for you, as the same person, so History shows one photo added and one confirmed. ## Size A base64 body is a third larger than the picture. Keep the picture a few megabytes; if a call is refused for size, shrink the picture first. ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`read_only`](https://headhoncho.app/docs/api/errors#read_only) | 403 | This credential may read this area but not change it. | | [`not_found`](https://headhoncho.app/docs/api/errors#not_found) | 404 | No such record in the companies this credential reaches. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`missing_idempotency_key`](https://headhoncho.app/docs/api/errors#missing_idempotency_key) | 400 | Send an Idempotency-Key header on every command. | | [`idempotency_mismatch`](https://headhoncho.app/docs/api/errors#idempotency_mismatch) | 409 | This Idempotency-Key was used with a different body. | | [`idempotency_in_progress`](https://headhoncho.app/docs/api/errors#idempotency_in_progress) | 409 | A command with this Idempotency-Key is still running. Wait a moment and send it again. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [Create job](https://headhoncho.app/docs/api/create_job): Open a job or a lead in one company: the customer, the address, and optionally the job type, the time window and the technician. - [Update job](https://headhoncho.app/docs/api/update_job): Change a job's facts: the customer, the address, the schedule, the job type or the notes. Only the fields you send change. - [Change job status](https://headhoncho.app/docs/api/change_job_status): Move a job to another status by its name, slug or id. The move lands in the job's history with who asked for it. - [Assign worker](https://headhoncho.app/docs/api/assign_worker): Put a technician or subcontractor on a job. If Job follow-up is on, the automation acts on it at once, as it would from the app. - [Unassign worker](https://headhoncho.app/docs/api/unassign_worker): Take a technician or subcontractor off a job. The ticket's cancellation reaches them the way it does from the app. - [Add job note](https://headhoncho.app/docs/api/add_job_note): Add a note to a job. It appends to the job's log and never overwrites. - [Update job note](https://headhoncho.app/docs/api/update_job_note): Fix what a note says. Only the person who wrote it may change it; the old text stays in the job's history. - [Delete job note](https://headhoncho.app/docs/api/delete_job_note): Take a note off a job. Its author or an owner may. The removal is in the job's history. - [Set job cut](https://headhoncho.app/docs/api/set_job_cut): What one technician or subcontractor on a job is paid on this job: a percent of the total, a percent of the profit, or a flat amount. - [Release job status](https://headhoncho.app/docs/api/release_job_status): Hand a status set by hand back to the automation. The job moves at once to the status its facts hold, and History says why. - [Resolve job detour](https://headhoncho.app/docs/api/resolve_job_detour): Close a job's detour, such as Waiting on parts. The job goes back to the status it left, then on to where its facts put it. - [Archive job](https://headhoncho.app/docs/api/archive_job): File a finished job away, off the boards. It keeps its money and counts in every figure; Unarchive brings it back. - [Unarchive job](https://headhoncho.app/docs/api/unarchive_job): Bring an archived job back onto the boards, as it was. - [Trash job](https://headhoncho.app/docs/api/trash_job): Move a job to Trash, with why. It leaves every list and every figure, and can be restored for 30 days. - [Restore job](https://headhoncho.app/docs/api/restore_job): Bring a job back from Trash, whole: its money, its history and its technicians. - [Delete photo](https://headhoncho.app/docs/api/delete_photo): Remove one photo from a job, for good: its record and its file. - The same records in the app: [the Jobs panel](https://headhoncho.app/docs/jobs). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "accepted": true, "job_id": "job_1203", "number": 1203, "position": 88411, "photo_id": "pho_5d21", "state": "stored" } ``` ### cURL ```bash curl -X POST "https://api.headhoncho.app/api/v1/commands/request-job-photo" \ -H "Authorization: Bearer hh_live_..." \ -H "Idempotency-Key: 6f1d2c9e-1b7a-4c1e-9a52-0d3f8e4b7a10" \ -H "Content-Type: application/json" \ -d '{ "job_id": "job_1138", "content_type": "image/jpeg", "content_base64": "/9j/4AAQSkZJRgABAQ...", "note_id": "note_5c21" }' ``` ### Python ```python import requests import uuid response = requests.post( "https://api.headhoncho.app/api/v1/commands/request-job-photo", headers={ "Authorization": "Bearer hh_live_...", "Idempotency-Key": str(uuid.uuid4()), }, json={ "job_id": "job_1138", "content_type": "image/jpeg", "content_base64": "/9j/4AAQSkZJRgABAQ...", "note_id": "note_5c21", }, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/commands/request-job-photo", { method: "POST", headers: { Authorization: "Bearer hh_live_...", "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "job_id": "job_1138", "content_type": "image/jpeg", "content_base64": "/9j/4AAQSkZJRgABAQ...", "note_id": "note_5c21" }), }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: upload_photo Arguments: job_id (id, required), content_type (text, required), content_base64 (text, required), note_id (id, optional) Access: do on Jobs Hints: readOnly=false, destructive=false, idempotent=false, openWorld=false Try asking: "Using HeadHoncho, upload photo with job_id job_1138 and content_type image/jpeg and content_base64 /9j/4AAQSkZJRgABAQ... and note_id note_5c21." ``` --- # Delete photo Delete photo is a command in the HeadHoncho API. Remove one photo from a job, for good: its record and its file. Page: https://headhoncho.app/docs/api/delete_photo | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **Delete photo**, HeadHoncho API v1. It is a command, sent to the base address `https://api.headhoncho.app`. `POST /api/v1/commands/delete-job-photo` The key needs the **Jobs** area at **do**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). It runs the app's own command `delete-job-photo`. Send an `Idempotency-Key` header with every call: the same key with the same body returns the first answer and runs nothing twice. See [the model](https://headhoncho.app/docs/api/model#idempotency). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `photo_id` | id, in the JSON body | Yes | The photo id, from A job's photos. | `pho_5d21` | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back accepted, job_id, number, photo_id, deleted (true) and position. The file is removed right after the record; there is no Trash for photos. It never deletes anything. It changes only what the command names, and it writes the change to the job's history with who asked for it. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `accepted` | true or false | True when the command ran. A command that cannot run is an error instead. | | `job_id` | id (text) | The id of the job. | | `number` | whole number | The number people say out loud, such as the job number. | | `position` | whole number | Where the change landed in the event log. Pass it as `after` on a read to see your own write. | | `photo_id` | id (text) | The id of the photo. | | `deleted` | true or false | The deleted. | ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`read_only`](https://headhoncho.app/docs/api/errors#read_only) | 403 | This credential may read this area but not change it. | | [`not_found`](https://headhoncho.app/docs/api/errors#not_found) | 404 | No such record in the companies this credential reaches. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`missing_idempotency_key`](https://headhoncho.app/docs/api/errors#missing_idempotency_key) | 400 | Send an Idempotency-Key header on every command. | | [`idempotency_mismatch`](https://headhoncho.app/docs/api/errors#idempotency_mismatch) | 409 | This Idempotency-Key was used with a different body. | | [`idempotency_in_progress`](https://headhoncho.app/docs/api/errors#idempotency_in_progress) | 409 | A command with this Idempotency-Key is still running. Wait a moment and send it again. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [Create job](https://headhoncho.app/docs/api/create_job): Open a job or a lead in one company: the customer, the address, and optionally the job type, the time window and the technician. - [Update job](https://headhoncho.app/docs/api/update_job): Change a job's facts: the customer, the address, the schedule, the job type or the notes. Only the fields you send change. - [Change job status](https://headhoncho.app/docs/api/change_job_status): Move a job to another status by its name, slug or id. The move lands in the job's history with who asked for it. - [Assign worker](https://headhoncho.app/docs/api/assign_worker): Put a technician or subcontractor on a job. If Job follow-up is on, the automation acts on it at once, as it would from the app. - [Unassign worker](https://headhoncho.app/docs/api/unassign_worker): Take a technician or subcontractor off a job. The ticket's cancellation reaches them the way it does from the app. - [Add job note](https://headhoncho.app/docs/api/add_job_note): Add a note to a job. It appends to the job's log and never overwrites. - [Update job note](https://headhoncho.app/docs/api/update_job_note): Fix what a note says. Only the person who wrote it may change it; the old text stays in the job's history. - [Delete job note](https://headhoncho.app/docs/api/delete_job_note): Take a note off a job. Its author or an owner may. The removal is in the job's history. - [Set job cut](https://headhoncho.app/docs/api/set_job_cut): What one technician or subcontractor on a job is paid on this job: a percent of the total, a percent of the profit, or a flat amount. - [Release job status](https://headhoncho.app/docs/api/release_job_status): Hand a status set by hand back to the automation. The job moves at once to the status its facts hold, and History says why. - [Resolve job detour](https://headhoncho.app/docs/api/resolve_job_detour): Close a job's detour, such as Waiting on parts. The job goes back to the status it left, then on to where its facts put it. - [Archive job](https://headhoncho.app/docs/api/archive_job): File a finished job away, off the boards. It keeps its money and counts in every figure; Unarchive brings it back. - [Unarchive job](https://headhoncho.app/docs/api/unarchive_job): Bring an archived job back onto the boards, as it was. - [Trash job](https://headhoncho.app/docs/api/trash_job): Move a job to Trash, with why. It leaves every list and every figure, and can be restored for 30 days. - [Restore job](https://headhoncho.app/docs/api/restore_job): Bring a job back from Trash, whole: its money, its history and its technicians. - [Upload photo](https://headhoncho.app/docs/api/upload_photo): Put one photo on a job. Send the picture as base64 text; it is stored and confirmed in one call. - The same records in the app: [the Jobs panel](https://headhoncho.app/docs/jobs). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "accepted": true, "job_id": "job_1203", "number": 1203, "position": 88411, "photo_id": "pho_5d21", "deleted": true } ``` ### cURL ```bash curl -X POST "https://api.headhoncho.app/api/v1/commands/delete-job-photo" \ -H "Authorization: Bearer hh_live_..." \ -H "Idempotency-Key: 6f1d2c9e-1b7a-4c1e-9a52-0d3f8e4b7a10" \ -H "Content-Type: application/json" \ -d '{ "photo_id": "pho_5d21" }' ``` ### Python ```python import requests import uuid response = requests.post( "https://api.headhoncho.app/api/v1/commands/delete-job-photo", headers={ "Authorization": "Bearer hh_live_...", "Idempotency-Key": str(uuid.uuid4()), }, json={ "photo_id": "pho_5d21", }, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/commands/delete-job-photo", { method: "POST", headers: { Authorization: "Bearer hh_live_...", "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "photo_id": "pho_5d21" }), }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: delete_photo Arguments: photo_id (id, required) Access: do on Jobs Hints: readOnly=false, destructive=true, idempotent=true, openWorld=false Try asking: "Using HeadHoncho, delete photo with photo_id pho_5d21." ``` --- # Bulk change status Bulk change status is a command in the HeadHoncho API. Move up to 200 jobs to one status. Each move lands in that job's history. Page: https://headhoncho.app/docs/api/bulk_change_status | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **Bulk change status**, HeadHoncho API v1. It is a command, sent to the base address `https://api.headhoncho.app`. `POST /api/v1/commands/bulk-change-job-status` The key needs the **Jobs** area at **do**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). It runs the app's own command `bulk-change-job-status`. Send an `Idempotency-Key` header with every call: the same key with the same body returns the first answer and runs nothing twice. See [the model](https://headhoncho.app/docs/api/model#idempotency). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `job_ids` | text, in the JSON body | Yes | Job ids or numbers, 1 to 200, separated by commas. Over the API a JSON list works too. A repeat is read once. | `job_1203, job_1204, 1205` | | `status` | text, in the JSON body | Yes | A status name or slug from Who am I. status_id works too. | `Canceled` | | `reason` | text, in the JSON body | No | Read on a move into Canceled: why. One reason covers every job. | `Customer found another mover` | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back accepted (true when at least one job changed), requested (how many different jobs you sent), applied (job_id and number of each job that changed), skipped (jobs where nothing needed to change, with why), refused (jobs the app refused, with the app's reason) and not_found (ids that match no job in the companies this credential reaches), then position. One job never stops the others: each runs the app's own single command by itself, with its own history line, and is not undone if another is refused. More than 200 jobs is refused whole, by name. Also status: where the jobs now stand. It never deletes anything. It changes only what the command names, and it writes the change to the job's history with who asked for it. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `accepted` | true or false | True when the command ran. A command that cannot run is an error instead. | | `requested` | whole number | The requested. | | `applied` | list of objects | The applied. | | `applied[].job_id` | id (text) | The id of the job. | | `applied[].number` | whole number | The number people say out loud, such as the job number. | | `skipped` | list | The skipped. | | `refused` | list of objects | The refused. | | `refused[].job_id` | id (text) | The id of the job. | | `refused[].number` | whole number | The number people say out loud, such as the job number. | | `refused[].reason` | text | The reason given. | | `not_found` | list | The not found. | | `position` | whole number | Where the change landed in the event log. Pass it as `after` on a read to see your own write. | | `status` | object | The job status. | | `status.id` | id (text) | The id of this record. Ids are opaque text: keep them exactly as given. | | `status.name` | text | The name, as the app shows it. | | `status.slug` | text | The same name as a lowercase code word. Match on this, not on the name. | ## Partial success The call is not one transaction. Read applied, skipped, refused and not_found; send the refused ones again after you fix the cause. A whole call replayed with the same Idempotency-Key does nothing twice. ## One credit per job A call costs one credit for each job it changed. Jobs skipped, refused or not found cost nothing. Before the call runs, your balance must cover every job you sent, or the call is refused no_credits and nothing changes. ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`read_only`](https://headhoncho.app/docs/api/errors#read_only) | 403 | This credential may read this area but not change it. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`missing_idempotency_key`](https://headhoncho.app/docs/api/errors#missing_idempotency_key) | 400 | Send an Idempotency-Key header on every command. | | [`idempotency_mismatch`](https://headhoncho.app/docs/api/errors#idempotency_mismatch) | 409 | This Idempotency-Key was used with a different body. | | [`idempotency_in_progress`](https://headhoncho.app/docs/api/errors#idempotency_in_progress) | 409 | A command with this Idempotency-Key is still running. Wait a moment and send it again. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [Bulk assign worker](https://headhoncho.app/docs/api/bulk_assign_worker): Put one technician or subcontractor on up to 200 jobs. A job that already has them is skipped. - [Bulk unassign worker](https://headhoncho.app/docs/api/bulk_unassign_worker): Take one technician or subcontractor off up to 200 jobs. - [Bulk add note](https://headhoncho.app/docs/api/bulk_add_note): Add the same note to up to 200 jobs. It appends to each job's log and never overwrites. - [Bulk archive jobs](https://headhoncho.app/docs/api/bulk_archive_jobs): File up to 200 finished jobs away. They keep their money and still count in every figure. - [Bulk unarchive jobs](https://headhoncho.app/docs/api/bulk_unarchive_jobs): Bring up to 200 archived jobs back, as they were. - [Bulk trash jobs](https://headhoncho.app/docs/api/bulk_trash_jobs): Move up to 200 jobs to Trash, with one reason. They leave every list and figure, and can be restored for 30 days. - [Bulk restore jobs](https://headhoncho.app/docs/api/bulk_restore_jobs): Bring up to 200 jobs back from Trash, whole: money, history and technicians. - The same records in the app: [the Jobs panel](https://headhoncho.app/docs/jobs). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "accepted": true, "requested": 3, "applied": [ { "job_id": "job_1203", "number": 1203 }, { "job_id": "job_1204", "number": 1204 } ], "skipped": [], "refused": [ { "job_id": "job_1205", "number": 1205, "reason": "This job is in Trash. Restore it first." } ], "not_found": [], "position": 88411, "status": { "id": "st_09", "name": "Canceled", "slug": "canceled" } } ``` ### cURL ```bash curl -X POST "https://api.headhoncho.app/api/v1/commands/bulk-change-job-status" \ -H "Authorization: Bearer hh_live_..." \ -H "Idempotency-Key: 6f1d2c9e-1b7a-4c1e-9a52-0d3f8e4b7a10" \ -H "Content-Type: application/json" \ -d '{ "job_ids": "job_1203, job_1204, 1205", "status": "Canceled", "reason": "Customer found another mover" }' ``` ### Python ```python import requests import uuid response = requests.post( "https://api.headhoncho.app/api/v1/commands/bulk-change-job-status", headers={ "Authorization": "Bearer hh_live_...", "Idempotency-Key": str(uuid.uuid4()), }, json={ "job_ids": "job_1203, job_1204, 1205", "status": "Canceled", "reason": "Customer found another mover", }, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/commands/bulk-change-job-status", { method: "POST", headers: { Authorization: "Bearer hh_live_...", "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "job_ids": "job_1203, job_1204, 1205", "status": "Canceled", "reason": "Customer found another mover" }), }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: bulk_change_status Arguments: job_ids (text, required), status (text, required), reason (text, optional) Access: do on Jobs Hints: readOnly=false, destructive=false, idempotent=true, openWorld=false Try asking: "Using HeadHoncho, bulk change status with job_ids job_1203, job_1204, 1205 and status Canceled and reason Customer found another mover." ``` --- # Bulk assign worker Bulk assign worker is a command in the HeadHoncho API. Put one technician or subcontractor on up to 200 jobs. A job that already has them is skipped. Page: https://headhoncho.app/docs/api/bulk_assign_worker | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **Bulk assign worker**, HeadHoncho API v1. It is a command, sent to the base address `https://api.headhoncho.app`. `POST /api/v1/commands/bulk-assign-worker` The key needs the **Jobs** area at **do**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). It runs the app's own command `bulk-assign-worker`. Send an `Idempotency-Key` header with every call: the same key with the same body returns the first answer and runs nothing twice. See [the model](https://headhoncho.app/docs/api/model#idempotency). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `job_ids` | text, in the JSON body | Yes | Job ids or numbers, 1 to 200, separated by commas. Over the API a JSON list works too. A repeat is read once. | `job_1203, job_1204, 1205` | | `worker_id` | id, in the JSON body | Yes | From Who am I. | `wrk_7a12` | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back accepted (true when at least one job changed), requested (how many different jobs you sent), applied (job_id and number of each job that changed), skipped (jobs where nothing needed to change, with why), refused (jobs the app refused, with the app's reason) and not_found (ids that match no job in the companies this credential reaches), then position. One job never stops the others: each runs the app's own single command by itself, with its own history line, and is not undone if another is refused. More than 200 jobs is refused whole, by name. Also automation: one sentence on what Job follow-up did for the jobs that changed, or empty. It never deletes anything. It changes only what the command names, and it writes the change to the job's history with who asked for it. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `accepted` | true or false | True when the command ran. A command that cannot run is an error instead. | | `requested` | whole number | The requested. | | `applied` | list of objects | The applied. | | `applied[].job_id` | id (text) | The id of the job. | | `applied[].number` | whole number | The number people say out loud, such as the job number. | | `skipped` | list | The skipped. | | `refused` | list of objects | The refused. | | `refused[].job_id` | id (text) | The id of the job. | | `refused[].number` | whole number | The number people say out loud, such as the job number. | | `refused[].reason` | text | The reason given. | | `not_found` | list | The not found. | | `position` | whole number | Where the change landed in the event log. Pass it as `after` on a read to see your own write. | | `automation` | text | One sentence on what an automation did because of this change, or empty. | ## Partial success The call is not one transaction. Read applied, skipped, refused and not_found; send the refused ones again after you fix the cause. A whole call replayed with the same Idempotency-Key does nothing twice. ## One credit per job A call costs one credit for each job it changed. Jobs skipped, refused or not found cost nothing. Before the call runs, your balance must cover every job you sent, or the call is refused no_credits and nothing changes. ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`read_only`](https://headhoncho.app/docs/api/errors#read_only) | 403 | This credential may read this area but not change it. | | [`not_found`](https://headhoncho.app/docs/api/errors#not_found) | 404 | No such record in the companies this credential reaches. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`missing_idempotency_key`](https://headhoncho.app/docs/api/errors#missing_idempotency_key) | 400 | Send an Idempotency-Key header on every command. | | [`idempotency_mismatch`](https://headhoncho.app/docs/api/errors#idempotency_mismatch) | 409 | This Idempotency-Key was used with a different body. | | [`idempotency_in_progress`](https://headhoncho.app/docs/api/errors#idempotency_in_progress) | 409 | A command with this Idempotency-Key is still running. Wait a moment and send it again. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [Bulk change status](https://headhoncho.app/docs/api/bulk_change_status): Move up to 200 jobs to one status. Each move lands in that job's history. - [Bulk unassign worker](https://headhoncho.app/docs/api/bulk_unassign_worker): Take one technician or subcontractor off up to 200 jobs. - [Bulk add note](https://headhoncho.app/docs/api/bulk_add_note): Add the same note to up to 200 jobs. It appends to each job's log and never overwrites. - [Bulk archive jobs](https://headhoncho.app/docs/api/bulk_archive_jobs): File up to 200 finished jobs away. They keep their money and still count in every figure. - [Bulk unarchive jobs](https://headhoncho.app/docs/api/bulk_unarchive_jobs): Bring up to 200 archived jobs back, as they were. - [Bulk trash jobs](https://headhoncho.app/docs/api/bulk_trash_jobs): Move up to 200 jobs to Trash, with one reason. They leave every list and figure, and can be restored for 30 days. - [Bulk restore jobs](https://headhoncho.app/docs/api/bulk_restore_jobs): Bring up to 200 jobs back from Trash, whole: money, history and technicians. - The same records in the app: [the Jobs panel](https://headhoncho.app/docs/jobs). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "accepted": true, "requested": 3, "applied": [ { "job_id": "job_1203", "number": 1203 }, { "job_id": "job_1204", "number": 1204 } ], "skipped": [], "refused": [ { "job_id": "job_1205", "number": 1205, "reason": "This job is in Trash. Restore it first." } ], "not_found": [], "position": 88411, "automation": "Tickets sent to Omar S." } ``` ### cURL ```bash curl -X POST "https://api.headhoncho.app/api/v1/commands/bulk-assign-worker" \ -H "Authorization: Bearer hh_live_..." \ -H "Idempotency-Key: 6f1d2c9e-1b7a-4c1e-9a52-0d3f8e4b7a10" \ -H "Content-Type: application/json" \ -d '{ "job_ids": "job_1203, job_1204, 1205", "worker_id": "wrk_7a12" }' ``` ### Python ```python import requests import uuid response = requests.post( "https://api.headhoncho.app/api/v1/commands/bulk-assign-worker", headers={ "Authorization": "Bearer hh_live_...", "Idempotency-Key": str(uuid.uuid4()), }, json={ "job_ids": "job_1203, job_1204, 1205", "worker_id": "wrk_7a12", }, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/commands/bulk-assign-worker", { method: "POST", headers: { Authorization: "Bearer hh_live_...", "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "job_ids": "job_1203, job_1204, 1205", "worker_id": "wrk_7a12" }), }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: bulk_assign_worker Arguments: job_ids (text, required), worker_id (id, required) Access: do on Jobs Hints: readOnly=false, destructive=false, idempotent=true, openWorld=false Try asking: "Using HeadHoncho, bulk assign worker with job_ids job_1203, job_1204, 1205 and worker_id wrk_7a12." ``` --- # Bulk unassign worker Bulk unassign worker is a command in the HeadHoncho API. Take one technician or subcontractor off up to 200 jobs. Page: https://headhoncho.app/docs/api/bulk_unassign_worker | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **Bulk unassign worker**, HeadHoncho API v1. It is a command, sent to the base address `https://api.headhoncho.app`. `POST /api/v1/commands/bulk-unassign-worker` The key needs the **Jobs** area at **do**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). It runs the app's own command `bulk-unassign-worker`. Send an `Idempotency-Key` header with every call: the same key with the same body returns the first answer and runs nothing twice. See [the model](https://headhoncho.app/docs/api/model#idempotency). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `job_ids` | text, in the JSON body | Yes | Job ids or numbers, 1 to 200, separated by commas. Over the API a JSON list works too. A repeat is read once. | `job_1203, job_1204, 1205` | | `worker_id` | id, in the JSON body | Yes | From Who am I. | `wrk_7a12` | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back accepted (true when at least one job changed), requested (how many different jobs you sent), applied (job_id and number of each job that changed), skipped (jobs where nothing needed to change, with why), refused (jobs the app refused, with the app's reason) and not_found (ids that match no job in the companies this credential reaches), then position. One job never stops the others: each runs the app's own single command by itself, with its own history line, and is not undone if another is refused. More than 200 jobs is refused whole, by name. It never deletes anything. It changes only what the command names, and it writes the change to the job's history with who asked for it. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `accepted` | true or false | True when the command ran. A command that cannot run is an error instead. | | `requested` | whole number | The requested. | | `applied` | list of objects | The applied. | | `applied[].job_id` | id (text) | The id of the job. | | `applied[].number` | whole number | The number people say out loud, such as the job number. | | `skipped` | list | The skipped. | | `refused` | list of objects | The refused. | | `refused[].job_id` | id (text) | The id of the job. | | `refused[].number` | whole number | The number people say out loud, such as the job number. | | `refused[].reason` | text | The reason given. | | `not_found` | list | The not found. | | `position` | whole number | Where the change landed in the event log. Pass it as `after` on a read to see your own write. | ## Partial success The call is not one transaction. Read applied, skipped, refused and not_found; send the refused ones again after you fix the cause. A whole call replayed with the same Idempotency-Key does nothing twice. ## One credit per job A call costs one credit for each job it changed. Jobs skipped, refused or not found cost nothing. Before the call runs, your balance must cover every job you sent, or the call is refused no_credits and nothing changes. ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`read_only`](https://headhoncho.app/docs/api/errors#read_only) | 403 | This credential may read this area but not change it. | | [`not_found`](https://headhoncho.app/docs/api/errors#not_found) | 404 | No such record in the companies this credential reaches. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`missing_idempotency_key`](https://headhoncho.app/docs/api/errors#missing_idempotency_key) | 400 | Send an Idempotency-Key header on every command. | | [`idempotency_mismatch`](https://headhoncho.app/docs/api/errors#idempotency_mismatch) | 409 | This Idempotency-Key was used with a different body. | | [`idempotency_in_progress`](https://headhoncho.app/docs/api/errors#idempotency_in_progress) | 409 | A command with this Idempotency-Key is still running. Wait a moment and send it again. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [Bulk change status](https://headhoncho.app/docs/api/bulk_change_status): Move up to 200 jobs to one status. Each move lands in that job's history. - [Bulk assign worker](https://headhoncho.app/docs/api/bulk_assign_worker): Put one technician or subcontractor on up to 200 jobs. A job that already has them is skipped. - [Bulk add note](https://headhoncho.app/docs/api/bulk_add_note): Add the same note to up to 200 jobs. It appends to each job's log and never overwrites. - [Bulk archive jobs](https://headhoncho.app/docs/api/bulk_archive_jobs): File up to 200 finished jobs away. They keep their money and still count in every figure. - [Bulk unarchive jobs](https://headhoncho.app/docs/api/bulk_unarchive_jobs): Bring up to 200 archived jobs back, as they were. - [Bulk trash jobs](https://headhoncho.app/docs/api/bulk_trash_jobs): Move up to 200 jobs to Trash, with one reason. They leave every list and figure, and can be restored for 30 days. - [Bulk restore jobs](https://headhoncho.app/docs/api/bulk_restore_jobs): Bring up to 200 jobs back from Trash, whole: money, history and technicians. - The same records in the app: [the Jobs panel](https://headhoncho.app/docs/jobs). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "accepted": true, "requested": 3, "applied": [ { "job_id": "job_1203", "number": 1203 }, { "job_id": "job_1204", "number": 1204 } ], "skipped": [], "refused": [ { "job_id": "job_1205", "number": 1205, "reason": "This job is in Trash. Restore it first." } ], "not_found": [], "position": 88411 } ``` ### cURL ```bash curl -X POST "https://api.headhoncho.app/api/v1/commands/bulk-unassign-worker" \ -H "Authorization: Bearer hh_live_..." \ -H "Idempotency-Key: 6f1d2c9e-1b7a-4c1e-9a52-0d3f8e4b7a10" \ -H "Content-Type: application/json" \ -d '{ "job_ids": "job_1203, job_1204, 1205", "worker_id": "wrk_7a12" }' ``` ### Python ```python import requests import uuid response = requests.post( "https://api.headhoncho.app/api/v1/commands/bulk-unassign-worker", headers={ "Authorization": "Bearer hh_live_...", "Idempotency-Key": str(uuid.uuid4()), }, json={ "job_ids": "job_1203, job_1204, 1205", "worker_id": "wrk_7a12", }, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/commands/bulk-unassign-worker", { method: "POST", headers: { Authorization: "Bearer hh_live_...", "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "job_ids": "job_1203, job_1204, 1205", "worker_id": "wrk_7a12" }), }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: bulk_unassign_worker Arguments: job_ids (text, required), worker_id (id, required) Access: do on Jobs Hints: readOnly=false, destructive=false, idempotent=true, openWorld=false Try asking: "Using HeadHoncho, bulk unassign worker with job_ids job_1203, job_1204, 1205 and worker_id wrk_7a12." ``` --- # Bulk add note Bulk add note is a command in the HeadHoncho API. Add the same note to up to 200 jobs. It appends to each job's log and never overwrites. Page: https://headhoncho.app/docs/api/bulk_add_note | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **Bulk add note**, HeadHoncho API v1. It is a command, sent to the base address `https://api.headhoncho.app`. `POST /api/v1/commands/bulk-add-job-note` The key needs the **Jobs** area at **do**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). It runs the app's own command `bulk-add-job-note`. Send an `Idempotency-Key` header with every call: the same key with the same body returns the first answer and runs nothing twice. See [the model](https://headhoncho.app/docs/api/model#idempotency). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `job_ids` | text, in the JSON body | Yes | Job ids or numbers, 1 to 200, separated by commas. Over the API a JSON list works too. A repeat is read once. | `job_1203, job_1204, 1205` | | `body` | text, in the JSON body | Yes | The note, as written. | `Confirmed with the client` | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back accepted (true when at least one job changed), requested (how many different jobs you sent), applied (job_id and number of each job that changed), skipped (jobs where nothing needed to change, with why), refused (jobs the app refused, with the app's reason) and not_found (ids that match no job in the companies this credential reaches), then position. One job never stops the others: each runs the app's own single command by itself, with its own history line, and is not undone if another is refused. More than 200 jobs is refused whole, by name. It never deletes anything. It changes only what the command names, and it writes the change to the job's history with who asked for it. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `accepted` | true or false | True when the command ran. A command that cannot run is an error instead. | | `requested` | whole number | The requested. | | `applied` | list of objects | The applied. | | `applied[].job_id` | id (text) | The id of the job. | | `applied[].number` | whole number | The number people say out loud, such as the job number. | | `skipped` | list | The skipped. | | `refused` | list of objects | The refused. | | `refused[].job_id` | id (text) | The id of the job. | | `refused[].number` | whole number | The number people say out loud, such as the job number. | | `refused[].reason` | text | The reason given. | | `not_found` | list | The not found. | | `position` | whole number | Where the change landed in the event log. Pass it as `after` on a read to see your own write. | ## Partial success The call is not one transaction. Read applied, skipped, refused and not_found; send the refused ones again after you fix the cause. A whole call replayed with the same Idempotency-Key does nothing twice. ## One credit per job A call costs one credit for each job it changed. Jobs skipped, refused or not found cost nothing. Before the call runs, your balance must cover every job you sent, or the call is refused no_credits and nothing changes. ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`read_only`](https://headhoncho.app/docs/api/errors#read_only) | 403 | This credential may read this area but not change it. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`missing_idempotency_key`](https://headhoncho.app/docs/api/errors#missing_idempotency_key) | 400 | Send an Idempotency-Key header on every command. | | [`idempotency_mismatch`](https://headhoncho.app/docs/api/errors#idempotency_mismatch) | 409 | This Idempotency-Key was used with a different body. | | [`idempotency_in_progress`](https://headhoncho.app/docs/api/errors#idempotency_in_progress) | 409 | A command with this Idempotency-Key is still running. Wait a moment and send it again. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [Bulk change status](https://headhoncho.app/docs/api/bulk_change_status): Move up to 200 jobs to one status. Each move lands in that job's history. - [Bulk assign worker](https://headhoncho.app/docs/api/bulk_assign_worker): Put one technician or subcontractor on up to 200 jobs. A job that already has them is skipped. - [Bulk unassign worker](https://headhoncho.app/docs/api/bulk_unassign_worker): Take one technician or subcontractor off up to 200 jobs. - [Bulk archive jobs](https://headhoncho.app/docs/api/bulk_archive_jobs): File up to 200 finished jobs away. They keep their money and still count in every figure. - [Bulk unarchive jobs](https://headhoncho.app/docs/api/bulk_unarchive_jobs): Bring up to 200 archived jobs back, as they were. - [Bulk trash jobs](https://headhoncho.app/docs/api/bulk_trash_jobs): Move up to 200 jobs to Trash, with one reason. They leave every list and figure, and can be restored for 30 days. - [Bulk restore jobs](https://headhoncho.app/docs/api/bulk_restore_jobs): Bring up to 200 jobs back from Trash, whole: money, history and technicians. - The same records in the app: [the Jobs panel](https://headhoncho.app/docs/jobs). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "accepted": true, "requested": 3, "applied": [ { "job_id": "job_1203", "number": 1203 }, { "job_id": "job_1204", "number": 1204 } ], "skipped": [], "refused": [ { "job_id": "job_1205", "number": 1205, "reason": "This job is in Trash. Restore it first." } ], "not_found": [], "position": 88411 } ``` ### cURL ```bash curl -X POST "https://api.headhoncho.app/api/v1/commands/bulk-add-job-note" \ -H "Authorization: Bearer hh_live_..." \ -H "Idempotency-Key: 6f1d2c9e-1b7a-4c1e-9a52-0d3f8e4b7a10" \ -H "Content-Type: application/json" \ -d '{ "job_ids": "job_1203, job_1204, 1205", "body": "Confirmed with the client" }' ``` ### Python ```python import requests import uuid response = requests.post( "https://api.headhoncho.app/api/v1/commands/bulk-add-job-note", headers={ "Authorization": "Bearer hh_live_...", "Idempotency-Key": str(uuid.uuid4()), }, json={ "job_ids": "job_1203, job_1204, 1205", "body": "Confirmed with the client", }, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/commands/bulk-add-job-note", { method: "POST", headers: { Authorization: "Bearer hh_live_...", "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "job_ids": "job_1203, job_1204, 1205", "body": "Confirmed with the client" }), }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: bulk_add_note Arguments: job_ids (text, required), body (text, required) Access: do on Jobs Hints: readOnly=false, destructive=false, idempotent=false, openWorld=false Try asking: "Using HeadHoncho, bulk add note with job_ids job_1203, job_1204, 1205 and body Confirmed with the client." ``` --- # Bulk archive jobs Bulk archive jobs is a command in the HeadHoncho API. File up to 200 finished jobs away. They keep their money and still count in every figure. Page: https://headhoncho.app/docs/api/bulk_archive_jobs | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **Bulk archive jobs**, HeadHoncho API v1. It is a command, sent to the base address `https://api.headhoncho.app`. `POST /api/v1/commands/bulk-archive-jobs` The key needs the **Jobs** area at **do**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). It runs the app's own command `bulk-archive-jobs`. Send an `Idempotency-Key` header with every call: the same key with the same body returns the first answer and runs nothing twice. See [the model](https://headhoncho.app/docs/api/model#idempotency). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `job_ids` | text, in the JSON body | Yes | Job ids or numbers, 1 to 200, separated by commas. Over the API a JSON list works too. A repeat is read once. | `job_1203, job_1204, 1205` | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back accepted (true when at least one job changed), requested (how many different jobs you sent), applied (job_id and number of each job that changed), skipped (jobs where nothing needed to change, with why), refused (jobs the app refused, with the app's reason) and not_found (ids that match no job in the companies this credential reaches), then position. One job never stops the others: each runs the app's own single command by itself, with its own history line, and is not undone if another is refused. More than 200 jobs is refused whole, by name. It never deletes anything. It changes only what the command names, and it writes the change to the job's history with who asked for it. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `accepted` | true or false | True when the command ran. A command that cannot run is an error instead. | | `requested` | whole number | The requested. | | `applied` | list of objects | The applied. | | `applied[].job_id` | id (text) | The id of the job. | | `applied[].number` | whole number | The number people say out loud, such as the job number. | | `skipped` | list | The skipped. | | `refused` | list of objects | The refused. | | `refused[].job_id` | id (text) | The id of the job. | | `refused[].number` | whole number | The number people say out loud, such as the job number. | | `refused[].reason` | text | The reason given. | | `not_found` | list | The not found. | | `position` | whole number | Where the change landed in the event log. Pass it as `after` on a read to see your own write. | ## Partial success The call is not one transaction. Read applied, skipped, refused and not_found; send the refused ones again after you fix the cause. A whole call replayed with the same Idempotency-Key does nothing twice. ## One credit per job A call costs one credit for each job it changed. Jobs skipped, refused or not found cost nothing. Before the call runs, your balance must cover every job you sent, or the call is refused no_credits and nothing changes. ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`read_only`](https://headhoncho.app/docs/api/errors#read_only) | 403 | This credential may read this area but not change it. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`missing_idempotency_key`](https://headhoncho.app/docs/api/errors#missing_idempotency_key) | 400 | Send an Idempotency-Key header on every command. | | [`idempotency_mismatch`](https://headhoncho.app/docs/api/errors#idempotency_mismatch) | 409 | This Idempotency-Key was used with a different body. | | [`idempotency_in_progress`](https://headhoncho.app/docs/api/errors#idempotency_in_progress) | 409 | A command with this Idempotency-Key is still running. Wait a moment and send it again. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [Bulk change status](https://headhoncho.app/docs/api/bulk_change_status): Move up to 200 jobs to one status. Each move lands in that job's history. - [Bulk assign worker](https://headhoncho.app/docs/api/bulk_assign_worker): Put one technician or subcontractor on up to 200 jobs. A job that already has them is skipped. - [Bulk unassign worker](https://headhoncho.app/docs/api/bulk_unassign_worker): Take one technician or subcontractor off up to 200 jobs. - [Bulk add note](https://headhoncho.app/docs/api/bulk_add_note): Add the same note to up to 200 jobs. It appends to each job's log and never overwrites. - [Bulk unarchive jobs](https://headhoncho.app/docs/api/bulk_unarchive_jobs): Bring up to 200 archived jobs back, as they were. - [Bulk trash jobs](https://headhoncho.app/docs/api/bulk_trash_jobs): Move up to 200 jobs to Trash, with one reason. They leave every list and figure, and can be restored for 30 days. - [Bulk restore jobs](https://headhoncho.app/docs/api/bulk_restore_jobs): Bring up to 200 jobs back from Trash, whole: money, history and technicians. - The same records in the app: [the Jobs panel](https://headhoncho.app/docs/jobs). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "accepted": true, "requested": 3, "applied": [ { "job_id": "job_1203", "number": 1203 }, { "job_id": "job_1204", "number": 1204 } ], "skipped": [], "refused": [ { "job_id": "job_1205", "number": 1205, "reason": "This job is in Trash. Restore it first." } ], "not_found": [], "position": 88411 } ``` ### cURL ```bash curl -X POST "https://api.headhoncho.app/api/v1/commands/bulk-archive-jobs" \ -H "Authorization: Bearer hh_live_..." \ -H "Idempotency-Key: 6f1d2c9e-1b7a-4c1e-9a52-0d3f8e4b7a10" \ -H "Content-Type: application/json" \ -d '{ "job_ids": "job_1203, job_1204, 1205" }' ``` ### Python ```python import requests import uuid response = requests.post( "https://api.headhoncho.app/api/v1/commands/bulk-archive-jobs", headers={ "Authorization": "Bearer hh_live_...", "Idempotency-Key": str(uuid.uuid4()), }, json={ "job_ids": "job_1203, job_1204, 1205", }, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/commands/bulk-archive-jobs", { method: "POST", headers: { Authorization: "Bearer hh_live_...", "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "job_ids": "job_1203, job_1204, 1205" }), }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: bulk_archive_jobs Arguments: job_ids (text, required) Access: do on Jobs Hints: readOnly=false, destructive=false, idempotent=true, openWorld=false Try asking: "Using HeadHoncho, bulk archive jobs with job_ids job_1203, job_1204, 1205." ``` --- # Bulk unarchive jobs Bulk unarchive jobs is a command in the HeadHoncho API. Bring up to 200 archived jobs back, as they were. Page: https://headhoncho.app/docs/api/bulk_unarchive_jobs | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **Bulk unarchive jobs**, HeadHoncho API v1. It is a command, sent to the base address `https://api.headhoncho.app`. `POST /api/v1/commands/bulk-unarchive-jobs` The key needs the **Jobs** area at **do**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). It runs the app's own command `bulk-unarchive-jobs`. Send an `Idempotency-Key` header with every call: the same key with the same body returns the first answer and runs nothing twice. See [the model](https://headhoncho.app/docs/api/model#idempotency). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `job_ids` | text, in the JSON body | Yes | Job ids or numbers, 1 to 200, separated by commas. Over the API a JSON list works too. A repeat is read once. | `job_1203, job_1204, 1205` | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back accepted (true when at least one job changed), requested (how many different jobs you sent), applied (job_id and number of each job that changed), skipped (jobs where nothing needed to change, with why), refused (jobs the app refused, with the app's reason) and not_found (ids that match no job in the companies this credential reaches), then position. One job never stops the others: each runs the app's own single command by itself, with its own history line, and is not undone if another is refused. More than 200 jobs is refused whole, by name. It never deletes anything. It changes only what the command names, and it writes the change to the job's history with who asked for it. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `accepted` | true or false | True when the command ran. A command that cannot run is an error instead. | | `requested` | whole number | The requested. | | `applied` | list of objects | The applied. | | `applied[].job_id` | id (text) | The id of the job. | | `applied[].number` | whole number | The number people say out loud, such as the job number. | | `skipped` | list | The skipped. | | `refused` | list of objects | The refused. | | `refused[].job_id` | id (text) | The id of the job. | | `refused[].number` | whole number | The number people say out loud, such as the job number. | | `refused[].reason` | text | The reason given. | | `not_found` | list | The not found. | | `position` | whole number | Where the change landed in the event log. Pass it as `after` on a read to see your own write. | ## Partial success The call is not one transaction. Read applied, skipped, refused and not_found; send the refused ones again after you fix the cause. A whole call replayed with the same Idempotency-Key does nothing twice. ## One credit per job A call costs one credit for each job it changed. Jobs skipped, refused or not found cost nothing. Before the call runs, your balance must cover every job you sent, or the call is refused no_credits and nothing changes. ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`read_only`](https://headhoncho.app/docs/api/errors#read_only) | 403 | This credential may read this area but not change it. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`missing_idempotency_key`](https://headhoncho.app/docs/api/errors#missing_idempotency_key) | 400 | Send an Idempotency-Key header on every command. | | [`idempotency_mismatch`](https://headhoncho.app/docs/api/errors#idempotency_mismatch) | 409 | This Idempotency-Key was used with a different body. | | [`idempotency_in_progress`](https://headhoncho.app/docs/api/errors#idempotency_in_progress) | 409 | A command with this Idempotency-Key is still running. Wait a moment and send it again. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [Bulk change status](https://headhoncho.app/docs/api/bulk_change_status): Move up to 200 jobs to one status. Each move lands in that job's history. - [Bulk assign worker](https://headhoncho.app/docs/api/bulk_assign_worker): Put one technician or subcontractor on up to 200 jobs. A job that already has them is skipped. - [Bulk unassign worker](https://headhoncho.app/docs/api/bulk_unassign_worker): Take one technician or subcontractor off up to 200 jobs. - [Bulk add note](https://headhoncho.app/docs/api/bulk_add_note): Add the same note to up to 200 jobs. It appends to each job's log and never overwrites. - [Bulk archive jobs](https://headhoncho.app/docs/api/bulk_archive_jobs): File up to 200 finished jobs away. They keep their money and still count in every figure. - [Bulk trash jobs](https://headhoncho.app/docs/api/bulk_trash_jobs): Move up to 200 jobs to Trash, with one reason. They leave every list and figure, and can be restored for 30 days. - [Bulk restore jobs](https://headhoncho.app/docs/api/bulk_restore_jobs): Bring up to 200 jobs back from Trash, whole: money, history and technicians. - The same records in the app: [the Jobs panel](https://headhoncho.app/docs/jobs). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "accepted": true, "requested": 3, "applied": [ { "job_id": "job_1203", "number": 1203 }, { "job_id": "job_1204", "number": 1204 } ], "skipped": [], "refused": [ { "job_id": "job_1205", "number": 1205, "reason": "This job is in Trash. Restore it first." } ], "not_found": [], "position": 88411 } ``` ### cURL ```bash curl -X POST "https://api.headhoncho.app/api/v1/commands/bulk-unarchive-jobs" \ -H "Authorization: Bearer hh_live_..." \ -H "Idempotency-Key: 6f1d2c9e-1b7a-4c1e-9a52-0d3f8e4b7a10" \ -H "Content-Type: application/json" \ -d '{ "job_ids": "job_1203, job_1204, 1205" }' ``` ### Python ```python import requests import uuid response = requests.post( "https://api.headhoncho.app/api/v1/commands/bulk-unarchive-jobs", headers={ "Authorization": "Bearer hh_live_...", "Idempotency-Key": str(uuid.uuid4()), }, json={ "job_ids": "job_1203, job_1204, 1205", }, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/commands/bulk-unarchive-jobs", { method: "POST", headers: { Authorization: "Bearer hh_live_...", "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "job_ids": "job_1203, job_1204, 1205" }), }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: bulk_unarchive_jobs Arguments: job_ids (text, required) Access: do on Jobs Hints: readOnly=false, destructive=false, idempotent=true, openWorld=false Try asking: "Using HeadHoncho, bulk unarchive jobs with job_ids job_1203, job_1204, 1205." ``` --- # Bulk trash jobs Bulk trash jobs is a command in the HeadHoncho API. Move up to 200 jobs to Trash, with one reason. They leave every list and figure, and can be restored for 30 days. Page: https://headhoncho.app/docs/api/bulk_trash_jobs | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **Bulk trash jobs**, HeadHoncho API v1. It is a command, sent to the base address `https://api.headhoncho.app`. `POST /api/v1/commands/bulk-trash-jobs` The key needs the **Jobs** area at **do**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). It runs the app's own command `bulk-trash-jobs`. Send an `Idempotency-Key` header with every call: the same key with the same body returns the first answer and runs nothing twice. See [the model](https://headhoncho.app/docs/api/model#idempotency). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `job_ids` | text, in the JSON body | Yes | Job ids or numbers, 1 to 200, separated by commas. Over the API a JSON list works too. A repeat is read once. | `job_1203, job_1204, 1205` | | `reason` | text, in the JSON body | Yes | Why, as the Trash tab will show it. One reason covers every job. | `Duplicates from the import` | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back accepted (true when at least one job changed), requested (how many different jobs you sent), applied (job_id and number of each job that changed), skipped (jobs where nothing needed to change, with why), refused (jobs the app refused, with the app's reason) and not_found (ids that match no job in the companies this credential reaches), then position. One job never stops the others: each runs the app's own single command by itself, with its own history line, and is not undone if another is refused. More than 200 jobs is refused whole, by name. Erasing for good is done in the app only. It never deletes anything. It changes only what the command names, and it writes the change to the job's history with who asked for it. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `accepted` | true or false | True when the command ran. A command that cannot run is an error instead. | | `requested` | whole number | The requested. | | `applied` | list of objects | The applied. | | `applied[].job_id` | id (text) | The id of the job. | | `applied[].number` | whole number | The number people say out loud, such as the job number. | | `skipped` | list | The skipped. | | `refused` | list of objects | The refused. | | `refused[].job_id` | id (text) | The id of the job. | | `refused[].number` | whole number | The number people say out loud, such as the job number. | | `refused[].reason` | text | The reason given. | | `not_found` | list | The not found. | | `position` | whole number | Where the change landed in the event log. Pass it as `after` on a read to see your own write. | ## Partial success The call is not one transaction. Read applied, skipped, refused and not_found; send the refused ones again after you fix the cause. A whole call replayed with the same Idempotency-Key does nothing twice. ## One credit per job A call costs one credit for each job it changed. Jobs skipped, refused or not found cost nothing. Before the call runs, your balance must cover every job you sent, or the call is refused no_credits and nothing changes. ## Delete is Trash Nothing is erased. Jobs wait in Trash until someone restores them or 30 days pass. ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`read_only`](https://headhoncho.app/docs/api/errors#read_only) | 403 | This credential may read this area but not change it. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`missing_idempotency_key`](https://headhoncho.app/docs/api/errors#missing_idempotency_key) | 400 | Send an Idempotency-Key header on every command. | | [`idempotency_mismatch`](https://headhoncho.app/docs/api/errors#idempotency_mismatch) | 409 | This Idempotency-Key was used with a different body. | | [`idempotency_in_progress`](https://headhoncho.app/docs/api/errors#idempotency_in_progress) | 409 | A command with this Idempotency-Key is still running. Wait a moment and send it again. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [Bulk change status](https://headhoncho.app/docs/api/bulk_change_status): Move up to 200 jobs to one status. Each move lands in that job's history. - [Bulk assign worker](https://headhoncho.app/docs/api/bulk_assign_worker): Put one technician or subcontractor on up to 200 jobs. A job that already has them is skipped. - [Bulk unassign worker](https://headhoncho.app/docs/api/bulk_unassign_worker): Take one technician or subcontractor off up to 200 jobs. - [Bulk add note](https://headhoncho.app/docs/api/bulk_add_note): Add the same note to up to 200 jobs. It appends to each job's log and never overwrites. - [Bulk archive jobs](https://headhoncho.app/docs/api/bulk_archive_jobs): File up to 200 finished jobs away. They keep their money and still count in every figure. - [Bulk unarchive jobs](https://headhoncho.app/docs/api/bulk_unarchive_jobs): Bring up to 200 archived jobs back, as they were. - [Bulk restore jobs](https://headhoncho.app/docs/api/bulk_restore_jobs): Bring up to 200 jobs back from Trash, whole: money, history and technicians. - The same records in the app: [the Jobs panel](https://headhoncho.app/docs/jobs). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "accepted": true, "requested": 3, "applied": [ { "job_id": "job_1203", "number": 1203 }, { "job_id": "job_1204", "number": 1204 } ], "skipped": [], "refused": [ { "job_id": "job_1205", "number": 1205, "reason": "This job is in Trash. Restore it first." } ], "not_found": [], "position": 88411 } ``` ### cURL ```bash curl -X POST "https://api.headhoncho.app/api/v1/commands/bulk-trash-jobs" \ -H "Authorization: Bearer hh_live_..." \ -H "Idempotency-Key: 6f1d2c9e-1b7a-4c1e-9a52-0d3f8e4b7a10" \ -H "Content-Type: application/json" \ -d '{ "job_ids": "job_1203, job_1204, 1205", "reason": "Duplicates from the import" }' ``` ### Python ```python import requests import uuid response = requests.post( "https://api.headhoncho.app/api/v1/commands/bulk-trash-jobs", headers={ "Authorization": "Bearer hh_live_...", "Idempotency-Key": str(uuid.uuid4()), }, json={ "job_ids": "job_1203, job_1204, 1205", "reason": "Duplicates from the import", }, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/commands/bulk-trash-jobs", { method: "POST", headers: { Authorization: "Bearer hh_live_...", "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "job_ids": "job_1203, job_1204, 1205", "reason": "Duplicates from the import" }), }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: bulk_trash_jobs Arguments: job_ids (text, required), reason (text, required) Access: do on Jobs Hints: readOnly=false, destructive=true, idempotent=true, openWorld=false Try asking: "Using HeadHoncho, bulk trash jobs with job_ids job_1203, job_1204, 1205 and reason Duplicates from the import." ``` --- # Bulk restore jobs Bulk restore jobs is a command in the HeadHoncho API. Bring up to 200 jobs back from Trash, whole: money, history and technicians. Page: https://headhoncho.app/docs/api/bulk_restore_jobs | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **Bulk restore jobs**, HeadHoncho API v1. It is a command, sent to the base address `https://api.headhoncho.app`. `POST /api/v1/commands/bulk-restore-jobs` The key needs the **Jobs** area at **do**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). It runs the app's own command `bulk-restore-jobs`. Send an `Idempotency-Key` header with every call: the same key with the same body returns the first answer and runs nothing twice. See [the model](https://headhoncho.app/docs/api/model#idempotency). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `job_ids` | text, in the JSON body | Yes | Job ids or numbers, 1 to 200, separated by commas. Over the API a JSON list works too. A repeat is read once. | `job_1203, job_1204, 1205` | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back accepted (true when at least one job changed), requested (how many different jobs you sent), applied (job_id and number of each job that changed), skipped (jobs where nothing needed to change, with why), refused (jobs the app refused, with the app's reason) and not_found (ids that match no job in the companies this credential reaches), then position. One job never stops the others: each runs the app's own single command by itself, with its own history line, and is not undone if another is refused. More than 200 jobs is refused whole, by name. Only jobs in Trash are found by this call; List jobs with bin=trash finds them. It never deletes anything. It changes only what the command names, and it writes the change to the job's history with who asked for it. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `accepted` | true or false | True when the command ran. A command that cannot run is an error instead. | | `requested` | whole number | The requested. | | `applied` | list of objects | The applied. | | `applied[].job_id` | id (text) | The id of the job. | | `applied[].number` | whole number | The number people say out loud, such as the job number. | | `skipped` | list | The skipped. | | `refused` | list of objects | The refused. | | `refused[].job_id` | id (text) | The id of the job. | | `refused[].number` | whole number | The number people say out loud, such as the job number. | | `refused[].reason` | text | The reason given. | | `not_found` | list | The not found. | | `position` | whole number | Where the change landed in the event log. Pass it as `after` on a read to see your own write. | ## Partial success The call is not one transaction. Read applied, skipped, refused and not_found; send the refused ones again after you fix the cause. A whole call replayed with the same Idempotency-Key does nothing twice. ## One credit per job A call costs one credit for each job it changed. Jobs skipped, refused or not found cost nothing. Before the call runs, your balance must cover every job you sent, or the call is refused no_credits and nothing changes. ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`read_only`](https://headhoncho.app/docs/api/errors#read_only) | 403 | This credential may read this area but not change it. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`missing_idempotency_key`](https://headhoncho.app/docs/api/errors#missing_idempotency_key) | 400 | Send an Idempotency-Key header on every command. | | [`idempotency_mismatch`](https://headhoncho.app/docs/api/errors#idempotency_mismatch) | 409 | This Idempotency-Key was used with a different body. | | [`idempotency_in_progress`](https://headhoncho.app/docs/api/errors#idempotency_in_progress) | 409 | A command with this Idempotency-Key is still running. Wait a moment and send it again. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [Bulk change status](https://headhoncho.app/docs/api/bulk_change_status): Move up to 200 jobs to one status. Each move lands in that job's history. - [Bulk assign worker](https://headhoncho.app/docs/api/bulk_assign_worker): Put one technician or subcontractor on up to 200 jobs. A job that already has them is skipped. - [Bulk unassign worker](https://headhoncho.app/docs/api/bulk_unassign_worker): Take one technician or subcontractor off up to 200 jobs. - [Bulk add note](https://headhoncho.app/docs/api/bulk_add_note): Add the same note to up to 200 jobs. It appends to each job's log and never overwrites. - [Bulk archive jobs](https://headhoncho.app/docs/api/bulk_archive_jobs): File up to 200 finished jobs away. They keep their money and still count in every figure. - [Bulk unarchive jobs](https://headhoncho.app/docs/api/bulk_unarchive_jobs): Bring up to 200 archived jobs back, as they were. - [Bulk trash jobs](https://headhoncho.app/docs/api/bulk_trash_jobs): Move up to 200 jobs to Trash, with one reason. They leave every list and figure, and can be restored for 30 days. - The same records in the app: [the Jobs panel](https://headhoncho.app/docs/jobs). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "accepted": true, "requested": 3, "applied": [ { "job_id": "job_1203", "number": 1203 }, { "job_id": "job_1204", "number": 1204 } ], "skipped": [], "refused": [ { "job_id": "job_1205", "number": 1205, "reason": "This job is in Trash. Restore it first." } ], "not_found": [], "position": 88411 } ``` ### cURL ```bash curl -X POST "https://api.headhoncho.app/api/v1/commands/bulk-restore-jobs" \ -H "Authorization: Bearer hh_live_..." \ -H "Idempotency-Key: 6f1d2c9e-1b7a-4c1e-9a52-0d3f8e4b7a10" \ -H "Content-Type: application/json" \ -d '{ "job_ids": "job_1203, job_1204, 1205" }' ``` ### Python ```python import requests import uuid response = requests.post( "https://api.headhoncho.app/api/v1/commands/bulk-restore-jobs", headers={ "Authorization": "Bearer hh_live_...", "Idempotency-Key": str(uuid.uuid4()), }, json={ "job_ids": "job_1203, job_1204, 1205", }, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/commands/bulk-restore-jobs", { method: "POST", headers: { Authorization: "Bearer hh_live_...", "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "job_ids": "job_1203, job_1204, 1205" }), }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: bulk_restore_jobs Arguments: job_ids (text, required) Access: do on Jobs Hints: readOnly=false, destructive=false, idempotent=true, openWorld=false Try asking: "Using HeadHoncho, bulk restore jobs with job_ids job_1203, job_1204, 1205." ``` --- # Get settings Get settings is a read in the HeadHoncho API. What each company is set up with: name, hours, service area, week and time zone, plus the job types and the statuses with their line. Page: https://headhoncho.app/docs/api/get_settings | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **Get settings**, HeadHoncho API v1. It is a read, sent to the base address `https://api.headhoncho.app`. `GET /api/v1/settings` The key needs the **Company settings** area at **read**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). Send your key as `Authorization: Bearer hh_live_...`. See [API keys](https://headhoncho.app/docs/api/keys). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `company_id` | id, in the query | No | One company. Default: every company the credential reaches. | `cmp_14f5` | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back organization (id, name). companies, one per company: id, name, status, service_area, time_zone, country, week_start and week_end (0 is Monday), color, has_logo, business_hours (weekday, opens, closes) and service_places (city, state). job_types and statuses are shared by every company: each status has its slug, tone, colors, icon, band (line or detour), position, archived and job_count, the jobs on it in the companies this credential reaches. status_icons lists the marks a status may wear. It never changes a record. It only reads the companies the key reaches. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `organization` | object | The organization. | | `organization.id` | id (text) | The id of this record. Ids are opaque text: keep them exactly as given. | | `organization.name` | text | The name, as the app shows it. | | `companies` | list of objects | The companies. | | `companies[].id` | id (text) | The id of this record. Ids are opaque text: keep them exactly as given. | | `companies[].name` | text | The name, as the app shows it. | | `companies[].status` | text | The job status. | | `companies[].service_area` | text | The service area. | | `companies[].time_zone` | text | The company's time zone name, such as America/Chicago. | | `companies[].country` | text | The country. | | `companies[].week_start` | whole number | The week start. | | `companies[].week_end` | whole number | The week end. | | `companies[].color` | text | The color. | | `companies[].has_logo` | true or false | True when there is a logo. | | `companies[].business_hours` | list of objects | The business hours. | | `companies[].business_hours[].weekday` | whole number | The weekday. | | `companies[].business_hours[].opens` | text | The opens. | | `companies[].business_hours[].closes` | text | The closes. | | `companies[].service_places` | list of objects | The service places. | | `companies[].service_places[].city` | text | The city. | | `companies[].service_places[].state` | text | The state or region. | | `job_types` | list of objects | The job types. | | `job_types[].id` | id (text) | The id of this record. Ids are opaque text: keep them exactly as given. | | `job_types[].name` | text | The name, as the app shows it. | | `job_types[].position` | whole number | Where the change landed in the event log. Pass it as `after` on a read to see your own write. | | `job_types[].archived` | true or false | The archived. | | `statuses` | list of objects | The statuses. | | `statuses[].id` | id (text) | The id of this record. Ids are opaque text: keep them exactly as given. | | `statuses[].name` | text | The name, as the app shows it. | | `statuses[].slug` | text | The same name as a lowercase code word. Match on this, not on the name. | | `statuses[].tone` | text | The tone. | | `statuses[].color` | text | The color. | | `statuses[].ink` | text | The ink. | | `statuses[].icon` | text | The icon. | | `statuses[].band` | text | The band. | | `statuses[].position` | whole number | Where the change landed in the event log. Pass it as `after` on a read to see your own write. | | `statuses[].archived` | true or false | The archived. | | `statuses[].job_count` | whole number | The job count. | | `status_icons` | list of text | The status icons. | ## Shared by every company Job types and statuses belong to the workspace, not to one company. The same list is returned whichever company you ask for. ## Counts job_count leaves out Trash and jobs in companies this credential does not reach. ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`not_found`](https://headhoncho.app/docs/api/errors#not_found) | 404 | No such record in the companies this credential reaches. | | [`out_of_scope`](https://headhoncho.app/docs/api/errors#out_of_scope) | 404 | No such company in the companies this credential reaches. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - The same records in the app: [Settings](https://headhoncho.app/docs/settings). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "organization": { "id": "org_2c7d", "name": "Northwind Ads" }, "companies": [ { "id": "cmp_14f5", "name": "Sunrise Moving", "status": "active", "service_area": "Bloomington and Normal, IL", "time_zone": "America/Chicago", "country": "US", "week_start": 0, "week_end": 6, "color": "#2f6fdb", "has_logo": false, "business_hours": [ { "weekday": 0, "opens": "08:00:00", "closes": "17:00:00" }, { "weekday": 1, "opens": "08:00:00", "closes": "17:00:00" } ], "service_places": [ { "city": "Bloomington", "state": "IL" }, { "city": "Normal", "state": "IL" } ] } ], "job_types": [ { "id": "jt_02", "name": "Local move", "position": 0, "archived": false }, { "id": "jt_05", "name": "Packing only", "position": 1, "archived": false } ], "statuses": [ { "id": "st_01", "name": "Draft", "slug": "draft", "tone": "neutral", "color": "", "ink": "", "icon": "", "band": "line", "position": 0, "archived": false, "job_count": 12 }, { "id": "st_02", "name": "Scheduled", "slug": "submitted", "tone": "info", "color": "", "ink": "", "icon": "", "band": "line", "position": 1, "archived": false, "job_count": 31 }, { "id": "st_09", "name": "Waiting", "slug": "", "tone": "warn", "color": "#f2c94c", "ink": "#3a2f00", "icon": "pause", "band": "detour", "position": 7, "archived": false, "job_count": 4 } ], "status_icons": [ "alarm", "schedule", "call", "chat", "warning", "gavel", "help", "pause", "person", "construction", "payments" ] } ``` ### cURL ```bash curl "https://api.headhoncho.app/api/v1/settings?company_id=cmp_14f5" \ -H "Authorization: Bearer hh_live_..." ``` ### Python ```python import requests response = requests.get( "https://api.headhoncho.app/api/v1/settings", headers={"Authorization": "Bearer hh_live_..."}, params={ "company_id": "cmp_14f5", }, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/settings?company_id=cmp_14f5", { headers: { Authorization: "Bearer hh_live_..." }, }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: get_settings Arguments: company_id (id, optional) Access: read on Company settings Hints: readOnly=true, destructive=false, idempotent=true, openWorld=false Try asking: "Using HeadHoncho, get settings with company_id cmp_14f5." ``` --- # Update company Update company is a command in the HeadHoncho API. Change one company's own facts: name, service area, time zone, country, color, week, opening hours or service places. Only what you send changes. Page: https://headhoncho.app/docs/api/update_company | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **Update company**, HeadHoncho API v1. It is a command, sent to the base address `https://api.headhoncho.app`. `POST /api/v1/commands/update-company` The key needs the **Company settings** area at **do**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). It runs the app's own command `update-company`. Send an `Idempotency-Key` header with every call: the same key with the same body returns the first answer and runs nothing twice. See [the model](https://headhoncho.app/docs/api/model#idempotency). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `company_id` | id, in the JSON body | Yes | From Who am I. | `cmp_14f5` | | `name` | text, in the JSON body | No | At least 3 characters. Two companies cannot share a name. | `Sunrise Moving and Storage` | | `service_area` | text, in the JSON body | No | A sentence about where the company works. Empty clears it. | `Bloomington and Normal, IL` | | `time_zone` | text, in the JSON body | No | An IANA time zone name. | `America/Chicago` | | `country` | text, in the JSON body | No | Two letters. It decides how phone numbers typed here are read. | `US` | | `color` | text, in the JSON body | No | The brand color as #rrggbb. Empty lets the app pick one. | `#2f6fdb` | | `week_start` | number, in the JSON body | No | The first day of the company's week, 0 (Monday) to 6 (Sunday). | `0` | | `week_end` | number, in the JSON body | No | The last day of the company's week, 0 to 6. | `6` | | `business_hours` | text, in the JSON body | No | The whole week as a JSON list of weekday (0 to 6), opens and closes (HH:MM). It replaces the old hours. Send [] to clear. | `[{"weekday": 0, "opens": "08:00", "closes": "17:00"}]` | | `service_places` | text, in the JSON body | No | Every place served as a JSON list of city and 2-letter state. It replaces the old list. Send [] to clear. | `[{"city": "Bloomington", "state": "IL"}]` | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back accepted, company_id, name and position. It never deletes anything. It changes only what the command names, and it writes the change to the job's history with who asked for it. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `accepted` | true or false | True when the command ran. A command that cannot run is an error instead. | | `position` | whole number | Where the change landed in the event log. Pass it as `after` on a read to see your own write. | | `company_id` | id (text) | The id of the company. | | `name` | text | The name, as the app shows it. | ## Owner or admin only The app keeps this to an owner or an admin of the workspace, so a key made by anyone else is refused with no_access. ## Lists are replaced business_hours and service_places replace the whole list, so a stale copy can never bring back a day that was removed. ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`read_only`](https://headhoncho.app/docs/api/errors#read_only) | 403 | This credential may read this area but not change it. | | [`not_found`](https://headhoncho.app/docs/api/errors#not_found) | 404 | No such record in the companies this credential reaches. | | [`out_of_scope`](https://headhoncho.app/docs/api/errors#out_of_scope) | 404 | No such company in the companies this credential reaches. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`missing_idempotency_key`](https://headhoncho.app/docs/api/errors#missing_idempotency_key) | 400 | Send an Idempotency-Key header on every command. | | [`idempotency_mismatch`](https://headhoncho.app/docs/api/errors#idempotency_mismatch) | 409 | This Idempotency-Key was used with a different body. | | [`idempotency_in_progress`](https://headhoncho.app/docs/api/errors#idempotency_in_progress) | 409 | A command with this Idempotency-Key is still running. Wait a moment and send it again. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [Create company](https://headhoncho.app/docs/api/create_company): Add another company to the workspace. It starts with the first company's time zone and country unless you send your own. - [Update organization](https://headhoncho.app/docs/api/update_organization): Rename the workspace. A company still carrying the old workspace name is renamed with it. - [Add job type](https://headhoncho.app/docs/api/add_job_type): Add a kind of work the business does, such as Local move or Roof repair. A name already in use is refused. - [Update job type](https://headhoncho.app/docs/api/update_job_type): Rename a job type, move it in the list, or retire it so new jobs cannot pick it. Old jobs keep it. - [Update job status](https://headhoncho.app/docs/api/update_job_status): Rename a status, change its look, move it in the list, or retire it. A rename shows on every job at once. Its slug and band stay. - [Set status band](https://headhoncho.app/docs/api/set_status_band): Put a status on the line (a step every job passes) or off it as a detour (a place a job gets stuck). The line closes up behind it. - [Replace job status](https://headhoncho.app/docs/api/replace_job_status): Let another status stand in for this one: move its jobs onto the new status, retire the old word, or both. Name an existing status or a new one. - [Add job status](https://headhoncho.app/docs/api/add_job_status): Add a status to the workspace's list, on the line or as a detour. It carries no role: it is a name and a color. - [Reorder line](https://headhoncho.app/docs/api/reorder_line): Set the order of the statuses on the line, the order every picker offers. Send every status on the line, once each. - [Update agency feed](https://headhoncho.app/docs/api/update_agency_feed): Change how closed jobs reach the agency: the webhook address, the daily file address and hour, or switch the feed on or off. Secrets are not touched. - [Sync callrail](https://headhoncho.app/docs/api/sync_callrail): Pull the company's new CallRail calls and forms now, match them to jobs, and say how many landed. The hourly sync does this on its own. - [Update callrail tracking](https://headhoncho.app/docs/api/update_callrail_tracking): Set the tracking phone numbers on a company's CallRail connection. They replace the list whole. The webhook signing key is set in the app. - [Refresh sources](https://headhoncho.app/docs/api/refresh_sources): Clear the Call center source stamped on a company's jobs, pull all its CallRail history again and re-read every call, so each job's source is worked out afresh. - [Sync ad platform](https://headhoncho.app/docs/api/sync_ad_platform): Pull a company's latest campaigns and spend from one ad platform now. The hourly sync does this on its own. - The same records in the app: [Settings](https://headhoncho.app/docs/settings). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "accepted": true, "position": 88611, "company_id": "cmp_14f5", "name": "Sunrise Moving and Storage" } ``` ### cURL ```bash curl -X POST "https://api.headhoncho.app/api/v1/commands/update-company" \ -H "Authorization: Bearer hh_live_..." \ -H "Idempotency-Key: 6f1d2c9e-1b7a-4c1e-9a52-0d3f8e4b7a10" \ -H "Content-Type: application/json" \ -d '{ "company_id": "cmp_14f5", "name": "Sunrise Moving and Storage", "service_area": "Bloomington and Normal, IL", "time_zone": "America/Chicago", "country": "US", "color": "#2f6fdb", "week_start": 0, "week_end": 6, "business_hours": "[{\"weekday\": 0, \"opens\": \"08:00\", \"closes\": \"17:00\"}]", "service_places": "[{\"city\": \"Bloomington\", \"state\": \"IL\"}]" }' ``` ### Python ```python import requests import uuid response = requests.post( "https://api.headhoncho.app/api/v1/commands/update-company", headers={ "Authorization": "Bearer hh_live_...", "Idempotency-Key": str(uuid.uuid4()), }, json={ "company_id": "cmp_14f5", "name": "Sunrise Moving and Storage", "service_area": "Bloomington and Normal, IL", "time_zone": "America/Chicago", "country": "US", "color": "#2f6fdb", "week_start": 0, "week_end": 6, "business_hours": "[{\"weekday\": 0, \"opens\": \"08:00\", \"closes\": \"17:00\"}]", "service_places": "[{\"city\": \"Bloomington\", \"state\": \"IL\"}]", }, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/commands/update-company", { method: "POST", headers: { Authorization: "Bearer hh_live_...", "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "company_id": "cmp_14f5", "name": "Sunrise Moving and Storage", "service_area": "Bloomington and Normal, IL", "time_zone": "America/Chicago", "country": "US", "color": "#2f6fdb", "week_start": 0, "week_end": 6, "business_hours": "[{\"weekday\": 0, \"opens\": \"08:00\", \"closes\": \"17:00\"}]", "service_places": "[{\"city\": \"Bloomington\", \"state\": \"IL\"}]" }), }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: update_company Arguments: company_id (id, required), name (text, optional), service_area (text, optional), time_zone (text, optional), country (text, optional), color (text, optional), week_start (number, optional), week_end (number, optional), business_hours (text, optional), service_places (text, optional) Access: do on Company settings Hints: readOnly=false, destructive=false, idempotent=true, openWorld=false Try asking: "Using HeadHoncho, update company with company_id cmp_14f5 and name Sunrise Moving and Storage." ``` --- # Create company Create company is a command in the HeadHoncho API. Add another company to the workspace. It starts with the first company's time zone and country unless you send your own. Page: https://headhoncho.app/docs/api/create_company | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **Create company**, HeadHoncho API v1. It is a command, sent to the base address `https://api.headhoncho.app`. `POST /api/v1/commands/create-company` The key needs the **Company settings** area at **do**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). It runs the app's own command `create-company`. Send an `Idempotency-Key` header with every call: the same key with the same body returns the first answer and runs nothing twice. See [the model](https://headhoncho.app/docs/api/model#idempotency). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `name` | text, in the JSON body | Yes | At least 3 characters. A name already in use is refused. | `Capital Roofing` | | `time_zone` | text, in the JSON body | No | An IANA time zone name. Default: the first company's. | `America/New_York` | | `service_area` | text, in the JSON body | No | A sentence about where the company works. | `Springfield, IL` | | `country` | text, in the JSON body | No | Two letters. Default: the first company's. | `US` | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back accepted, company_id, organization_id, name and position. A plan that holds one company refuses the second with plan_limit in fields. It never deletes anything. It changes only what the command names, and it writes the change to the job's history with who asked for it. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `accepted` | true or false | True when the command ran. A command that cannot run is an error instead. | | `position` | whole number | Where the change landed in the event log. Pass it as `after` on a read to see your own write. | | `company_id` | id (text) | The id of the company. | | `organization_id` | id (text) | The id of the organization. | | `name` | text | The name, as the app shows it. | ## The plan counts companies Free runs one company. The app refuses the second with the upgrade answer, and so does this, naming plan_limit. A paid plan is never refused here; an extra company is billing, not a wall. ## Reach The credential must reach every company, and the person it acts as must be an owner or an admin. A key that names no companies reaches the new one at once; a key that names companies does not, and is refused this call. ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`read_only`](https://headhoncho.app/docs/api/errors#read_only) | 403 | This credential may read this area but not change it. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`missing_idempotency_key`](https://headhoncho.app/docs/api/errors#missing_idempotency_key) | 400 | Send an Idempotency-Key header on every command. | | [`idempotency_mismatch`](https://headhoncho.app/docs/api/errors#idempotency_mismatch) | 409 | This Idempotency-Key was used with a different body. | | [`idempotency_in_progress`](https://headhoncho.app/docs/api/errors#idempotency_in_progress) | 409 | A command with this Idempotency-Key is still running. Wait a moment and send it again. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [Update company](https://headhoncho.app/docs/api/update_company): Change one company's own facts: name, service area, time zone, country, color, week, opening hours or service places. Only what you send changes. - [Update organization](https://headhoncho.app/docs/api/update_organization): Rename the workspace. A company still carrying the old workspace name is renamed with it. - [Add job type](https://headhoncho.app/docs/api/add_job_type): Add a kind of work the business does, such as Local move or Roof repair. A name already in use is refused. - [Update job type](https://headhoncho.app/docs/api/update_job_type): Rename a job type, move it in the list, or retire it so new jobs cannot pick it. Old jobs keep it. - [Update job status](https://headhoncho.app/docs/api/update_job_status): Rename a status, change its look, move it in the list, or retire it. A rename shows on every job at once. Its slug and band stay. - [Set status band](https://headhoncho.app/docs/api/set_status_band): Put a status on the line (a step every job passes) or off it as a detour (a place a job gets stuck). The line closes up behind it. - [Replace job status](https://headhoncho.app/docs/api/replace_job_status): Let another status stand in for this one: move its jobs onto the new status, retire the old word, or both. Name an existing status or a new one. - [Add job status](https://headhoncho.app/docs/api/add_job_status): Add a status to the workspace's list, on the line or as a detour. It carries no role: it is a name and a color. - [Reorder line](https://headhoncho.app/docs/api/reorder_line): Set the order of the statuses on the line, the order every picker offers. Send every status on the line, once each. - [Update agency feed](https://headhoncho.app/docs/api/update_agency_feed): Change how closed jobs reach the agency: the webhook address, the daily file address and hour, or switch the feed on or off. Secrets are not touched. - [Sync callrail](https://headhoncho.app/docs/api/sync_callrail): Pull the company's new CallRail calls and forms now, match them to jobs, and say how many landed. The hourly sync does this on its own. - [Update callrail tracking](https://headhoncho.app/docs/api/update_callrail_tracking): Set the tracking phone numbers on a company's CallRail connection. They replace the list whole. The webhook signing key is set in the app. - [Refresh sources](https://headhoncho.app/docs/api/refresh_sources): Clear the Call center source stamped on a company's jobs, pull all its CallRail history again and re-read every call, so each job's source is worked out afresh. - [Sync ad platform](https://headhoncho.app/docs/api/sync_ad_platform): Pull a company's latest campaigns and spend from one ad platform now. The hourly sync does this on its own. - The same records in the app: [Settings](https://headhoncho.app/docs/settings). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "accepted": true, "position": 88611, "company_id": "cmp_8a21", "organization_id": "org_2c7d", "name": "Capital Roofing" } ``` ### cURL ```bash curl -X POST "https://api.headhoncho.app/api/v1/commands/create-company" \ -H "Authorization: Bearer hh_live_..." \ -H "Idempotency-Key: 6f1d2c9e-1b7a-4c1e-9a52-0d3f8e4b7a10" \ -H "Content-Type: application/json" \ -d '{ "name": "Capital Roofing", "time_zone": "America/New_York", "service_area": "Springfield, IL", "country": "US" }' ``` ### Python ```python import requests import uuid response = requests.post( "https://api.headhoncho.app/api/v1/commands/create-company", headers={ "Authorization": "Bearer hh_live_...", "Idempotency-Key": str(uuid.uuid4()), }, json={ "name": "Capital Roofing", "time_zone": "America/New_York", "service_area": "Springfield, IL", "country": "US", }, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/commands/create-company", { method: "POST", headers: { Authorization: "Bearer hh_live_...", "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "name": "Capital Roofing", "time_zone": "America/New_York", "service_area": "Springfield, IL", "country": "US" }), }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: create_company Arguments: name (text, required), time_zone (text, optional), service_area (text, optional), country (text, optional) Access: do on Company settings Hints: readOnly=false, destructive=false, idempotent=false, openWorld=false Try asking: "Using HeadHoncho, create company with name Capital Roofing and time_zone America/New_York." ``` --- # Update organization Update organization is a command in the HeadHoncho API. Rename the workspace. A company still carrying the old workspace name is renamed with it. Page: https://headhoncho.app/docs/api/update_organization | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **Update organization**, HeadHoncho API v1. It is a command, sent to the base address `https://api.headhoncho.app`. `POST /api/v1/commands/update-organization` The key needs the **Company settings** area at **do**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). It runs the app's own command `update-organization`. Send an `Idempotency-Key` header with every call: the same key with the same body returns the first answer and runs nothing twice. See [the model](https://headhoncho.app/docs/api/model#idempotency). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `name` | text, in the JSON body | Yes | At least 3 characters. | `Northwind Ads Group` | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back accepted, organization_id, name and position. It never deletes anything. It changes only what the command names, and it writes the change to the job's history with who asked for it. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `accepted` | true or false | True when the command ran. A command that cannot run is an error instead. | | `position` | whole number | Where the change landed in the event log. Pass it as `after` on a read to see your own write. | | `organization_id` | id (text) | The id of the organization. | | `name` | text | The name, as the app shows it. | ## Owner or admin only Refused with no_access for anyone else, and for a credential that does not reach every company, because the rename can reach them all. ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`read_only`](https://headhoncho.app/docs/api/errors#read_only) | 403 | This credential may read this area but not change it. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`missing_idempotency_key`](https://headhoncho.app/docs/api/errors#missing_idempotency_key) | 400 | Send an Idempotency-Key header on every command. | | [`idempotency_mismatch`](https://headhoncho.app/docs/api/errors#idempotency_mismatch) | 409 | This Idempotency-Key was used with a different body. | | [`idempotency_in_progress`](https://headhoncho.app/docs/api/errors#idempotency_in_progress) | 409 | A command with this Idempotency-Key is still running. Wait a moment and send it again. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [Update company](https://headhoncho.app/docs/api/update_company): Change one company's own facts: name, service area, time zone, country, color, week, opening hours or service places. Only what you send changes. - [Create company](https://headhoncho.app/docs/api/create_company): Add another company to the workspace. It starts with the first company's time zone and country unless you send your own. - [Add job type](https://headhoncho.app/docs/api/add_job_type): Add a kind of work the business does, such as Local move or Roof repair. A name already in use is refused. - [Update job type](https://headhoncho.app/docs/api/update_job_type): Rename a job type, move it in the list, or retire it so new jobs cannot pick it. Old jobs keep it. - [Update job status](https://headhoncho.app/docs/api/update_job_status): Rename a status, change its look, move it in the list, or retire it. A rename shows on every job at once. Its slug and band stay. - [Set status band](https://headhoncho.app/docs/api/set_status_band): Put a status on the line (a step every job passes) or off it as a detour (a place a job gets stuck). The line closes up behind it. - [Replace job status](https://headhoncho.app/docs/api/replace_job_status): Let another status stand in for this one: move its jobs onto the new status, retire the old word, or both. Name an existing status or a new one. - [Add job status](https://headhoncho.app/docs/api/add_job_status): Add a status to the workspace's list, on the line or as a detour. It carries no role: it is a name and a color. - [Reorder line](https://headhoncho.app/docs/api/reorder_line): Set the order of the statuses on the line, the order every picker offers. Send every status on the line, once each. - [Update agency feed](https://headhoncho.app/docs/api/update_agency_feed): Change how closed jobs reach the agency: the webhook address, the daily file address and hour, or switch the feed on or off. Secrets are not touched. - [Sync callrail](https://headhoncho.app/docs/api/sync_callrail): Pull the company's new CallRail calls and forms now, match them to jobs, and say how many landed. The hourly sync does this on its own. - [Update callrail tracking](https://headhoncho.app/docs/api/update_callrail_tracking): Set the tracking phone numbers on a company's CallRail connection. They replace the list whole. The webhook signing key is set in the app. - [Refresh sources](https://headhoncho.app/docs/api/refresh_sources): Clear the Call center source stamped on a company's jobs, pull all its CallRail history again and re-read every call, so each job's source is worked out afresh. - [Sync ad platform](https://headhoncho.app/docs/api/sync_ad_platform): Pull a company's latest campaigns and spend from one ad platform now. The hourly sync does this on its own. - The same records in the app: [Settings](https://headhoncho.app/docs/settings). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "accepted": true, "position": 88611, "organization_id": "org_2c7d", "name": "Northwind Ads Group" } ``` ### cURL ```bash curl -X POST "https://api.headhoncho.app/api/v1/commands/update-organization" \ -H "Authorization: Bearer hh_live_..." \ -H "Idempotency-Key: 6f1d2c9e-1b7a-4c1e-9a52-0d3f8e4b7a10" \ -H "Content-Type: application/json" \ -d '{ "name": "Northwind Ads Group" }' ``` ### Python ```python import requests import uuid response = requests.post( "https://api.headhoncho.app/api/v1/commands/update-organization", headers={ "Authorization": "Bearer hh_live_...", "Idempotency-Key": str(uuid.uuid4()), }, json={ "name": "Northwind Ads Group", }, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/commands/update-organization", { method: "POST", headers: { Authorization: "Bearer hh_live_...", "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "name": "Northwind Ads Group" }), }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: update_organization Arguments: name (text, required) Access: do on Company settings Hints: readOnly=false, destructive=false, idempotent=true, openWorld=false Try asking: "Using HeadHoncho, update organization with name Northwind Ads Group." ``` --- # Add job type Add job type is a command in the HeadHoncho API. Add a kind of work the business does, such as Local move or Roof repair. A name already in use is refused. Page: https://headhoncho.app/docs/api/add_job_type | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **Add job type**, HeadHoncho API v1. It is a command, sent to the base address `https://api.headhoncho.app`. `POST /api/v1/commands/add-job-type` The key needs the **Company settings** area at **do**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). It runs the app's own command `add-job-type`. Send an `Idempotency-Key` header with every call: the same key with the same body returns the first answer and runs nothing twice. See [the model](https://headhoncho.app/docs/api/model#idempotency). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `name` | text, in the JSON body | Yes | What the work is called. | `Packing only` | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back accepted, job_type_id, name and position. It never deletes anything. It changes only what the command names, and it writes the change to the job's history with who asked for it. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `accepted` | true or false | True when the command ran. A command that cannot run is an error instead. | | `position` | whole number | Where the change landed in the event log. Pass it as `after` on a read to see your own write. | | `job_type_id` | id (text) | The id of the job type. | | `name` | text | The name, as the app shows it. | ## Shared A job type belongs to the workspace, so every company can use it. ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`read_only`](https://headhoncho.app/docs/api/errors#read_only) | 403 | This credential may read this area but not change it. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`missing_idempotency_key`](https://headhoncho.app/docs/api/errors#missing_idempotency_key) | 400 | Send an Idempotency-Key header on every command. | | [`idempotency_mismatch`](https://headhoncho.app/docs/api/errors#idempotency_mismatch) | 409 | This Idempotency-Key was used with a different body. | | [`idempotency_in_progress`](https://headhoncho.app/docs/api/errors#idempotency_in_progress) | 409 | A command with this Idempotency-Key is still running. Wait a moment and send it again. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [Update company](https://headhoncho.app/docs/api/update_company): Change one company's own facts: name, service area, time zone, country, color, week, opening hours or service places. Only what you send changes. - [Create company](https://headhoncho.app/docs/api/create_company): Add another company to the workspace. It starts with the first company's time zone and country unless you send your own. - [Update organization](https://headhoncho.app/docs/api/update_organization): Rename the workspace. A company still carrying the old workspace name is renamed with it. - [Update job type](https://headhoncho.app/docs/api/update_job_type): Rename a job type, move it in the list, or retire it so new jobs cannot pick it. Old jobs keep it. - [Update job status](https://headhoncho.app/docs/api/update_job_status): Rename a status, change its look, move it in the list, or retire it. A rename shows on every job at once. Its slug and band stay. - [Set status band](https://headhoncho.app/docs/api/set_status_band): Put a status on the line (a step every job passes) or off it as a detour (a place a job gets stuck). The line closes up behind it. - [Replace job status](https://headhoncho.app/docs/api/replace_job_status): Let another status stand in for this one: move its jobs onto the new status, retire the old word, or both. Name an existing status or a new one. - [Add job status](https://headhoncho.app/docs/api/add_job_status): Add a status to the workspace's list, on the line or as a detour. It carries no role: it is a name and a color. - [Reorder line](https://headhoncho.app/docs/api/reorder_line): Set the order of the statuses on the line, the order every picker offers. Send every status on the line, once each. - [Update agency feed](https://headhoncho.app/docs/api/update_agency_feed): Change how closed jobs reach the agency: the webhook address, the daily file address and hour, or switch the feed on or off. Secrets are not touched. - [Sync callrail](https://headhoncho.app/docs/api/sync_callrail): Pull the company's new CallRail calls and forms now, match them to jobs, and say how many landed. The hourly sync does this on its own. - [Update callrail tracking](https://headhoncho.app/docs/api/update_callrail_tracking): Set the tracking phone numbers on a company's CallRail connection. They replace the list whole. The webhook signing key is set in the app. - [Refresh sources](https://headhoncho.app/docs/api/refresh_sources): Clear the Call center source stamped on a company's jobs, pull all its CallRail history again and re-read every call, so each job's source is worked out afresh. - [Sync ad platform](https://headhoncho.app/docs/api/sync_ad_platform): Pull a company's latest campaigns and spend from one ad platform now. The hourly sync does this on its own. - The same records in the app: [Settings](https://headhoncho.app/docs/settings). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "accepted": true, "position": 88611, "job_type_id": "jt_05", "name": "Packing only" } ``` ### cURL ```bash curl -X POST "https://api.headhoncho.app/api/v1/commands/add-job-type" \ -H "Authorization: Bearer hh_live_..." \ -H "Idempotency-Key: 6f1d2c9e-1b7a-4c1e-9a52-0d3f8e4b7a10" \ -H "Content-Type: application/json" \ -d '{ "name": "Packing only" }' ``` ### Python ```python import requests import uuid response = requests.post( "https://api.headhoncho.app/api/v1/commands/add-job-type", headers={ "Authorization": "Bearer hh_live_...", "Idempotency-Key": str(uuid.uuid4()), }, json={ "name": "Packing only", }, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/commands/add-job-type", { method: "POST", headers: { Authorization: "Bearer hh_live_...", "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "name": "Packing only" }), }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: add_job_type Arguments: name (text, required) Access: do on Company settings Hints: readOnly=false, destructive=false, idempotent=false, openWorld=false Try asking: "Using HeadHoncho, add job type with name Packing only." ``` --- # Update job type Update job type is a command in the HeadHoncho API. Rename a job type, move it in the list, or retire it so new jobs cannot pick it. Old jobs keep it. Page: https://headhoncho.app/docs/api/update_job_type | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **Update job type**, HeadHoncho API v1. It is a command, sent to the base address `https://api.headhoncho.app`. `POST /api/v1/commands/update-job-type` The key needs the **Company settings** area at **do**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). It runs the app's own command `update-job-type`. Send an `Idempotency-Key` header with every call: the same key with the same body returns the first answer and runs nothing twice. See [the model](https://headhoncho.app/docs/api/model#idempotency). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `job_type_id` | id, in the JSON body | Yes | From Who am I or Company settings. | `jt_05` | | `name` | text, in the JSON body | No | The new name. | `Packing and unpacking` | | `position` | number, in the JSON body | No | Where it sits in the list, 0 first. | `1` | | `archived` | boolean, in the JSON body | No | true retires it, false brings it back. | `false` | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back accepted, job_type_id, name and position. It never deletes anything. It changes only what the command names, and it writes the change to the job's history with who asked for it. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `accepted` | true or false | True when the command ran. A command that cannot run is an error instead. | | `position` | whole number | Where the change landed in the event log. Pass it as `after` on a read to see your own write. | | `job_type_id` | id (text) | The id of the job type. | | `name` | text | The name, as the app shows it. | ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`read_only`](https://headhoncho.app/docs/api/errors#read_only) | 403 | This credential may read this area but not change it. | | [`not_found`](https://headhoncho.app/docs/api/errors#not_found) | 404 | No such record in the companies this credential reaches. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`missing_idempotency_key`](https://headhoncho.app/docs/api/errors#missing_idempotency_key) | 400 | Send an Idempotency-Key header on every command. | | [`idempotency_mismatch`](https://headhoncho.app/docs/api/errors#idempotency_mismatch) | 409 | This Idempotency-Key was used with a different body. | | [`idempotency_in_progress`](https://headhoncho.app/docs/api/errors#idempotency_in_progress) | 409 | A command with this Idempotency-Key is still running. Wait a moment and send it again. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [Update company](https://headhoncho.app/docs/api/update_company): Change one company's own facts: name, service area, time zone, country, color, week, opening hours or service places. Only what you send changes. - [Create company](https://headhoncho.app/docs/api/create_company): Add another company to the workspace. It starts with the first company's time zone and country unless you send your own. - [Update organization](https://headhoncho.app/docs/api/update_organization): Rename the workspace. A company still carrying the old workspace name is renamed with it. - [Add job type](https://headhoncho.app/docs/api/add_job_type): Add a kind of work the business does, such as Local move or Roof repair. A name already in use is refused. - [Update job status](https://headhoncho.app/docs/api/update_job_status): Rename a status, change its look, move it in the list, or retire it. A rename shows on every job at once. Its slug and band stay. - [Set status band](https://headhoncho.app/docs/api/set_status_band): Put a status on the line (a step every job passes) or off it as a detour (a place a job gets stuck). The line closes up behind it. - [Replace job status](https://headhoncho.app/docs/api/replace_job_status): Let another status stand in for this one: move its jobs onto the new status, retire the old word, or both. Name an existing status or a new one. - [Add job status](https://headhoncho.app/docs/api/add_job_status): Add a status to the workspace's list, on the line or as a detour. It carries no role: it is a name and a color. - [Reorder line](https://headhoncho.app/docs/api/reorder_line): Set the order of the statuses on the line, the order every picker offers. Send every status on the line, once each. - [Update agency feed](https://headhoncho.app/docs/api/update_agency_feed): Change how closed jobs reach the agency: the webhook address, the daily file address and hour, or switch the feed on or off. Secrets are not touched. - [Sync callrail](https://headhoncho.app/docs/api/sync_callrail): Pull the company's new CallRail calls and forms now, match them to jobs, and say how many landed. The hourly sync does this on its own. - [Update callrail tracking](https://headhoncho.app/docs/api/update_callrail_tracking): Set the tracking phone numbers on a company's CallRail connection. They replace the list whole. The webhook signing key is set in the app. - [Refresh sources](https://headhoncho.app/docs/api/refresh_sources): Clear the Call center source stamped on a company's jobs, pull all its CallRail history again and re-read every call, so each job's source is worked out afresh. - [Sync ad platform](https://headhoncho.app/docs/api/sync_ad_platform): Pull a company's latest campaigns and spend from one ad platform now. The hourly sync does this on its own. - The same records in the app: [Settings](https://headhoncho.app/docs/settings). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "accepted": true, "position": 88611, "job_type_id": "jt_05", "name": "Packing and unpacking" } ``` ### cURL ```bash curl -X POST "https://api.headhoncho.app/api/v1/commands/update-job-type" \ -H "Authorization: Bearer hh_live_..." \ -H "Idempotency-Key: 6f1d2c9e-1b7a-4c1e-9a52-0d3f8e4b7a10" \ -H "Content-Type: application/json" \ -d '{ "job_type_id": "jt_05", "name": "Packing and unpacking", "position": 1, "archived": false }' ``` ### Python ```python import requests import uuid response = requests.post( "https://api.headhoncho.app/api/v1/commands/update-job-type", headers={ "Authorization": "Bearer hh_live_...", "Idempotency-Key": str(uuid.uuid4()), }, json={ "job_type_id": "jt_05", "name": "Packing and unpacking", "position": 1, "archived": False, }, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/commands/update-job-type", { method: "POST", headers: { Authorization: "Bearer hh_live_...", "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "job_type_id": "jt_05", "name": "Packing and unpacking", "position": 1, "archived": false }), }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: update_job_type Arguments: job_type_id (id, required), name (text, optional), position (number, optional), archived (boolean, optional) Access: do on Company settings Hints: readOnly=false, destructive=false, idempotent=true, openWorld=false Try asking: "Using HeadHoncho, update job type with job_type_id jt_05 and name Packing and unpacking." ``` --- # Update job status Update job status is a command in the HeadHoncho API. Rename a status, change its look, move it in the list, or retire it. A rename shows on every job at once. Its slug and band stay. Page: https://headhoncho.app/docs/api/update_job_status | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **Update job status**, HeadHoncho API v1. It is a command, sent to the base address `https://api.headhoncho.app`. `POST /api/v1/commands/update-job-status` The key needs the **Company settings** area at **do**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). It runs the app's own command `update-job-status`. Send an `Idempotency-Key` header with every call: the same key with the same body returns the first answer and runs nothing twice. See [the model](https://headhoncho.app/docs/api/model#idempotency). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `status` | text, in the JSON body | Yes | The status: its id, its slug or its name, from Who am I or Company settings. | `waiting` | | `name` | text, in the JSON body | No | The new name. It shows on every job that has this status. | `On hold` | | `tone` | text, in the JSON body | No | The pill's tone. One of `neutral`, `info`, `good`, `warn`, `bad`. | `warn` | | `color` | text, in the JSON body | No | The fill as #rrggbb. Empty uses the tone's. | `#f2c94c` | | `ink` | text, in the JSON body | No | The text color as #rrggbb. Empty uses the tone's. | `#3a2f00` | | `icon` | text, in the JSON body | No | A mark from Company settings' status_icons. Empty for none. | `pause` | | `position` | number, in the JSON body | No | Its place in the list, 0 first. | `7` | | `archived` | boolean, in the JSON body | No | true retires it, false brings it back. A status that carries a role (draft, closed and so on) must hand the role on first. | `false` | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back accepted, job_status_id, name and position. It never deletes anything. It changes only what the command names, and it writes the change to the job's history with who asked for it. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `accepted` | true or false | True when the command ran. A command that cannot run is an error instead. | | `position` | whole number | Where the change landed in the event log. Pass it as `after` on a read to see your own write. | | `job_status_id` | id (text) | The id of the job status. | | `name` | text | The name, as the app shows it. | ## To move it between the line and the detours Use Move a status to a band. To change the order of the whole line at once, use Reorder the line. ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`read_only`](https://headhoncho.app/docs/api/errors#read_only) | 403 | This credential may read this area but not change it. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`missing_idempotency_key`](https://headhoncho.app/docs/api/errors#missing_idempotency_key) | 400 | Send an Idempotency-Key header on every command. | | [`idempotency_mismatch`](https://headhoncho.app/docs/api/errors#idempotency_mismatch) | 409 | This Idempotency-Key was used with a different body. | | [`idempotency_in_progress`](https://headhoncho.app/docs/api/errors#idempotency_in_progress) | 409 | A command with this Idempotency-Key is still running. Wait a moment and send it again. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [Update company](https://headhoncho.app/docs/api/update_company): Change one company's own facts: name, service area, time zone, country, color, week, opening hours or service places. Only what you send changes. - [Create company](https://headhoncho.app/docs/api/create_company): Add another company to the workspace. It starts with the first company's time zone and country unless you send your own. - [Update organization](https://headhoncho.app/docs/api/update_organization): Rename the workspace. A company still carrying the old workspace name is renamed with it. - [Add job type](https://headhoncho.app/docs/api/add_job_type): Add a kind of work the business does, such as Local move or Roof repair. A name already in use is refused. - [Update job type](https://headhoncho.app/docs/api/update_job_type): Rename a job type, move it in the list, or retire it so new jobs cannot pick it. Old jobs keep it. - [Set status band](https://headhoncho.app/docs/api/set_status_band): Put a status on the line (a step every job passes) or off it as a detour (a place a job gets stuck). The line closes up behind it. - [Replace job status](https://headhoncho.app/docs/api/replace_job_status): Let another status stand in for this one: move its jobs onto the new status, retire the old word, or both. Name an existing status or a new one. - [Add job status](https://headhoncho.app/docs/api/add_job_status): Add a status to the workspace's list, on the line or as a detour. It carries no role: it is a name and a color. - [Reorder line](https://headhoncho.app/docs/api/reorder_line): Set the order of the statuses on the line, the order every picker offers. Send every status on the line, once each. - [Update agency feed](https://headhoncho.app/docs/api/update_agency_feed): Change how closed jobs reach the agency: the webhook address, the daily file address and hour, or switch the feed on or off. Secrets are not touched. - [Sync callrail](https://headhoncho.app/docs/api/sync_callrail): Pull the company's new CallRail calls and forms now, match them to jobs, and say how many landed. The hourly sync does this on its own. - [Update callrail tracking](https://headhoncho.app/docs/api/update_callrail_tracking): Set the tracking phone numbers on a company's CallRail connection. They replace the list whole. The webhook signing key is set in the app. - [Refresh sources](https://headhoncho.app/docs/api/refresh_sources): Clear the Call center source stamped on a company's jobs, pull all its CallRail history again and re-read every call, so each job's source is worked out afresh. - [Sync ad platform](https://headhoncho.app/docs/api/sync_ad_platform): Pull a company's latest campaigns and spend from one ad platform now. The hourly sync does this on its own. - The same records in the app: [Settings](https://headhoncho.app/docs/settings). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "accepted": true, "position": 88611, "job_status_id": "st_09", "name": "On hold" } ``` ### cURL ```bash curl -X POST "https://api.headhoncho.app/api/v1/commands/update-job-status" \ -H "Authorization: Bearer hh_live_..." \ -H "Idempotency-Key: 6f1d2c9e-1b7a-4c1e-9a52-0d3f8e4b7a10" \ -H "Content-Type: application/json" \ -d '{ "status": "waiting", "name": "On hold", "tone": "warn", "color": "#f2c94c", "ink": "#3a2f00", "icon": "pause", "position": 7, "archived": false }' ``` ### Python ```python import requests import uuid response = requests.post( "https://api.headhoncho.app/api/v1/commands/update-job-status", headers={ "Authorization": "Bearer hh_live_...", "Idempotency-Key": str(uuid.uuid4()), }, json={ "status": "waiting", "name": "On hold", "tone": "warn", "color": "#f2c94c", "ink": "#3a2f00", "icon": "pause", "position": 7, "archived": False, }, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/commands/update-job-status", { method: "POST", headers: { Authorization: "Bearer hh_live_...", "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "status": "waiting", "name": "On hold", "tone": "warn", "color": "#f2c94c", "ink": "#3a2f00", "icon": "pause", "position": 7, "archived": false }), }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: update_job_status Arguments: status (text, required), name (text, optional), tone (text, optional), color (text, optional), ink (text, optional), icon (text, optional), position (number, optional), archived (boolean, optional) Access: do on Company settings Hints: readOnly=false, destructive=false, idempotent=true, openWorld=false Try asking: "Using HeadHoncho, update job status with status waiting and name On hold." ``` --- # Set status band Set status band is a command in the HeadHoncho API. Put a status on the line (a step every job passes) or off it as a detour (a place a job gets stuck). The line closes up behind it. Page: https://headhoncho.app/docs/api/set_status_band | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **Set status band**, HeadHoncho API v1. It is a command, sent to the base address `https://api.headhoncho.app`. `POST /api/v1/commands/set-status-band` The key needs the **Company settings** area at **do**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). It runs the app's own command `set-status-band`. Send an `Idempotency-Key` header with every call: the same key with the same body returns the first answer and runs nothing twice. See [the model](https://headhoncho.app/docs/api/model#idempotency). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `status` | text, in the JSON body | Yes | The status: its id, its slug or its name, from Who am I or Company settings. | `waiting` | | `band` | text, in the JSON body | Yes | line or detour. One of `line`, `detour`. | `detour` | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back accepted, status_id, band and position. unchanged is true when it was already there. The statuses that intake, dispatch or finance land a job on stay on the line and are refused. It never deletes anything. It changes only what the command names, and it writes the change to the job's history with who asked for it. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `accepted` | true or false | True when the command ran. A command that cannot run is an error instead. | | `position` | whole number | Where the change landed in the event log. Pass it as `after` on a read to see your own write. | | `status_id` | id (text) | The id of the status. | | `band` | text | One of `line`, `detour`. | ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`read_only`](https://headhoncho.app/docs/api/errors#read_only) | 403 | This credential may read this area but not change it. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`missing_idempotency_key`](https://headhoncho.app/docs/api/errors#missing_idempotency_key) | 400 | Send an Idempotency-Key header on every command. | | [`idempotency_mismatch`](https://headhoncho.app/docs/api/errors#idempotency_mismatch) | 409 | This Idempotency-Key was used with a different body. | | [`idempotency_in_progress`](https://headhoncho.app/docs/api/errors#idempotency_in_progress) | 409 | A command with this Idempotency-Key is still running. Wait a moment and send it again. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [Update company](https://headhoncho.app/docs/api/update_company): Change one company's own facts: name, service area, time zone, country, color, week, opening hours or service places. Only what you send changes. - [Create company](https://headhoncho.app/docs/api/create_company): Add another company to the workspace. It starts with the first company's time zone and country unless you send your own. - [Update organization](https://headhoncho.app/docs/api/update_organization): Rename the workspace. A company still carrying the old workspace name is renamed with it. - [Add job type](https://headhoncho.app/docs/api/add_job_type): Add a kind of work the business does, such as Local move or Roof repair. A name already in use is refused. - [Update job type](https://headhoncho.app/docs/api/update_job_type): Rename a job type, move it in the list, or retire it so new jobs cannot pick it. Old jobs keep it. - [Update job status](https://headhoncho.app/docs/api/update_job_status): Rename a status, change its look, move it in the list, or retire it. A rename shows on every job at once. Its slug and band stay. - [Replace job status](https://headhoncho.app/docs/api/replace_job_status): Let another status stand in for this one: move its jobs onto the new status, retire the old word, or both. Name an existing status or a new one. - [Add job status](https://headhoncho.app/docs/api/add_job_status): Add a status to the workspace's list, on the line or as a detour. It carries no role: it is a name and a color. - [Reorder line](https://headhoncho.app/docs/api/reorder_line): Set the order of the statuses on the line, the order every picker offers. Send every status on the line, once each. - [Update agency feed](https://headhoncho.app/docs/api/update_agency_feed): Change how closed jobs reach the agency: the webhook address, the daily file address and hour, or switch the feed on or off. Secrets are not touched. - [Sync callrail](https://headhoncho.app/docs/api/sync_callrail): Pull the company's new CallRail calls and forms now, match them to jobs, and say how many landed. The hourly sync does this on its own. - [Update callrail tracking](https://headhoncho.app/docs/api/update_callrail_tracking): Set the tracking phone numbers on a company's CallRail connection. They replace the list whole. The webhook signing key is set in the app. - [Refresh sources](https://headhoncho.app/docs/api/refresh_sources): Clear the Call center source stamped on a company's jobs, pull all its CallRail history again and re-read every call, so each job's source is worked out afresh. - [Sync ad platform](https://headhoncho.app/docs/api/sync_ad_platform): Pull a company's latest campaigns and spend from one ad platform now. The hourly sync does this on its own. - The same records in the app: [Settings](https://headhoncho.app/docs/settings). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "accepted": true, "position": 88611, "status_id": "st_09", "band": "detour" } ``` ### cURL ```bash curl -X POST "https://api.headhoncho.app/api/v1/commands/set-status-band" \ -H "Authorization: Bearer hh_live_..." \ -H "Idempotency-Key: 6f1d2c9e-1b7a-4c1e-9a52-0d3f8e4b7a10" \ -H "Content-Type: application/json" \ -d '{ "status": "waiting", "band": "detour" }' ``` ### Python ```python import requests import uuid response = requests.post( "https://api.headhoncho.app/api/v1/commands/set-status-band", headers={ "Authorization": "Bearer hh_live_...", "Idempotency-Key": str(uuid.uuid4()), }, json={ "status": "waiting", "band": "detour", }, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/commands/set-status-band", { method: "POST", headers: { Authorization: "Bearer hh_live_...", "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "status": "waiting", "band": "detour" }), }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: set_status_band Arguments: status (text, required), band (text, required) Access: do on Company settings Hints: readOnly=false, destructive=false, idempotent=true, openWorld=false Try asking: "Using HeadHoncho, set status band with status waiting and band detour." ``` --- # Replace job status Replace job status is a command in the HeadHoncho API. Let another status stand in for this one: move its jobs onto the new status, retire the old word, or both. Name an existing status or a new one. Page: https://headhoncho.app/docs/api/replace_job_status | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **Replace job status**, HeadHoncho API v1. It is a command, sent to the base address `https://api.headhoncho.app`. `POST /api/v1/commands/replace-job-status` The key needs the **Company settings** area at **do**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). It runs the app's own command `replace-job-status`. Send an `Idempotency-Key` header with every call: the same key with the same body returns the first answer and runs nothing twice. See [the model](https://headhoncho.app/docs/api/model#idempotency). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `status` | text, in the JSON body | Yes | The status: its id, its slug or its name, from Who am I or Company settings. | `waiting` | | `into_status` | text, in the JSON body | No | An existing status to take its place: id, slug or name. Leave out when you send new_name. | `scheduled` | | `new_name` | text, in the JSON body | No | A new status to create in its place. Leave out when you send into_status. | `On hold` | | `new_color` | text, in the JSON body | No | The new status's fill as #rrggbb. Default: the old one's. | None | | `new_ink` | text, in the JSON body | No | The new status's text color as #rrggbb. Default: the old one's. | None | | `move_jobs` | boolean, in the JSON body | No | true (default) moves every job on the old status to the new one. | `true` | | `retire_old` | boolean, in the JSON body | No | true (default) retires the old status so nothing can pick it. Old jobs not moved keep its name. | `true` | | `take_place` | boolean, in the JSON body | No | true puts an existing status in the old one's place on the line. A new status always takes it. | `false` | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back accepted, status_id (the old one), into_status_id, into_name, created (whether a new status was made), moved (how many jobs changed status) and retired, and position. It never deletes anything. It changes only what the command names, and it writes the change to the job's history with who asked for it. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `accepted` | true or false | True when the command ran. A command that cannot run is an error instead. | | `position` | whole number | Where the change landed in the event log. Pass it as `after` on a read to see your own write. | | `status_id` | id (text) | The id of the status. | | `into_status_id` | id (text) | The id of the into status. | | `into_name` | text | The into name. | | `created` | true or false | The created. | | `moved` | whole number | The moved. | | `retired` | true or false | The retired. | ## What it does to jobs With move_jobs true, every job on the old status in every company moves to the new one, and each move lands in that job's history. A job that is closed or canceled travels with the role. With move_jobs false the jobs keep the old name. Sending neither move_jobs nor retire_old as true is refused, because nothing would happen. ## Reach The credential must reach every company, because the jobs of all of them move. ## Roles A status that carries a role (draft, closed, canceled and so on) hands the role to the one taking its place. ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`read_only`](https://headhoncho.app/docs/api/errors#read_only) | 403 | This credential may read this area but not change it. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`missing_idempotency_key`](https://headhoncho.app/docs/api/errors#missing_idempotency_key) | 400 | Send an Idempotency-Key header on every command. | | [`idempotency_mismatch`](https://headhoncho.app/docs/api/errors#idempotency_mismatch) | 409 | This Idempotency-Key was used with a different body. | | [`idempotency_in_progress`](https://headhoncho.app/docs/api/errors#idempotency_in_progress) | 409 | A command with this Idempotency-Key is still running. Wait a moment and send it again. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [Update company](https://headhoncho.app/docs/api/update_company): Change one company's own facts: name, service area, time zone, country, color, week, opening hours or service places. Only what you send changes. - [Create company](https://headhoncho.app/docs/api/create_company): Add another company to the workspace. It starts with the first company's time zone and country unless you send your own. - [Update organization](https://headhoncho.app/docs/api/update_organization): Rename the workspace. A company still carrying the old workspace name is renamed with it. - [Add job type](https://headhoncho.app/docs/api/add_job_type): Add a kind of work the business does, such as Local move or Roof repair. A name already in use is refused. - [Update job type](https://headhoncho.app/docs/api/update_job_type): Rename a job type, move it in the list, or retire it so new jobs cannot pick it. Old jobs keep it. - [Update job status](https://headhoncho.app/docs/api/update_job_status): Rename a status, change its look, move it in the list, or retire it. A rename shows on every job at once. Its slug and band stay. - [Set status band](https://headhoncho.app/docs/api/set_status_band): Put a status on the line (a step every job passes) or off it as a detour (a place a job gets stuck). The line closes up behind it. - [Add job status](https://headhoncho.app/docs/api/add_job_status): Add a status to the workspace's list, on the line or as a detour. It carries no role: it is a name and a color. - [Reorder line](https://headhoncho.app/docs/api/reorder_line): Set the order of the statuses on the line, the order every picker offers. Send every status on the line, once each. - [Update agency feed](https://headhoncho.app/docs/api/update_agency_feed): Change how closed jobs reach the agency: the webhook address, the daily file address and hour, or switch the feed on or off. Secrets are not touched. - [Sync callrail](https://headhoncho.app/docs/api/sync_callrail): Pull the company's new CallRail calls and forms now, match them to jobs, and say how many landed. The hourly sync does this on its own. - [Update callrail tracking](https://headhoncho.app/docs/api/update_callrail_tracking): Set the tracking phone numbers on a company's CallRail connection. They replace the list whole. The webhook signing key is set in the app. - [Refresh sources](https://headhoncho.app/docs/api/refresh_sources): Clear the Call center source stamped on a company's jobs, pull all its CallRail history again and re-read every call, so each job's source is worked out afresh. - [Sync ad platform](https://headhoncho.app/docs/api/sync_ad_platform): Pull a company's latest campaigns and spend from one ad platform now. The hourly sync does this on its own. - The same records in the app: [Settings](https://headhoncho.app/docs/settings). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "accepted": true, "position": 88611, "status_id": "st_09", "into_status_id": "st_12", "into_name": "On hold", "created": true, "moved": 4, "retired": true } ``` ### cURL ```bash curl -X POST "https://api.headhoncho.app/api/v1/commands/replace-job-status" \ -H "Authorization: Bearer hh_live_..." \ -H "Idempotency-Key: 6f1d2c9e-1b7a-4c1e-9a52-0d3f8e4b7a10" \ -H "Content-Type: application/json" \ -d '{ "status": "waiting", "into_status": "scheduled", "new_name": "On hold", "move_jobs": true, "retire_old": true, "take_place": false }' ``` ### Python ```python import requests import uuid response = requests.post( "https://api.headhoncho.app/api/v1/commands/replace-job-status", headers={ "Authorization": "Bearer hh_live_...", "Idempotency-Key": str(uuid.uuid4()), }, json={ "status": "waiting", "into_status": "scheduled", "new_name": "On hold", "move_jobs": True, "retire_old": True, "take_place": False, }, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/commands/replace-job-status", { method: "POST", headers: { Authorization: "Bearer hh_live_...", "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "status": "waiting", "into_status": "scheduled", "new_name": "On hold", "move_jobs": true, "retire_old": true, "take_place": false }), }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: replace_job_status Arguments: status (text, required), into_status (text, optional), new_name (text, optional), new_color (text, optional), new_ink (text, optional), move_jobs (boolean, optional), retire_old (boolean, optional), take_place (boolean, optional) Access: do on Company settings Hints: readOnly=false, destructive=true, idempotent=false, openWorld=false Try asking: "Using HeadHoncho, replace job status with status waiting and into_status scheduled." ``` --- # Add job status Add job status is a command in the HeadHoncho API. Add a status to the workspace's list, on the line or as a detour. It carries no role: it is a name and a color. Page: https://headhoncho.app/docs/api/add_job_status | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **Add job status**, HeadHoncho API v1. It is a command, sent to the base address `https://api.headhoncho.app`. `POST /api/v1/commands/add-job-status` The key needs the **Company settings** area at **do**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). It runs the app's own command `add-job-status`. Send an `Idempotency-Key` header with every call: the same key with the same body returns the first answer and runs nothing twice. See [the model](https://headhoncho.app/docs/api/model#idempotency). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `name` | text, in the JSON body | Yes | What the status is called. A name already in use is refused. | `Waiting on parts` | | `band` | text, in the JSON body | No | line (default) or detour. One of `line`, `detour`. | `detour` | | `tone` | text, in the JSON body | No | The pill's tone. Default neutral. One of `neutral`, `info`, `good`, `warn`, `bad`. | `warn` | | `color` | text, in the JSON body | No | The fill as #rrggbb. Default: the tone's. | `#f2c94c` | | `ink` | text, in the JSON body | No | The text color as #rrggbb. Default: the tone's. | `#3a2f00` | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back accepted, job_status_id, name and position. It never deletes anything. It changes only what the command names, and it writes the change to the job's history with who asked for it. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `accepted` | true or false | True when the command ran. A command that cannot run is an error instead. | | `position` | whole number | Where the change landed in the event log. Pass it as `after` on a read to see your own write. | | `job_status_id` | id (text) | The id of the job status. | | `name` | text | The name, as the app shows it. | ## Shared A status belongs to the workspace, so every company can use it. ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`read_only`](https://headhoncho.app/docs/api/errors#read_only) | 403 | This credential may read this area but not change it. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`missing_idempotency_key`](https://headhoncho.app/docs/api/errors#missing_idempotency_key) | 400 | Send an Idempotency-Key header on every command. | | [`idempotency_mismatch`](https://headhoncho.app/docs/api/errors#idempotency_mismatch) | 409 | This Idempotency-Key was used with a different body. | | [`idempotency_in_progress`](https://headhoncho.app/docs/api/errors#idempotency_in_progress) | 409 | A command with this Idempotency-Key is still running. Wait a moment and send it again. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [Update company](https://headhoncho.app/docs/api/update_company): Change one company's own facts: name, service area, time zone, country, color, week, opening hours or service places. Only what you send changes. - [Create company](https://headhoncho.app/docs/api/create_company): Add another company to the workspace. It starts with the first company's time zone and country unless you send your own. - [Update organization](https://headhoncho.app/docs/api/update_organization): Rename the workspace. A company still carrying the old workspace name is renamed with it. - [Add job type](https://headhoncho.app/docs/api/add_job_type): Add a kind of work the business does, such as Local move or Roof repair. A name already in use is refused. - [Update job type](https://headhoncho.app/docs/api/update_job_type): Rename a job type, move it in the list, or retire it so new jobs cannot pick it. Old jobs keep it. - [Update job status](https://headhoncho.app/docs/api/update_job_status): Rename a status, change its look, move it in the list, or retire it. A rename shows on every job at once. Its slug and band stay. - [Set status band](https://headhoncho.app/docs/api/set_status_band): Put a status on the line (a step every job passes) or off it as a detour (a place a job gets stuck). The line closes up behind it. - [Replace job status](https://headhoncho.app/docs/api/replace_job_status): Let another status stand in for this one: move its jobs onto the new status, retire the old word, or both. Name an existing status or a new one. - [Reorder line](https://headhoncho.app/docs/api/reorder_line): Set the order of the statuses on the line, the order every picker offers. Send every status on the line, once each. - [Update agency feed](https://headhoncho.app/docs/api/update_agency_feed): Change how closed jobs reach the agency: the webhook address, the daily file address and hour, or switch the feed on or off. Secrets are not touched. - [Sync callrail](https://headhoncho.app/docs/api/sync_callrail): Pull the company's new CallRail calls and forms now, match them to jobs, and say how many landed. The hourly sync does this on its own. - [Update callrail tracking](https://headhoncho.app/docs/api/update_callrail_tracking): Set the tracking phone numbers on a company's CallRail connection. They replace the list whole. The webhook signing key is set in the app. - [Refresh sources](https://headhoncho.app/docs/api/refresh_sources): Clear the Call center source stamped on a company's jobs, pull all its CallRail history again and re-read every call, so each job's source is worked out afresh. - [Sync ad platform](https://headhoncho.app/docs/api/sync_ad_platform): Pull a company's latest campaigns and spend from one ad platform now. The hourly sync does this on its own. - The same records in the app: [Settings](https://headhoncho.app/docs/settings). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "accepted": true, "position": 88611, "job_status_id": "st_12", "name": "Waiting on parts" } ``` ### cURL ```bash curl -X POST "https://api.headhoncho.app/api/v1/commands/add-job-status" \ -H "Authorization: Bearer hh_live_..." \ -H "Idempotency-Key: 6f1d2c9e-1b7a-4c1e-9a52-0d3f8e4b7a10" \ -H "Content-Type: application/json" \ -d '{ "name": "Waiting on parts", "band": "detour", "tone": "warn", "color": "#f2c94c", "ink": "#3a2f00" }' ``` ### Python ```python import requests import uuid response = requests.post( "https://api.headhoncho.app/api/v1/commands/add-job-status", headers={ "Authorization": "Bearer hh_live_...", "Idempotency-Key": str(uuid.uuid4()), }, json={ "name": "Waiting on parts", "band": "detour", "tone": "warn", "color": "#f2c94c", "ink": "#3a2f00", }, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/commands/add-job-status", { method: "POST", headers: { Authorization: "Bearer hh_live_...", "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "name": "Waiting on parts", "band": "detour", "tone": "warn", "color": "#f2c94c", "ink": "#3a2f00" }), }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: add_job_status Arguments: name (text, required), band (text, optional), tone (text, optional), color (text, optional), ink (text, optional) Access: do on Company settings Hints: readOnly=false, destructive=false, idempotent=false, openWorld=false Try asking: "Using HeadHoncho, add job status with name Waiting on parts and band detour." ``` --- # Reorder line Reorder line is a command in the HeadHoncho API. Set the order of the statuses on the line, the order every picker offers. Send every status on the line, once each. Page: https://headhoncho.app/docs/api/reorder_line | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **Reorder line**, HeadHoncho API v1. It is a command, sent to the base address `https://api.headhoncho.app`. `POST /api/v1/commands/reorder-line` The key needs the **Company settings** area at **do**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). It runs the app's own command `reorder-line`. Send an `Idempotency-Key` header with every call: the same key with the same body returns the first answer and runs nothing twice. See [the model](https://headhoncho.app/docs/api/model#idempotency). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `status_ids` | text, in the JSON body | Yes | Every status on the line, in the new order, as a JSON list of ids, slugs or names. Nothing added, nothing left out. Company settings shows the line. | `["st_01", "st_02", "st_03", "st_06"]` | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back accepted, status_ids (the line in its new order) and position. It never deletes anything. It changes only what the command names, and it writes the change to the job's history with who asked for it. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `accepted` | true or false | True when the command ran. A command that cannot run is an error instead. | | `position` | whole number | Where the change landed in the event log. Pass it as `after` on a read to see your own write. | | `status_ids` | list of text | The status ids. | ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`read_only`](https://headhoncho.app/docs/api/errors#read_only) | 403 | This credential may read this area but not change it. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`missing_idempotency_key`](https://headhoncho.app/docs/api/errors#missing_idempotency_key) | 400 | Send an Idempotency-Key header on every command. | | [`idempotency_mismatch`](https://headhoncho.app/docs/api/errors#idempotency_mismatch) | 409 | This Idempotency-Key was used with a different body. | | [`idempotency_in_progress`](https://headhoncho.app/docs/api/errors#idempotency_in_progress) | 409 | A command with this Idempotency-Key is still running. Wait a moment and send it again. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [Update company](https://headhoncho.app/docs/api/update_company): Change one company's own facts: name, service area, time zone, country, color, week, opening hours or service places. Only what you send changes. - [Create company](https://headhoncho.app/docs/api/create_company): Add another company to the workspace. It starts with the first company's time zone and country unless you send your own. - [Update organization](https://headhoncho.app/docs/api/update_organization): Rename the workspace. A company still carrying the old workspace name is renamed with it. - [Add job type](https://headhoncho.app/docs/api/add_job_type): Add a kind of work the business does, such as Local move or Roof repair. A name already in use is refused. - [Update job type](https://headhoncho.app/docs/api/update_job_type): Rename a job type, move it in the list, or retire it so new jobs cannot pick it. Old jobs keep it. - [Update job status](https://headhoncho.app/docs/api/update_job_status): Rename a status, change its look, move it in the list, or retire it. A rename shows on every job at once. Its slug and band stay. - [Set status band](https://headhoncho.app/docs/api/set_status_band): Put a status on the line (a step every job passes) or off it as a detour (a place a job gets stuck). The line closes up behind it. - [Replace job status](https://headhoncho.app/docs/api/replace_job_status): Let another status stand in for this one: move its jobs onto the new status, retire the old word, or both. Name an existing status or a new one. - [Add job status](https://headhoncho.app/docs/api/add_job_status): Add a status to the workspace's list, on the line or as a detour. It carries no role: it is a name and a color. - [Update agency feed](https://headhoncho.app/docs/api/update_agency_feed): Change how closed jobs reach the agency: the webhook address, the daily file address and hour, or switch the feed on or off. Secrets are not touched. - [Sync callrail](https://headhoncho.app/docs/api/sync_callrail): Pull the company's new CallRail calls and forms now, match them to jobs, and say how many landed. The hourly sync does this on its own. - [Update callrail tracking](https://headhoncho.app/docs/api/update_callrail_tracking): Set the tracking phone numbers on a company's CallRail connection. They replace the list whole. The webhook signing key is set in the app. - [Refresh sources](https://headhoncho.app/docs/api/refresh_sources): Clear the Call center source stamped on a company's jobs, pull all its CallRail history again and re-read every call, so each job's source is worked out afresh. - [Sync ad platform](https://headhoncho.app/docs/api/sync_ad_platform): Pull a company's latest campaigns and spend from one ad platform now. The hourly sync does this on its own. - The same records in the app: [Settings](https://headhoncho.app/docs/settings). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "accepted": true, "position": 88611, "status_ids": [ "st_01", "st_02", "st_03", "st_06" ] } ``` ### cURL ```bash curl -X POST "https://api.headhoncho.app/api/v1/commands/reorder-line" \ -H "Authorization: Bearer hh_live_..." \ -H "Idempotency-Key: 6f1d2c9e-1b7a-4c1e-9a52-0d3f8e4b7a10" \ -H "Content-Type: application/json" \ -d '{ "status_ids": "[\"st_01\", \"st_02\", \"st_03\", \"st_06\"]" }' ``` ### Python ```python import requests import uuid response = requests.post( "https://api.headhoncho.app/api/v1/commands/reorder-line", headers={ "Authorization": "Bearer hh_live_...", "Idempotency-Key": str(uuid.uuid4()), }, json={ "status_ids": "[\"st_01\", \"st_02\", \"st_03\", \"st_06\"]", }, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/commands/reorder-line", { method: "POST", headers: { Authorization: "Bearer hh_live_...", "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "status_ids": "[\"st_01\", \"st_02\", \"st_03\", \"st_06\"]" }), }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: reorder_line Arguments: status_ids (text, required) Access: do on Company settings Hints: readOnly=false, destructive=false, idempotent=true, openWorld=false Try asking: "Using HeadHoncho, reorder line with status_ids ["st_01", "st_02", "st_03", "st_06"]." ``` --- # List import systems List import systems is a read in the HeadHoncho API. The systems a book can be imported from, and for each the steps to get its file out, what the file cannot carry, and which one this workspace used last. Page: https://headhoncho.app/docs/api/list_import_systems | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **List import systems**, HeadHoncho API v1. It is a read, sent to the base address `https://api.headhoncho.app`. `GET /api/v1/imports/systems` The key needs the **Jobs** area at **read**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). Send your key as `Authorization: Bearer hh_live_...`. See [API keys](https://headhoncho.app/docs/api/keys). ## Parameters This call takes no parameters. ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back systems, one per source: key, name, blurb, files, steps (kind, title, where to click, delivery, format, optional), cannot (what that system's file cannot carry) and warn. intents: the ways to import. last_system: the key this workspace used last, or null. It never changes a record. It only reads the companies the key reaches. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `systems` | list of objects | The systems. | | `systems[].key` | text | A short code for this item. Match on it in code. | | `systems[].name` | text | The name, as the app shows it. | | `systems[].mark` | text | The mark. | | `systems[].blurb` | text | The blurb. | | `systems[].files` | text | The files. | | `systems[].header_stable` | true or false | The header stable. | | `systems[].steps` | list of objects | The steps. | | `systems[].steps[].kind` | text | What sort of thing this is. | | `systems[].steps[].title` | text | The title, as the app shows it. | | `systems[].steps[].where` | text | The where. | | `systems[].steps[].delivery` | text | The delivery. | | `systems[].steps[].format` | text | The format. | | `systems[].steps[].optional` | true or false | The optional. | | `systems[].cannot` | list of text | The cannot. | | `systems[].warn` | text | The warn. | | `intents` | object | The intents. | | `intents.jobs` | text | The jobs. | | `intents.jobs_only` | text | The jobs only. | | `intents.money` | text | The money. | | `last_system` | text | The last system. | ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [Get import fields](https://headhoncho.app/docs/api/get_import_fields): Every field an import reads, for the jobs file and the money file: its label, its tier and what leaving it blank costs. - [Get import template](https://headhoncho.app/docs/api/get_import_template): A CSV to fill in, with every column the import reads and three example rows, for the jobs file, the money file or a payments list. - [Stage import](https://headhoncho.app/docs/api/stage_import): Send one export file (CSV or Excel) and get back what each column looks like and the mapping we propose. Nothing is imported yet. - [List import statuses](https://headhoncho.app/docs/api/list_import_statuses): The status words the staged files use, how many rows carry each, and which of our statuses each should land on. Nothing is written. - [List import job types](https://headhoncho.app/docs/api/list_import_job_types): The job-type words the staged files use, how many rows carry each, and which of our job types each should land on. Nothing is written. - [Preview import](https://headhoncho.app/docs/api/preview_import): Read the staged files against this workspace and say what an import would do, row by row: what lands, what is already here, what is refused and why. - [Rehearse import](https://headhoncho.app/docs/api/rehearse_import): Run the whole import for real inside one step that is then thrown away, and say what it would have landed and refused. Nothing is kept. - [Commit import](https://headhoncho.app/docs/api/commit_import): Import every clean row of the staged files: the jobs, then the money on them. Rows already here are skipped, so sending it twice adds nothing. - The same records in the app: [the Jobs panel](https://headhoncho.app/docs/jobs). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "systems": [ { "key": "workiz", "name": "Workiz", "mark": "W", "blurb": "Jobs report and Payments report, joined by Job ID.", "files": "2 files · you choose the columns", "header_stable": false, "steps": [ { "kind": "jobs", "title": "The jobs", "where": "In Workiz open Reports...", "delivery": "download", "format": "a CSV", "optional": false } ], "cannot": [ "A tech's cut" ], "warn": "" } ], "intents": { "jobs": "Jobs and money", "jobs_only": "Jobs only", "money": "Money only, the jobs are already here" }, "last_system": "workiz" } ``` ### cURL ```bash curl "https://api.headhoncho.app/api/v1/imports/systems" \ -H "Authorization: Bearer hh_live_..." ``` ### Python ```python import requests response = requests.get( "https://api.headhoncho.app/api/v1/imports/systems", headers={"Authorization": "Bearer hh_live_..."}, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/imports/systems", { headers: { Authorization: "Bearer hh_live_..." }, }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: list_import_systems Arguments: none Access: read on Jobs Hints: readOnly=true, destructive=false, idempotent=true, openWorld=false Try asking: "Using HeadHoncho, list import systems." ``` --- # Get import fields Get import fields is a read in the HeadHoncho API. Every field an import reads, for the jobs file and the money file: its label, its tier and what leaving it blank costs. Page: https://headhoncho.app/docs/api/get_import_fields | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **Get import fields**, HeadHoncho API v1. It is a read, sent to the base address `https://api.headhoncho.app`. `GET /api/v1/imports/fields` The key needs the **Jobs** area at **read**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). Send your key as `Authorization: Bearer hh_live_...`. See [API keys](https://headhoncho.app/docs/api/keys). ## Parameters This call takes no parameters. ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back jobs and money, each with kind, label, blurb, filename and fields (key, label, kind, tier, becomes, cost, multi). example_prefix: the word the template's example rows start with, which an import skips. It never changes a record. It only reads the companies the key reaches. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `jobs` | object | The jobs. | | `jobs.kind` | text | What sort of thing this is. | | `jobs.label` | text | The name the app shows for it. | | `jobs.blurb` | text | The blurb. | | `jobs.filename` | text | The name of the file. | | `jobs.fields` | list of objects | The fields. | | `jobs.fields[].key` | text | A short code for this item. Match on it in code. | | `jobs.fields[].label` | text | The name the app shows for it. | | `jobs.fields[].kind` | text | What sort of thing this is. | | `jobs.fields[].tier` | text | The tier. | | `jobs.fields[].becomes` | text | The becomes. | | `jobs.fields[].cost` | text | What it cost. | | `jobs.fields[].multi` | true or false | The multi. | | `money` | object | The money. | | `money.kind` | text | What sort of thing this is. | | `money.label` | text | The name the app shows for it. | | `money.blurb` | text | The blurb. | | `money.filename` | text | The name of the file. | | `money.fields` | list | The fields. | | `example_prefix` | text | The example prefix. | ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [List import systems](https://headhoncho.app/docs/api/list_import_systems): The systems a book can be imported from, and for each the steps to get its file out, what the file cannot carry, and which one this workspace used last. - [Get import template](https://headhoncho.app/docs/api/get_import_template): A CSV to fill in, with every column the import reads and three example rows, for the jobs file, the money file or a payments list. - [Stage import](https://headhoncho.app/docs/api/stage_import): Send one export file (CSV or Excel) and get back what each column looks like and the mapping we propose. Nothing is imported yet. - [List import statuses](https://headhoncho.app/docs/api/list_import_statuses): The status words the staged files use, how many rows carry each, and which of our statuses each should land on. Nothing is written. - [List import job types](https://headhoncho.app/docs/api/list_import_job_types): The job-type words the staged files use, how many rows carry each, and which of our job types each should land on. Nothing is written. - [Preview import](https://headhoncho.app/docs/api/preview_import): Read the staged files against this workspace and say what an import would do, row by row: what lands, what is already here, what is refused and why. - [Rehearse import](https://headhoncho.app/docs/api/rehearse_import): Run the whole import for real inside one step that is then thrown away, and say what it would have landed and refused. Nothing is kept. - [Commit import](https://headhoncho.app/docs/api/commit_import): Import every clean row of the staged files: the jobs, then the money on them. Rows already here are skipped, so sending it twice adds nothing. - The same records in the app: [the Jobs panel](https://headhoncho.app/docs/jobs). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "jobs": { "kind": "jobs", "label": "Jobs file", "blurb": "Who, where, when, and which ad sent them.", "filename": "headhoncho-jobs-template.csv", "fields": [ { "key": "ref", "label": "Ref", "kind": "ref", "tier": "required", "becomes": "The job's reference in your old system.", "cost": "A stand-in is made from the row's own facts.", "multi": false } ] }, "money": { "kind": "money", "label": "Money file", "blurb": "What each job made.", "filename": "headhoncho-money-template.csv", "fields": [] }, "example_prefix": "EXAMPLE" } ``` ### cURL ```bash curl "https://api.headhoncho.app/api/v1/imports/fields" \ -H "Authorization: Bearer hh_live_..." ``` ### Python ```python import requests response = requests.get( "https://api.headhoncho.app/api/v1/imports/fields", headers={"Authorization": "Bearer hh_live_..."}, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/imports/fields", { headers: { Authorization: "Bearer hh_live_..." }, }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: get_import_fields Arguments: none Access: read on Jobs Hints: readOnly=true, destructive=false, idempotent=true, openWorld=false Try asking: "Using HeadHoncho, get import fields." ``` --- # Get import template Get import template is a read in the HeadHoncho API. A CSV to fill in, with every column the import reads and three example rows, for the jobs file, the money file or a payments list. Page: https://headhoncho.app/docs/api/get_import_template | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **Get import template**, HeadHoncho API v1. It is a read, sent to the base address `https://api.headhoncho.app`. `GET /api/v1/imports/template` The key needs the **Jobs** area at **read**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). Send your key as `Authorization: Bearer hh_live_...`. See [API keys](https://headhoncho.app/docs/api/keys). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `kind` | text, in the query | No | jobs (default), money or payments. One of `jobs`, `money`, `payments`. | `jobs` | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back Over the API: the CSV itself (text/csv). Over MCP: a download link that works once for five minutes. The example rows start with the word in Import fields' example_prefix and are skipped. It never changes a record. It only reads the companies the key reaches. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `download` | object | The download. | | `download.url` | text | The link. | | `download.expires_in` | whole number | Seconds until the link stops working. | | `download.filename` | text | The name of the file. | ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [List import systems](https://headhoncho.app/docs/api/list_import_systems): The systems a book can be imported from, and for each the steps to get its file out, what the file cannot carry, and which one this workspace used last. - [Get import fields](https://headhoncho.app/docs/api/get_import_fields): Every field an import reads, for the jobs file and the money file: its label, its tier and what leaving it blank costs. - [Stage import](https://headhoncho.app/docs/api/stage_import): Send one export file (CSV or Excel) and get back what each column looks like and the mapping we propose. Nothing is imported yet. - [List import statuses](https://headhoncho.app/docs/api/list_import_statuses): The status words the staged files use, how many rows carry each, and which of our statuses each should land on. Nothing is written. - [List import job types](https://headhoncho.app/docs/api/list_import_job_types): The job-type words the staged files use, how many rows carry each, and which of our job types each should land on. Nothing is written. - [Preview import](https://headhoncho.app/docs/api/preview_import): Read the staged files against this workspace and say what an import would do, row by row: what lands, what is already here, what is refused and why. - [Rehearse import](https://headhoncho.app/docs/api/rehearse_import): Run the whole import for real inside one step that is then thrown away, and say what it would have landed and refused. Nothing is kept. - [Commit import](https://headhoncho.app/docs/api/commit_import): Import every clean row of the staged files: the jobs, then the money on them. Rows already here are skipped, so sending it twice adds nothing. - The same records in the app: [the Jobs panel](https://headhoncho.app/docs/jobs). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer This is the answer over MCP. Over the API the answer is the file itself, as text/csv. ```json { "download": { "url": "https://api.headhoncho.app/api/v1/imports/template?kind=jobs&once=t8Rv...", "expires_in": 300, "filename": "headhoncho-jobs-template.csv" } } ``` ### cURL ```bash curl "https://api.headhoncho.app/api/v1/imports/template?kind=jobs" \ -H "Authorization: Bearer hh_live_..." -o file.csv ``` ### Python ```python import requests response = requests.get( "https://api.headhoncho.app/api/v1/imports/template", headers={"Authorization": "Bearer hh_live_..."}, params={ "kind": "jobs", }, ) response.raise_for_status() open("file.csv", "wb").write(response.content) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/imports/template?kind=jobs", { headers: { Authorization: "Bearer hh_live_..." }, }); const data = await response.text(); console.log(data); ``` ### Your AI ```text Tool: get_import_template Arguments: kind (text, optional) Access: read on Jobs Hints: readOnly=true, destructive=false, idempotent=true, openWorld=false Try asking: "Using HeadHoncho, get import template with kind jobs." ``` --- # Stage import Stage import is a command in the HeadHoncho API. Send one export file (CSV or Excel) and get back what each column looks like and the mapping we propose. Nothing is imported yet. Page: https://headhoncho.app/docs/api/stage_import | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **Stage import**, HeadHoncho API v1. It is a command, sent to the base address `https://api.headhoncho.app`. `POST /api/v1/commands/stage-import` The key needs the **Jobs** area at **do**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). It runs the app's own command `stage-import`. Send an `Idempotency-Key` header with every call: the same key with the same body returns the first answer and runs nothing twice. See [the model](https://headhoncho.app/docs/api/model#idempotency). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `filename` | text, in the JSON body | Yes | The file's name, with its extension. | `jobs.csv` | | `content_base64` | text, in the JSON body | Yes | The file's bytes, base64 encoded. Up to 25 MB once decoded. | `UmVmLENsaWVudCxQaG9uZQ...` | | `system` | text, in the JSON body | No | The system the file came from, a key from Import sources. The answers are remembered for it. | `workiz` | | `half` | text, in the JSON body | No | jobs (default) or money. One of `jobs`, `money`. | `jobs` | | `shape` | text, in the JSON body | No | For the money half: auto (default), money (one row per job) or payments (one row per payment). One of `auto`, `money`, `payments`. | `auto` | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back accepted, position, staging_id (use it in plan), name, identified (the system it looks like, or null), columns_seen, rows_seen, and for a file we map: columns (name, samples, field, confidence, reason), mapping, date_order, missing_required, questions and counts. A Uleadz export is recognized outright and answers native true with its row count. It never deletes anything. It changes only what the command names, and it writes the change to the job's history with who asked for it. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `accepted` | true or false | True when the command ran. A command that cannot run is an error instead. | | `position` | whole number | Where the change landed in the event log. Pass it as `after` on a read to see your own write. | | `staging_id` | id (text) | The id of the staging. | | `name` | text | The name, as the app shows it. | | `identified` | text | The identified. | | `columns_seen` | whole number | The columns seen. | | `rows_seen` | whole number | The rows seen. | | `native` | true or false | The native. | | `half` | text | One of `jobs`, `money`. | | `shape` | text | One of `auto`, `money`, `payments`. | | `label` | text | The name the app shows for it. | | `columns` | list of objects | The columns. | | `columns[].index` | whole number | The index. | | `columns[].name` | text | The name, as the app shows it. | | `columns[].samples` | list of text | The samples. | | `columns[].filled` | whole number | The filled. | | `columns[].total` | whole number | The total, in the company's currency. | | `columns[].field` | text | The field. | | `columns[].field_label` | text | The field label. | | `columns[].tier` | text | The tier. | | `columns[].confidence` | text | The confidence. | | `columns[].reason` | text | The reason given. | | `mapping` | object | The mapping. | | `mapping.ref` | list | The ref. | | `date_order` | object | The date order. | | `missing_required` | list | The missing required. | | `questions` | list | The questions. | | `counts` | object | The counts. | | `counts.matched` | whole number | The matched. | | `counts.guessed` | whole number | The guessed. | | `counts.unmatched` | whole number | The unmatched. | ## A staged file is not a job The file is held for an hour and is gone after that. Nothing is written to the books until Commit an import. The position in the answer is the latest event, since staging adds none. ## Over MCP The file travels inside the call, so keep it small. The REST door takes the same JSON body. ## Personal details The sample values printed beside each column are customer data. When the credential hides personal details they are left out. ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`read_only`](https://headhoncho.app/docs/api/errors#read_only) | 403 | This credential may read this area but not change it. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`missing_idempotency_key`](https://headhoncho.app/docs/api/errors#missing_idempotency_key) | 400 | Send an Idempotency-Key header on every command. | | [`idempotency_mismatch`](https://headhoncho.app/docs/api/errors#idempotency_mismatch) | 409 | This Idempotency-Key was used with a different body. | | [`idempotency_in_progress`](https://headhoncho.app/docs/api/errors#idempotency_in_progress) | 409 | A command with this Idempotency-Key is still running. Wait a moment and send it again. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [List import systems](https://headhoncho.app/docs/api/list_import_systems): The systems a book can be imported from, and for each the steps to get its file out, what the file cannot carry, and which one this workspace used last. - [Get import fields](https://headhoncho.app/docs/api/get_import_fields): Every field an import reads, for the jobs file and the money file: its label, its tier and what leaving it blank costs. - [Get import template](https://headhoncho.app/docs/api/get_import_template): A CSV to fill in, with every column the import reads and three example rows, for the jobs file, the money file or a payments list. - [List import statuses](https://headhoncho.app/docs/api/list_import_statuses): The status words the staged files use, how many rows carry each, and which of our statuses each should land on. Nothing is written. - [List import job types](https://headhoncho.app/docs/api/list_import_job_types): The job-type words the staged files use, how many rows carry each, and which of our job types each should land on. Nothing is written. - [Preview import](https://headhoncho.app/docs/api/preview_import): Read the staged files against this workspace and say what an import would do, row by row: what lands, what is already here, what is refused and why. - [Rehearse import](https://headhoncho.app/docs/api/rehearse_import): Run the whole import for real inside one step that is then thrown away, and say what it would have landed and refused. Nothing is kept. - [Commit import](https://headhoncho.app/docs/api/commit_import): Import every clean row of the staged files: the jobs, then the money on them. Rows already here are skipped, so sending it twice adds nothing. - The same records in the app: [the Jobs panel](https://headhoncho.app/docs/jobs). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "accepted": true, "position": 88611, "staging_id": "k3Zp9aQ1", "name": "jobs.csv", "identified": "workiz", "columns_seen": 9, "rows_seen": 120, "native": false, "half": "jobs", "shape": "jobs", "label": "Jobs file", "columns": [ { "index": 0, "name": "Job ID", "samples": [ "W-1001", "W-1002" ], "filled": 120, "total": 120, "field": "ref", "field_label": "Ref", "tier": "required", "confidence": "name", "reason": "" } ], "mapping": { "ref": [ 0 ] }, "date_order": {}, "missing_required": [], "questions": [], "counts": { "matched": 8, "guessed": 1, "unmatched": 0 } } ``` ### cURL ```bash curl -X POST "https://api.headhoncho.app/api/v1/commands/stage-import" \ -H "Authorization: Bearer hh_live_..." \ -H "Idempotency-Key: 6f1d2c9e-1b7a-4c1e-9a52-0d3f8e4b7a10" \ -H "Content-Type: application/json" \ -d '{ "filename": "jobs.csv", "content_base64": "UmVmLENsaWVudCxQaG9uZQ...", "system": "workiz", "half": "jobs", "shape": "auto" }' ``` ### Python ```python import requests import uuid response = requests.post( "https://api.headhoncho.app/api/v1/commands/stage-import", headers={ "Authorization": "Bearer hh_live_...", "Idempotency-Key": str(uuid.uuid4()), }, json={ "filename": "jobs.csv", "content_base64": "UmVmLENsaWVudCxQaG9uZQ...", "system": "workiz", "half": "jobs", "shape": "auto", }, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/commands/stage-import", { method: "POST", headers: { Authorization: "Bearer hh_live_...", "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "filename": "jobs.csv", "content_base64": "UmVmLENsaWVudCxQaG9uZQ...", "system": "workiz", "half": "jobs", "shape": "auto" }), }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: stage_import Arguments: filename (text, required), content_base64 (text, required), system (text, optional), half (text, optional), shape (text, optional) Access: do on Jobs Hints: readOnly=false, destructive=false, idempotent=true, openWorld=false Try asking: "Using HeadHoncho, stage import with filename jobs.csv and content_base64 UmVmLENsaWVudCxQaG9uZQ... and system workiz." ``` --- # List import statuses List import statuses is a read in the HeadHoncho API. The status words the staged files use, how many rows carry each, and which of our statuses each should land on. Nothing is written. Page: https://headhoncho.app/docs/api/list_import_statuses | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **List import statuses**, HeadHoncho API v1. It is a read, sent to the base address `https://api.headhoncho.app`. `GET /api/v1/imports/statuses` The key needs the **Jobs** area at **read**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). Send your key as `Authorization: Bearer hh_live_...`. See [API keys](https://headhoncho.app/docs/api/keys). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `plan` | text, in the query | Yes | The staged files as a JSON list. Each item: staging_id (from Stage an import file), half (jobs, money or payments), mapping (field to column numbers) and date_order. | `[{"staging_id": "k3Zp...", "half": "jobs", "mapping": {"ref": [0], "client_name": [1]}}]` | | `system` | text, in the query | No | The system the file came from, a key from Import sources. The answers are remembered for it. | `workiz` | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back statuses, one per word: key, word, count, jobs, money, target (a status id, new or canceled), target_label, confidence and reason. options: the choices for each target. remembered_all and counts. Send your answers back as status_map on the next calls. It never changes a record. It only reads the companies the key reaches. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `statuses` | list of objects | The statuses. | | `statuses[].key` | text | A short code for this item. Match on it in code. | | `statuses[].word` | text | The word. | | `statuses[].count` | whole number | How many match in all, across every page. | | `statuses[].jobs` | whole number | The jobs. | | `statuses[].money` | whole number | The money. | | `statuses[].target` | text | The target. | | `statuses[].target_label` | text | The target label. | | `statuses[].confidence` | text | The confidence. | | `statuses[].reason` | text | The reason given. | | `options` | list of objects | The options. | | `options[].id` | id (text) | The id of this record. Ids are opaque text: keep them exactly as given. | | `options[].label` | text | The name the app shows for it. | | `remembered_all` | true or false | The remembered all. | | `counts` | object | The counts. | | `counts.words` | whole number | The text, as a person would say it. | | `counts.matched` | whole number | The matched. | | `counts.new` | whole number | The new. | ## How to answer Build status_map as an object of the file's word to a target: a status id, "new" to add it, or "canceled". Send it on Preview, Rehearse and Commit. ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [List import systems](https://headhoncho.app/docs/api/list_import_systems): The systems a book can be imported from, and for each the steps to get its file out, what the file cannot carry, and which one this workspace used last. - [Get import fields](https://headhoncho.app/docs/api/get_import_fields): Every field an import reads, for the jobs file and the money file: its label, its tier and what leaving it blank costs. - [Get import template](https://headhoncho.app/docs/api/get_import_template): A CSV to fill in, with every column the import reads and three example rows, for the jobs file, the money file or a payments list. - [Stage import](https://headhoncho.app/docs/api/stage_import): Send one export file (CSV or Excel) and get back what each column looks like and the mapping we propose. Nothing is imported yet. - [List import job types](https://headhoncho.app/docs/api/list_import_job_types): The job-type words the staged files use, how many rows carry each, and which of our job types each should land on. Nothing is written. - [Preview import](https://headhoncho.app/docs/api/preview_import): Read the staged files against this workspace and say what an import would do, row by row: what lands, what is already here, what is refused and why. - [Rehearse import](https://headhoncho.app/docs/api/rehearse_import): Run the whole import for real inside one step that is then thrown away, and say what it would have landed and refused. Nothing is kept. - [Commit import](https://headhoncho.app/docs/api/commit_import): Import every clean row of the staged files: the jobs, then the money on them. Rows already here are skipped, so sending it twice adds nothing. - The same records in the app: [the Jobs panel](https://headhoncho.app/docs/jobs). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "statuses": [ { "key": "done", "word": "Done", "count": 64, "jobs": 64, "money": 0, "target": "st_06", "target_label": "Closed", "confidence": "word", "reason": "" } ], "options": [ { "id": "st_06", "label": "Closed" } ], "remembered_all": false, "counts": { "words": 1, "matched": 1, "new": 0 } } ``` ### cURL ```bash curl "https://api.headhoncho.app/api/v1/imports/statuses?plan=%5B%7B%22staging_id%22%3A+%22k3Zp...%22%2C+%22half%22%3A+%22jobs%22%2C+%22mapping%22%3A+%7B%22ref%22%3A+%5B0%5D%2C+%22client_name%22%3A+%5B1%5D%7D%7D%5D&system=workiz" \ -H "Authorization: Bearer hh_live_..." ``` ### Python ```python import requests response = requests.get( "https://api.headhoncho.app/api/v1/imports/statuses", headers={"Authorization": "Bearer hh_live_..."}, params={ "plan": "[{\"staging_id\": \"k3Zp...\", \"half\": \"jobs\", \"mapping\": {\"ref\": [0], \"client_name\": [1]}}]", "system": "workiz", }, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/imports/statuses?plan=%5B%7B%22staging_id%22%3A+%22k3Zp...%22%2C+%22half%22%3A+%22jobs%22%2C+%22mapping%22%3A+%7B%22ref%22%3A+%5B0%5D%2C+%22client_name%22%3A+%5B1%5D%7D%7D%5D&system=workiz", { headers: { Authorization: "Bearer hh_live_..." }, }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: list_import_statuses Arguments: plan (text, required), system (text, optional) Access: read on Jobs Hints: readOnly=true, destructive=false, idempotent=true, openWorld=false Try asking: "Using HeadHoncho, list import statuses with plan [{"staging_id": "k3Zp...", "half": "jobs", "mapping": {"ref": [0], "client_name": [1]}}] and system workiz." ``` --- # List import job types List import job types is a read in the HeadHoncho API. The job-type words the staged files use, how many rows carry each, and which of our job types each should land on. Nothing is written. Page: https://headhoncho.app/docs/api/list_import_job_types | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **List import job types**, HeadHoncho API v1. It is a read, sent to the base address `https://api.headhoncho.app`. `GET /api/v1/imports/job-types` The key needs the **Jobs** area at **read**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). Send your key as `Authorization: Bearer hh_live_...`. See [API keys](https://headhoncho.app/docs/api/keys). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `plan` | text, in the query | Yes | The staged files as a JSON list. Each item: staging_id (from Stage an import file), half (jobs, money or payments), mapping (field to column numbers) and date_order. | `[{"staging_id": "k3Zp...", "half": "jobs", "mapping": {"ref": [0], "client_name": [1]}}]` | | `system` | text, in the query | No | The system the file came from, a key from Import sources. The answers are remembered for it. | `workiz` | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back job_types, one per word: key, word, count, jobs, money, target (a job type id, new or off), target_label and confidence. options, all_known and counts. Send your answers back as type_map on the next calls. It never changes a record. It only reads the companies the key reaches. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `job_types` | list of objects | The job types. | | `job_types[].key` | text | A short code for this item. Match on it in code. | | `job_types[].word` | text | The word. | | `job_types[].count` | whole number | How many match in all, across every page. | | `job_types[].jobs` | whole number | The jobs. | | `job_types[].money` | whole number | The money. | | `job_types[].target` | text | The target. | | `job_types[].target_label` | text | The target label. | | `job_types[].confidence` | text | The confidence. | | `options` | list of objects | The options. | | `options[].id` | id (text) | The id of this record. Ids are opaque text: keep them exactly as given. | | `options[].label` | text | The name the app shows for it. | | `all_known` | true or false | The all known. | | `counts` | object | The counts. | | `counts.words` | whole number | The text, as a person would say it. | | `counts.matched` | whole number | The matched. | | `counts.new` | whole number | The new. | ## How to answer Build type_map as an object of the file's word to a target: a job type id, "new" to add it, or "off" to leave it off. Send it on Preview, Rehearse and Commit. ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [List import systems](https://headhoncho.app/docs/api/list_import_systems): The systems a book can be imported from, and for each the steps to get its file out, what the file cannot carry, and which one this workspace used last. - [Get import fields](https://headhoncho.app/docs/api/get_import_fields): Every field an import reads, for the jobs file and the money file: its label, its tier and what leaving it blank costs. - [Get import template](https://headhoncho.app/docs/api/get_import_template): A CSV to fill in, with every column the import reads and three example rows, for the jobs file, the money file or a payments list. - [Stage import](https://headhoncho.app/docs/api/stage_import): Send one export file (CSV or Excel) and get back what each column looks like and the mapping we propose. Nothing is imported yet. - [List import statuses](https://headhoncho.app/docs/api/list_import_statuses): The status words the staged files use, how many rows carry each, and which of our statuses each should land on. Nothing is written. - [Preview import](https://headhoncho.app/docs/api/preview_import): Read the staged files against this workspace and say what an import would do, row by row: what lands, what is already here, what is refused and why. - [Rehearse import](https://headhoncho.app/docs/api/rehearse_import): Run the whole import for real inside one step that is then thrown away, and say what it would have landed and refused. Nothing is kept. - [Commit import](https://headhoncho.app/docs/api/commit_import): Import every clean row of the staged files: the jobs, then the money on them. Rows already here are skipped, so sending it twice adds nothing. - The same records in the app: [the Jobs panel](https://headhoncho.app/docs/jobs). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "job_types": [ { "key": "local move", "word": "Local Move", "count": 52, "jobs": 52, "money": 0, "target": "jt_02", "target_label": "Local move", "confidence": "name" } ], "options": [ { "id": "jt_02", "label": "Local move" } ], "all_known": true, "counts": { "words": 1, "matched": 1, "new": 0 } } ``` ### cURL ```bash curl "https://api.headhoncho.app/api/v1/imports/job-types?plan=%5B%7B%22staging_id%22%3A+%22k3Zp...%22%2C+%22half%22%3A+%22jobs%22%2C+%22mapping%22%3A+%7B%22ref%22%3A+%5B0%5D%2C+%22client_name%22%3A+%5B1%5D%7D%7D%5D&system=workiz" \ -H "Authorization: Bearer hh_live_..." ``` ### Python ```python import requests response = requests.get( "https://api.headhoncho.app/api/v1/imports/job-types", headers={"Authorization": "Bearer hh_live_..."}, params={ "plan": "[{\"staging_id\": \"k3Zp...\", \"half\": \"jobs\", \"mapping\": {\"ref\": [0], \"client_name\": [1]}}]", "system": "workiz", }, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/imports/job-types?plan=%5B%7B%22staging_id%22%3A+%22k3Zp...%22%2C+%22half%22%3A+%22jobs%22%2C+%22mapping%22%3A+%7B%22ref%22%3A+%5B0%5D%2C+%22client_name%22%3A+%5B1%5D%7D%7D%5D&system=workiz", { headers: { Authorization: "Bearer hh_live_..." }, }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: list_import_job_types Arguments: plan (text, required), system (text, optional) Access: read on Jobs Hints: readOnly=true, destructive=false, idempotent=true, openWorld=false Try asking: "Using HeadHoncho, list import job types with plan [{"staging_id": "k3Zp...", "half": "jobs", "mapping": {"ref": [0], "client_name": [1]}}] and system workiz." ``` --- # Preview import Preview import is a command in the HeadHoncho API. Read the staged files against this workspace and say what an import would do, row by row: what lands, what is already here, what is refused and why. Page: https://headhoncho.app/docs/api/preview_import | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **Preview import**, HeadHoncho API v1. It is a command, sent to the base address `https://api.headhoncho.app`. `POST /api/v1/commands/preview-import` The key needs the **Jobs** area at **read**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). It runs the app's own command `preview-import`. Send an `Idempotency-Key` header with every call: the same key with the same body returns the first answer and runs nothing twice. See [the model](https://headhoncho.app/docs/api/model#idempotency). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `company_id` | id, in the JSON body | Yes | The company the jobs land in. From Who am I. | `cmp_14f5` | | `plan` | text, in the JSON body | Yes | The staged files as a JSON list. Each item: staging_id (from Stage an import file), half (jobs, money or payments), mapping (field to column numbers) and date_order. | `[{"staging_id": "k3Zp...", "half": "jobs", "mapping": {"ref": [0], "client_name": [1]}}]` | | `status_map` | object, in the JSON body | No | The file's status word to a target, from Map statuses. | `{"Done": "st_06"}` | | `type_map` | object, in the JSON body | No | The file's job-type word to a target, from Map job types. | `{"Local Move": "jt_02"}` | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back accepted and position, then rows (each file row with its issues, gaps and already_imported), technicians (each name and the worker it would match), statuses and job_types_to_create, counts (total, importable, already_imported, refused, incomplete), finance (the money rows and their counts), decisions where the two files disagree (key, field, options jobs and money, values, default) and files and range. Nothing is written. It never deletes anything. It changes only what the command names, and it writes the change to the job's history with who asked for it. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `accepted` | true or false | True when the command ran. A command that cannot run is an error instead. | | `position` | whole number | Where the change landed in the event log. Pass it as `after` on a read to see your own write. | | `rows` | list of objects | The rows. | | `rows[].line` | whole number | The line. | | `rows[].ticket` | text | The job number the ticket shows. | | `rows[].status` | text | The job status. | | `rows[].job_type` | text | The job type. | | `rows[].technician` | text | The technician. | | `rows[].issues` | list | The issues. | | `rows[].gaps` | list | The gaps. | | `rows[].already_imported` | true or false | The already imported. | | `technicians` | list of objects | The technicians. | | `technicians[].name` | text | The name, as the app shows it. | | `technicians[].suggested_worker_id` | id (text) | The id of the suggested worker. | | `technicians[].suggested_worker_name` | text | The suggested worker name. | | `technicians[].suggested_role` | text | The suggested role. | | `statuses` | object | The statuses. | | `statuses.Done` | object | The Done. | | `statuses.Done.lands_on` | text | The date it was lands. | | `statuses.Done.creates` | value or null | The creates. | | `statuses.Done.archived` | value or null | The archived. | | `statuses_to_create` | list | The statuses to create. | | `job_types_to_create` | list | The job types to create. | | `counts` | object | The counts. | | `counts.total` | whole number | The total, in the company's currency. | | `counts.importable` | whole number | The importable. | | `counts.already_imported` | whole number | The already imported. | | `counts.refused` | whole number | The refused. | | `counts.addressless` | whole number | The addressless. | | `counts.incomplete` | whole number | The incomplete. | | `finance` | object | The finance. | | `finance.rows` | list | The rows. | | `finance.counts` | object | The counts. | | `finance.counts.total` | whole number | The total, in the company's currency. | | `finance.counts.importable` | whole number | The importable. | | `decisions` | list | The decisions. | | `files` | list of objects | The files. | | `files[].name` | text | The name, as the app shows it. | | `files[].half` | text | The half. | | `files[].rows` | whole number | The rows. | | `range` | value or null | The range. | ## A read that is sent as a command It writes nothing and needs only read access to Jobs, as the app's preview does. It is a POST because the plan is too long for a web address. ## Personal details The customer name, phone and street on each row follow the credential's personal-details switch. When it hides them, the raw address and the matched customer are left out too. ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`not_found`](https://headhoncho.app/docs/api/errors#not_found) | 404 | No such record in the companies this credential reaches. | | [`out_of_scope`](https://headhoncho.app/docs/api/errors#out_of_scope) | 404 | No such company in the companies this credential reaches. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`missing_idempotency_key`](https://headhoncho.app/docs/api/errors#missing_idempotency_key) | 400 | Send an Idempotency-Key header on every command. | | [`idempotency_mismatch`](https://headhoncho.app/docs/api/errors#idempotency_mismatch) | 409 | This Idempotency-Key was used with a different body. | | [`idempotency_in_progress`](https://headhoncho.app/docs/api/errors#idempotency_in_progress) | 409 | A command with this Idempotency-Key is still running. Wait a moment and send it again. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [List import systems](https://headhoncho.app/docs/api/list_import_systems): The systems a book can be imported from, and for each the steps to get its file out, what the file cannot carry, and which one this workspace used last. - [Get import fields](https://headhoncho.app/docs/api/get_import_fields): Every field an import reads, for the jobs file and the money file: its label, its tier and what leaving it blank costs. - [Get import template](https://headhoncho.app/docs/api/get_import_template): A CSV to fill in, with every column the import reads and three example rows, for the jobs file, the money file or a payments list. - [Stage import](https://headhoncho.app/docs/api/stage_import): Send one export file (CSV or Excel) and get back what each column looks like and the mapping we propose. Nothing is imported yet. - [List import statuses](https://headhoncho.app/docs/api/list_import_statuses): The status words the staged files use, how many rows carry each, and which of our statuses each should land on. Nothing is written. - [List import job types](https://headhoncho.app/docs/api/list_import_job_types): The job-type words the staged files use, how many rows carry each, and which of our job types each should land on. Nothing is written. - [Rehearse import](https://headhoncho.app/docs/api/rehearse_import): Run the whole import for real inside one step that is then thrown away, and say what it would have landed and refused. Nothing is kept. - [Commit import](https://headhoncho.app/docs/api/commit_import): Import every clean row of the staged files: the jobs, then the money on them. Rows already here are skipped, so sending it twice adds nothing. - The same records in the app: [the Jobs panel](https://headhoncho.app/docs/jobs). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "accepted": true, "position": 88611, "rows": [ { "line": 2, "ticket": "W-1001", "status": "Done", "job_type": "Local Move", "technician": "Dana R.", "issues": [], "gaps": [], "already_imported": false } ], "technicians": [ { "name": "Dana R.", "suggested_worker_id": "wrk_3b90", "suggested_worker_name": "Dana R.", "suggested_role": "technician" } ], "statuses": { "Done": { "lands_on": "Closed", "creates": null, "archived": null } }, "statuses_to_create": [], "job_types_to_create": [], "counts": { "total": 120, "importable": 118, "already_imported": 0, "refused": 2, "addressless": 3, "incomplete": 5 }, "finance": { "rows": [], "counts": { "total": 0, "importable": 0 } }, "decisions": [], "files": [ { "name": "jobs.csv", "half": "jobs", "rows": 120 } ], "range": null } ``` ### cURL ```bash curl -X POST "https://api.headhoncho.app/api/v1/commands/preview-import" \ -H "Authorization: Bearer hh_live_..." \ -H "Idempotency-Key: 6f1d2c9e-1b7a-4c1e-9a52-0d3f8e4b7a10" \ -H "Content-Type: application/json" \ -d '{ "company_id": "cmp_14f5", "plan": "[{\"staging_id\": \"k3Zp...\", \"half\": \"jobs\", \"mapping\": {\"ref\": [0], \"client_name\": [1]}}]", "status_map": { "Done": "st_06" }, "type_map": { "Local Move": "jt_02" } }' ``` ### Python ```python import requests import uuid response = requests.post( "https://api.headhoncho.app/api/v1/commands/preview-import", headers={ "Authorization": "Bearer hh_live_...", "Idempotency-Key": str(uuid.uuid4()), }, json={ "company_id": "cmp_14f5", "plan": "[{\"staging_id\": \"k3Zp...\", \"half\": \"jobs\", \"mapping\": {\"ref\": [0], \"client_name\": [1]}}]", "status_map": { "Done": "st_06", }, "type_map": { "Local Move": "jt_02", }, }, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/commands/preview-import", { method: "POST", headers: { Authorization: "Bearer hh_live_...", "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "company_id": "cmp_14f5", "plan": "[{\"staging_id\": \"k3Zp...\", \"half\": \"jobs\", \"mapping\": {\"ref\": [0], \"client_name\": [1]}}]", "status_map": { "Done": "st_06" }, "type_map": { "Local Move": "jt_02" } }), }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: preview_import Arguments: company_id (id, required), plan (text, required), status_map (object, optional), type_map (object, optional) Access: read on Jobs Hints: readOnly=false, destructive=false, idempotent=true, openWorld=false Try asking: "Using HeadHoncho, preview import with company_id cmp_14f5 and plan [{"staging_id": "k3Zp...", "half": "jobs", "mapping": {"ref": [0], "client_name": [1]}}]." ``` --- # Rehearse import Rehearse import is a command in the HeadHoncho API. Run the whole import for real inside one step that is then thrown away, and say what it would have landed and refused. Nothing is kept. Page: https://headhoncho.app/docs/api/rehearse_import | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **Rehearse import**, HeadHoncho API v1. It is a command, sent to the base address `https://api.headhoncho.app`. `POST /api/v1/commands/rehearse-import` The key needs the **Jobs** area at **read**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). It runs the app's own command `rehearse-import`. Send an `Idempotency-Key` header with every call: the same key with the same body returns the first answer and runs nothing twice. See [the model](https://headhoncho.app/docs/api/model#idempotency). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `company_id` | id, in the JSON body | Yes | The company the jobs land in. From Who am I. | `cmp_14f5` | | `plan` | text, in the JSON body | Yes | The staged files as a JSON list. Each item: staging_id (from Stage an import file), half (jobs, money or payments), mapping (field to column numbers) and date_order. | `[{"staging_id": "k3Zp...", "half": "jobs", "mapping": {"ref": [0], "client_name": [1]}}]` | | `status_map` | object, in the JSON body | No | The file's status word to a target, from Map statuses. | `{"Done": "st_06"}` | | `type_map` | object, in the JSON body | No | The file's job-type word to a target, from Map job types. | `{"Local Move": "jt_02"}` | | `worker_map` | object, in the JSON body | No | The file's technician name to one of our worker ids, or null to leave that technician's jobs unassigned. | `{"Dana R.": "wrk_3b90"}` | | `decisions` | object, in the JSON body | No | Your answers where the two files disagree, from Preview an import's decisions: the decision key to the side chosen, jobs (the jobs file's value) or money (the money file's). | `{"W-1001:status": "money"}` | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back accepted and position, rehearsal true, then the same report Commit an import gives: imported, skipped and refused per row, counts, gaps, finance and payments counts, and figures, the totals the files themselves state. It never deletes anything. It changes only what the command names, and it writes the change to the job's history with who asked for it. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `accepted` | true or false | True when the command ran. A command that cannot run is an error instead. | | `position` | whole number | Where the change landed in the event log. Pass it as `after` on a read to see your own write. | | `rehearsal` | true or false | The rehearsal. | | `imported` | list of objects | The imported. | | `imported[].line` | whole number | The line. | | `imported[].ticket` | text | The job number the ticket shows. | | `imported[].number` | whole number | The number people say out loud, such as the job number. | | `imported[].gaps` | list | The gaps. | | `skipped` | list | The skipped. | | `refused` | list of objects | The refused. | | `refused[].line` | whole number | The line. | | `refused[].ticket` | text | The job number the ticket shows. | | `refused[].reasons` | list of text | The reasons. | | `counts` | object | The counts. | | `counts.imported` | whole number | The imported. | | `counts.skipped` | whole number | The skipped. | | `counts.refused` | whole number | The refused. | | `counts.incomplete` | whole number | The incomplete. | | `examples` | whole number | The examples. | | `finance` | object | The finance. | | `finance.imported` | list | The imported. | | `finance.skipped` | list | The skipped. | | `finance.refused` | list | The refused. | | `finance.counts` | object | The counts. | | `finance.counts.imported` | whole number | The imported. | | `finance.counts.skipped` | whole number | The skipped. | | `finance.counts.refused` | whole number | The refused. | | `payments` | object | The payments. | | `payments.imported` | list | The imported. | | `payments.skipped` | list | The skipped. | | `payments.refused` | list | The refused. | | `payments.counts` | object | The counts. | | `payments.counts.imported` | whole number | The imported. | | `payments.counts.skipped` | whole number | The skipped. | | `payments.counts.refused` | whole number | The refused. | | `payments.counts.amount` | money (decimal as text) | The amount. In the company's currency. | | `figures` | object | The figures. | | `figures.money` | value or null | The money. | | `figures.payments` | value or null | The payments. | | `figures.span` | value or null | The span. | ## Why it exists A preview adds up the rows. A rehearsal runs the real commands, so a row that only fails inside a command shows up here and not after the import. ## What it leaves out The app also reads the Finance panel back after a rehearsal. The public API does not: the Finance panel is the app's own screen. Compare figures with Job money after a real import instead. ## Safe to repeat Nothing is kept, so run it as often as you like. Needs read access to Jobs, as in the app. ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`not_found`](https://headhoncho.app/docs/api/errors#not_found) | 404 | No such record in the companies this credential reaches. | | [`out_of_scope`](https://headhoncho.app/docs/api/errors#out_of_scope) | 404 | No such company in the companies this credential reaches. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`missing_idempotency_key`](https://headhoncho.app/docs/api/errors#missing_idempotency_key) | 400 | Send an Idempotency-Key header on every command. | | [`idempotency_mismatch`](https://headhoncho.app/docs/api/errors#idempotency_mismatch) | 409 | This Idempotency-Key was used with a different body. | | [`idempotency_in_progress`](https://headhoncho.app/docs/api/errors#idempotency_in_progress) | 409 | A command with this Idempotency-Key is still running. Wait a moment and send it again. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [List import systems](https://headhoncho.app/docs/api/list_import_systems): The systems a book can be imported from, and for each the steps to get its file out, what the file cannot carry, and which one this workspace used last. - [Get import fields](https://headhoncho.app/docs/api/get_import_fields): Every field an import reads, for the jobs file and the money file: its label, its tier and what leaving it blank costs. - [Get import template](https://headhoncho.app/docs/api/get_import_template): A CSV to fill in, with every column the import reads and three example rows, for the jobs file, the money file or a payments list. - [Stage import](https://headhoncho.app/docs/api/stage_import): Send one export file (CSV or Excel) and get back what each column looks like and the mapping we propose. Nothing is imported yet. - [List import statuses](https://headhoncho.app/docs/api/list_import_statuses): The status words the staged files use, how many rows carry each, and which of our statuses each should land on. Nothing is written. - [List import job types](https://headhoncho.app/docs/api/list_import_job_types): The job-type words the staged files use, how many rows carry each, and which of our job types each should land on. Nothing is written. - [Preview import](https://headhoncho.app/docs/api/preview_import): Read the staged files against this workspace and say what an import would do, row by row: what lands, what is already here, what is refused and why. - [Commit import](https://headhoncho.app/docs/api/commit_import): Import every clean row of the staged files: the jobs, then the money on them. Rows already here are skipped, so sending it twice adds nothing. - The same records in the app: [the Jobs panel](https://headhoncho.app/docs/jobs). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "accepted": true, "position": 88611, "rehearsal": true, "imported": [ { "line": 2, "ticket": "W-1001", "number": 1301, "gaps": [] } ], "skipped": [], "refused": [ { "line": 9, "ticket": "W-1008", "reasons": [ "Status \"Archived\" is retired." ] } ], "counts": { "imported": 118, "skipped": 0, "refused": 2, "incomplete": 5 }, "examples": 0, "finance": { "imported": [], "skipped": [], "refused": [], "counts": { "imported": 0, "skipped": 0, "refused": 0 } }, "payments": { "imported": [], "skipped": [], "refused": [], "counts": { "imported": 0, "skipped": 0, "refused": 0, "amount": "0.00" } }, "figures": { "money": null, "payments": null, "span": null } } ``` ### cURL ```bash curl -X POST "https://api.headhoncho.app/api/v1/commands/rehearse-import" \ -H "Authorization: Bearer hh_live_..." \ -H "Idempotency-Key: 6f1d2c9e-1b7a-4c1e-9a52-0d3f8e4b7a10" \ -H "Content-Type: application/json" \ -d '{ "company_id": "cmp_14f5", "plan": "[{\"staging_id\": \"k3Zp...\", \"half\": \"jobs\", \"mapping\": {\"ref\": [0], \"client_name\": [1]}}]", "status_map": { "Done": "st_06" }, "type_map": { "Local Move": "jt_02" }, "worker_map": { "Dana R.": "wrk_3b90" }, "decisions": { "W-1001:status": "money" } }' ``` ### Python ```python import requests import uuid response = requests.post( "https://api.headhoncho.app/api/v1/commands/rehearse-import", headers={ "Authorization": "Bearer hh_live_...", "Idempotency-Key": str(uuid.uuid4()), }, json={ "company_id": "cmp_14f5", "plan": "[{\"staging_id\": \"k3Zp...\", \"half\": \"jobs\", \"mapping\": {\"ref\": [0], \"client_name\": [1]}}]", "status_map": { "Done": "st_06", }, "type_map": { "Local Move": "jt_02", }, "worker_map": { "Dana R.": "wrk_3b90", }, "decisions": { "W-1001:status": "money", }, }, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/commands/rehearse-import", { method: "POST", headers: { Authorization: "Bearer hh_live_...", "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "company_id": "cmp_14f5", "plan": "[{\"staging_id\": \"k3Zp...\", \"half\": \"jobs\", \"mapping\": {\"ref\": [0], \"client_name\": [1]}}]", "status_map": { "Done": "st_06" }, "type_map": { "Local Move": "jt_02" }, "worker_map": { "Dana R.": "wrk_3b90" }, "decisions": { "W-1001:status": "money" } }), }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: rehearse_import Arguments: company_id (id, required), plan (text, required), status_map (object, optional), type_map (object, optional), worker_map (object, optional), decisions (object, optional) Access: read on Jobs Hints: readOnly=false, destructive=false, idempotent=true, openWorld=false Try asking: "Using HeadHoncho, rehearse import with company_id cmp_14f5 and plan [{"staging_id": "k3Zp...", "half": "jobs", "mapping": {"ref": [0], "client_name": [1]}}]." ``` --- # Commit import Commit import is a command in the HeadHoncho API. Import every clean row of the staged files: the jobs, then the money on them. Rows already here are skipped, so sending it twice adds nothing. Page: https://headhoncho.app/docs/api/commit_import | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **Commit import**, HeadHoncho API v1. It is a command, sent to the base address `https://api.headhoncho.app`. `POST /api/v1/commands/commit-import` The key needs the **Jobs** area at **do**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). It runs the app's own command `commit-import`. Send an `Idempotency-Key` header with every call: the same key with the same body returns the first answer and runs nothing twice. See [the model](https://headhoncho.app/docs/api/model#idempotency). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `company_id` | id, in the JSON body | Yes | The company the jobs land in. From Who am I. | `cmp_14f5` | | `plan` | text, in the JSON body | Yes | The staged files as a JSON list. Each item: staging_id (from Stage an import file), half (jobs, money or payments), mapping (field to column numbers) and date_order. | `[{"staging_id": "k3Zp...", "half": "jobs", "mapping": {"ref": [0], "client_name": [1]}}]` | | `status_map` | object, in the JSON body | No | The file's status word to a target, from Map statuses. | `{"Done": "st_06"}` | | `type_map` | object, in the JSON body | No | The file's job-type word to a target, from Map job types. | `{"Local Move": "jt_02"}` | | `worker_map` | object, in the JSON body | No | The file's technician name to one of our worker ids, or null to leave that technician's jobs unassigned. | `{"Dana R.": "wrk_3b90"}` | | `decisions` | object, in the JSON body | No | Your answers where the two files disagree, from Preview an import's decisions: the decision key to the side chosen, jobs (the jobs file's value) or money (the money file's). | `{"W-1001:status": "money"}` | | `system` | text, in the JSON body | No | The system the file came from, a key from Import sources. The answers are remembered for it. | `workiz` | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back accepted and position, then per row what landed: imported (line, ticket, new job number, gaps), skipped (already here) and refused (with the reasons), counts, gaps, finance and payments (their own imported, skipped, refused and counts), and figures. The answer is 201 when anything landed. It never deletes anything. It changes only what the command names, and it writes the change to the job's history with who asked for it. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `accepted` | true or false | True when the command ran. A command that cannot run is an error instead. | | `position` | whole number | Where the change landed in the event log. Pass it as `after` on a read to see your own write. | | `imported` | list of objects | The imported. | | `imported[].line` | whole number | The line. | | `imported[].ticket` | text | The job number the ticket shows. | | `imported[].number` | whole number | The number people say out loud, such as the job number. | | `imported[].gaps` | list | The gaps. | | `skipped` | list | The skipped. | | `refused` | list of objects | The refused. | | `refused[].line` | whole number | The line. | | `refused[].ticket` | text | The job number the ticket shows. | | `refused[].reasons` | list of text | The reasons. | | `counts` | object | The counts. | | `counts.imported` | whole number | The imported. | | `counts.skipped` | whole number | The skipped. | | `counts.refused` | whole number | The refused. | | `counts.incomplete` | whole number | The incomplete. | | `examples` | whole number | The examples. | | `finance` | object | The finance. | | `finance.imported` | list | The imported. | | `finance.skipped` | list | The skipped. | | `finance.refused` | list | The refused. | | `finance.counts` | object | The counts. | | `finance.counts.imported` | whole number | The imported. | | `finance.counts.skipped` | whole number | The skipped. | | `finance.counts.refused` | whole number | The refused. | | `payments` | object | The payments. | | `payments.imported` | list | The imported. | | `payments.skipped` | list | The skipped. | | `payments.refused` | list | The refused. | | `payments.counts` | object | The counts. | | `payments.counts.imported` | whole number | The imported. | | `payments.counts.skipped` | whole number | The skipped. | | `payments.counts.refused` | whole number | The refused. | | `payments.counts.amount` | money (decimal as text) | The amount. In the company's currency. | | `figures` | object | The figures. | | `figures.money` | value or null | The money. | | `figures.payments` | value or null | The payments. | | `figures.span` | value or null | The span. | ## Safe to send twice Every job is stored under its reference from the old system, or a stand-in made from the row's own facts. A row already imported is skipped, so a second commit of the same files lands nothing new. The staged file lives for an hour; after that Commit answers that the upload expired and you stage it again. ## Run Rehearse first Rehearse an import runs the same code and keeps nothing. ## What the app does that this leaves out The app can also close the imported balances in the same step. That option is not offered here; use Close a balance afterwards. ## Mapping is remembered With system, the status, job-type and column answers are saved for the next import from that system, as in the app. ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`read_only`](https://headhoncho.app/docs/api/errors#read_only) | 403 | This credential may read this area but not change it. | | [`not_found`](https://headhoncho.app/docs/api/errors#not_found) | 404 | No such record in the companies this credential reaches. | | [`out_of_scope`](https://headhoncho.app/docs/api/errors#out_of_scope) | 404 | No such company in the companies this credential reaches. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`missing_idempotency_key`](https://headhoncho.app/docs/api/errors#missing_idempotency_key) | 400 | Send an Idempotency-Key header on every command. | | [`idempotency_mismatch`](https://headhoncho.app/docs/api/errors#idempotency_mismatch) | 409 | This Idempotency-Key was used with a different body. | | [`idempotency_in_progress`](https://headhoncho.app/docs/api/errors#idempotency_in_progress) | 409 | A command with this Idempotency-Key is still running. Wait a moment and send it again. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [List import systems](https://headhoncho.app/docs/api/list_import_systems): The systems a book can be imported from, and for each the steps to get its file out, what the file cannot carry, and which one this workspace used last. - [Get import fields](https://headhoncho.app/docs/api/get_import_fields): Every field an import reads, for the jobs file and the money file: its label, its tier and what leaving it blank costs. - [Get import template](https://headhoncho.app/docs/api/get_import_template): A CSV to fill in, with every column the import reads and three example rows, for the jobs file, the money file or a payments list. - [Stage import](https://headhoncho.app/docs/api/stage_import): Send one export file (CSV or Excel) and get back what each column looks like and the mapping we propose. Nothing is imported yet. - [List import statuses](https://headhoncho.app/docs/api/list_import_statuses): The status words the staged files use, how many rows carry each, and which of our statuses each should land on. Nothing is written. - [List import job types](https://headhoncho.app/docs/api/list_import_job_types): The job-type words the staged files use, how many rows carry each, and which of our job types each should land on. Nothing is written. - [Preview import](https://headhoncho.app/docs/api/preview_import): Read the staged files against this workspace and say what an import would do, row by row: what lands, what is already here, what is refused and why. - [Rehearse import](https://headhoncho.app/docs/api/rehearse_import): Run the whole import for real inside one step that is then thrown away, and say what it would have landed and refused. Nothing is kept. - The same records in the app: [the Jobs panel](https://headhoncho.app/docs/jobs). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "accepted": true, "position": 88611, "imported": [ { "line": 2, "ticket": "W-1001", "number": 1301, "gaps": [] } ], "skipped": [], "refused": [ { "line": 9, "ticket": "W-1008", "reasons": [ "Status \"Archived\" is retired." ] } ], "counts": { "imported": 118, "skipped": 0, "refused": 2, "incomplete": 5 }, "examples": 0, "finance": { "imported": [], "skipped": [], "refused": [], "counts": { "imported": 0, "skipped": 0, "refused": 0 } }, "payments": { "imported": [], "skipped": [], "refused": [], "counts": { "imported": 0, "skipped": 0, "refused": 0, "amount": "0.00" } }, "figures": { "money": null, "payments": null, "span": null } } ``` ### cURL ```bash curl -X POST "https://api.headhoncho.app/api/v1/commands/commit-import" \ -H "Authorization: Bearer hh_live_..." \ -H "Idempotency-Key: 6f1d2c9e-1b7a-4c1e-9a52-0d3f8e4b7a10" \ -H "Content-Type: application/json" \ -d '{ "company_id": "cmp_14f5", "plan": "[{\"staging_id\": \"k3Zp...\", \"half\": \"jobs\", \"mapping\": {\"ref\": [0], \"client_name\": [1]}}]", "status_map": { "Done": "st_06" }, "type_map": { "Local Move": "jt_02" }, "worker_map": { "Dana R.": "wrk_3b90" }, "decisions": { "W-1001:status": "money" }, "system": "workiz" }' ``` ### Python ```python import requests import uuid response = requests.post( "https://api.headhoncho.app/api/v1/commands/commit-import", headers={ "Authorization": "Bearer hh_live_...", "Idempotency-Key": str(uuid.uuid4()), }, json={ "company_id": "cmp_14f5", "plan": "[{\"staging_id\": \"k3Zp...\", \"half\": \"jobs\", \"mapping\": {\"ref\": [0], \"client_name\": [1]}}]", "status_map": { "Done": "st_06", }, "type_map": { "Local Move": "jt_02", }, "worker_map": { "Dana R.": "wrk_3b90", }, "decisions": { "W-1001:status": "money", }, "system": "workiz", }, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/commands/commit-import", { method: "POST", headers: { Authorization: "Bearer hh_live_...", "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "company_id": "cmp_14f5", "plan": "[{\"staging_id\": \"k3Zp...\", \"half\": \"jobs\", \"mapping\": {\"ref\": [0], \"client_name\": [1]}}]", "status_map": { "Done": "st_06" }, "type_map": { "Local Move": "jt_02" }, "worker_map": { "Dana R.": "wrk_3b90" }, "decisions": { "W-1001:status": "money" }, "system": "workiz" }), }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: commit_import Arguments: company_id (id, required), plan (text, required), status_map (object, optional), type_map (object, optional), worker_map (object, optional), decisions (object, optional), system (text, optional) Access: do on Jobs Hints: readOnly=false, destructive=false, idempotent=true, openWorld=false Try asking: "Using HeadHoncho, commit import with company_id cmp_14f5 and plan [{"staging_id": "k3Zp...", "half": "jobs", "mapping": {"ref": [0], "client_name": [1]}}] and system workiz." ``` --- # List clients List clients is a read in the HeadHoncho API. The people behind your jobs, by name, with their phones and how many jobs each has. Page: https://headhoncho.app/docs/api/list_clients | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **List clients**, HeadHoncho API v1. It is a read, sent to the base address `https://api.headhoncho.app`. `GET /api/v1/clients` The key needs the **Jobs** area at **read**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). Send your key as `Authorization: Bearer hh_live_...`. See [API keys](https://headhoncho.app/docs/api/keys). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `q` | text, in the query | No | Part of a name or a phone number. | `azoulay` | | `limit` | number, in the query | No | 1 to 200. Default 50. | `50` | | `cursor` | text, in the query | No | From the previous answer's next. | `eyJhZnRlciI6IlIuIEF6b3VsYXkifQ` | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back items, one client each: id, name, phone, second_phone, email, job_count (jobs not in Trash), last_job_at and created_at. next is a cursor for the following page or null. count is how many match in all. With personal details hidden, names become initials, phones keep their last four and email is empty. It never changes a record. It only reads the companies the key reaches. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `items` | list of objects | The rows on this page. | | `items[].id` | id (text) | The id of this record. Ids are opaque text: keep them exactly as given. | | `items[].name` | text | The name, as the app shows it. | | `items[].phone` | text | A phone number. Hidden when the key hides personal details. | | `items[].second_phone` | text | A second phone number. Hidden when the key hides personal details. | | `items[].email` | text | The email. | | `items[].job_count` | whole number | The job count. | | `items[].last_job_at` | time (ISO 8601, with offset) | When the last job happened. Carries its offset from UTC; `Z` is UTC. | | `items[].created_at` | time (ISO 8601, with offset) | When it was created. Carries its offset from UTC; `Z` is UTC. | | `next` | value or null | The cursor for the next page, or null on the last page. Pass it back as `cursor`. | | `count` | whole number | How many match in all, across every page. | ## Needs every company The client book is the whole workspace's, not one company's. A credential that reaches only some companies is refused with no_access, so it can never read or change a person who also belongs to a company it cannot see. ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [Get client](https://headhoncho.app/docs/api/get_client): One client: name, phones and email, and their jobs, newest first. - The same records in the app: [the Jobs panel](https://headhoncho.app/docs/jobs). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "items": [ { "id": "cli_9c40", "name": "R. Azoulay", "phone": "+12175550142", "second_phone": "", "email": "r.azoulay@example.com", "job_count": 3, "last_job_at": "2026-10-11T18:25:40Z", "created_at": "2026-08-02T15:10:00Z" } ], "next": null, "count": 1 } ``` ### cURL ```bash curl "https://api.headhoncho.app/api/v1/clients?q=azoulay&limit=50" \ -H "Authorization: Bearer hh_live_..." ``` ### Python ```python import requests response = requests.get( "https://api.headhoncho.app/api/v1/clients", headers={"Authorization": "Bearer hh_live_..."}, params={ "q": "azoulay", "limit": "50", }, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/clients?q=azoulay&limit=50", { headers: { Authorization: "Bearer hh_live_..." }, }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: list_clients Arguments: q (text, optional), limit (number, optional), cursor (text, optional) Access: read on Jobs Hints: readOnly=true, destructive=false, idempotent=true, openWorld=false Try asking: "Using HeadHoncho, list clients with q azoulay." ``` --- # Get client Get client is a read in the HeadHoncho API. One client: name, phones and email, and their jobs, newest first. Page: https://headhoncho.app/docs/api/get_client | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **Get client**, HeadHoncho API v1. It is a read, sent to the base address `https://api.headhoncho.app`. `GET /api/v1/clients/{client_id}` The key needs the **Jobs** area at **read**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). Send your key as `Authorization: Bearer hh_live_...`. See [API keys](https://headhoncho.app/docs/api/keys). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `client_id` | id, in the path | Yes | The client id, from List clients. | `cli_9c40` | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back The client in the List clients shape, and jobs: up to 100, newest first, each with id, number, status and created_at. Jobs in Trash are not listed. It never changes a record. It only reads the companies the key reaches. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `id` | id (text) | The id of this record. Ids are opaque text: keep them exactly as given. | | `name` | text | The name, as the app shows it. | | `phone` | text | A phone number. Hidden when the key hides personal details. | | `second_phone` | text | A second phone number. Hidden when the key hides personal details. | | `email` | text | The email. | | `job_count` | whole number | The job count. | | `last_job_at` | time (ISO 8601, with offset) | When the last job happened. Carries its offset from UTC; `Z` is UTC. | | `created_at` | time (ISO 8601, with offset) | When it was created. Carries its offset from UTC; `Z` is UTC. | | `jobs` | list of objects | The jobs. | | `jobs[].id` | id (text) | The id of this record. Ids are opaque text: keep them exactly as given. | | `jobs[].number` | whole number | The number people say out loud, such as the job number. | | `jobs[].status` | text | The job status. | | `jobs[].created_at` | time (ISO 8601, with offset) | When it was created. Carries its offset from UTC; `Z` is UTC. | ## Needs every company The client book is the whole workspace's, not one company's. A credential that reaches only some companies is refused with no_access, so it can never read or change a person who also belongs to a company it cannot see. ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`not_found`](https://headhoncho.app/docs/api/errors#not_found) | 404 | No such record in the companies this credential reaches. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [List clients](https://headhoncho.app/docs/api/list_clients): The people behind your jobs, by name, with their phones and how many jobs each has. - The same records in the app: [the Jobs panel](https://headhoncho.app/docs/jobs). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "id": "cli_9c40", "name": "R. Azoulay", "phone": "+12175550142", "second_phone": "", "email": "r.azoulay@example.com", "job_count": 3, "last_job_at": "2026-10-11T18:25:40Z", "created_at": "2026-08-02T15:10:00Z", "jobs": [ { "id": "job_1138", "number": 1138, "status": "Scheduled", "created_at": "2026-10-11T18:25:40Z" } ] } ``` ### cURL ```bash curl "https://api.headhoncho.app/api/v1/clients/cli_9c40" \ -H "Authorization: Bearer hh_live_..." ``` ### Python ```python import requests response = requests.get( "https://api.headhoncho.app/api/v1/clients/cli_9c40", headers={"Authorization": "Bearer hh_live_..."}, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/clients/cli_9c40", { headers: { Authorization: "Bearer hh_live_..." }, }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: get_client Arguments: client_id (id, required) Access: read on Jobs Hints: readOnly=true, destructive=false, idempotent=true, openWorld=false Try asking: "Using HeadHoncho, get client with client_id cli_9c40." ``` --- # Create client Create client is a command in the HeadHoncho API. Add a client to the book before they have a job. One phone number is one client. Page: https://headhoncho.app/docs/api/create_client | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **Create client**, HeadHoncho API v1. It is a command, sent to the base address `https://api.headhoncho.app`. `POST /api/v1/commands/create-client` The key needs the **Jobs** area at **do**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). It runs the app's own command `create-client`. Send an `Idempotency-Key` header with every call: the same key with the same body returns the first answer and runs nothing twice. See [the model](https://headhoncho.app/docs/api/model#idempotency). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `name` | text, in the JSON body | Yes | At least 2 characters. | `R. Azoulay` | | `phone` | text, in the JSON body | Yes | Any format; stored as E.164. Must not belong to another client. | `+12175550142` | | `secondary_phone` | text, in the JSON body | No | A second phone. Optional. | `+12175550199` | | `email` | text, in the JSON body | No | Optional. | `r.azoulay@example.com` | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back accepted, client_id, name and position: the event position, usable as after= on the next read so you see your own write. A phone that another client already holds is refused with 422 naming the field, so sending it twice adds one client. It never deletes anything. It changes only what the command names, and it writes the change to the job's history with who asked for it. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `accepted` | true or false | True when the command ran. A command that cannot run is an error instead. | | `client_id` | id (text) | The id of the client. | | `position` | whole number | Where the change landed in the event log. Pass it as `after` on a read to see your own write. | | `name` | text | The name, as the app shows it. | ## Needs every company The client book is the whole workspace's, not one company's. A credential that reaches only some companies is refused with no_access, so it can never read or change a person who also belongs to a company it cannot see. ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`read_only`](https://headhoncho.app/docs/api/errors#read_only) | 403 | This credential may read this area but not change it. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`missing_idempotency_key`](https://headhoncho.app/docs/api/errors#missing_idempotency_key) | 400 | Send an Idempotency-Key header on every command. | | [`idempotency_mismatch`](https://headhoncho.app/docs/api/errors#idempotency_mismatch) | 409 | This Idempotency-Key was used with a different body. | | [`idempotency_in_progress`](https://headhoncho.app/docs/api/errors#idempotency_in_progress) | 409 | A command with this Idempotency-Key is still running. Wait a moment and send it again. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [Update client](https://headhoncho.app/docs/api/update_client): Correct a client's name, phones or email. Only the fields you send change. - [Delete client](https://headhoncho.app/docs/api/delete_client): Erase a person from the book. Their jobs stay, but lose the name and phone. It cannot be undone. - The same records in the app: [the Jobs panel](https://headhoncho.app/docs/jobs). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "accepted": true, "client_id": "cli_9c40", "position": 88502, "name": "R. Azoulay" } ``` ### cURL ```bash curl -X POST "https://api.headhoncho.app/api/v1/commands/create-client" \ -H "Authorization: Bearer hh_live_..." \ -H "Idempotency-Key: 6f1d2c9e-1b7a-4c1e-9a52-0d3f8e4b7a10" \ -H "Content-Type: application/json" \ -d '{ "name": "R. Azoulay", "phone": "+12175550142", "secondary_phone": "+12175550199", "email": "r.azoulay@example.com" }' ``` ### Python ```python import requests import uuid response = requests.post( "https://api.headhoncho.app/api/v1/commands/create-client", headers={ "Authorization": "Bearer hh_live_...", "Idempotency-Key": str(uuid.uuid4()), }, json={ "name": "R. Azoulay", "phone": "+12175550142", "secondary_phone": "+12175550199", "email": "r.azoulay@example.com", }, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/commands/create-client", { method: "POST", headers: { Authorization: "Bearer hh_live_...", "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "name": "R. Azoulay", "phone": "+12175550142", "secondary_phone": "+12175550199", "email": "r.azoulay@example.com" }), }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: create_client Arguments: name (text, required), phone (text, required), secondary_phone (text, optional), email (text, optional) Access: do on Jobs Hints: readOnly=false, destructive=false, idempotent=true, openWorld=false Try asking: "Using HeadHoncho, create client with name R. Azoulay and phone +12175550142 and secondary_phone +12175550199." ``` --- # Update client Update client is a command in the HeadHoncho API. Correct a client's name, phones or email. Only the fields you send change. Page: https://headhoncho.app/docs/api/update_client | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **Update client**, HeadHoncho API v1. It is a command, sent to the base address `https://api.headhoncho.app`. `POST /api/v1/commands/update-client` The key needs the **Jobs** area at **do**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). It runs the app's own command `update-client`. Send an `Idempotency-Key` header with every call: the same key with the same body returns the first answer and runs nothing twice. See [the model](https://headhoncho.app/docs/api/model#idempotency). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `client_id` | id, in the JSON body | Yes | From List clients. | `cli_9c40` | | `name` | text, in the JSON body | No | At least 2 characters. | `Ron Azoulay` | | `phone` | text, in the JSON body | No | Any format; stored as E.164. Must not belong to another client. | None | | `secondary_phone` | text, in the JSON body | No | A second phone, or empty to clear it. | None | | `email` | text, in the JSON body | No | The email, or empty to clear it. | None | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back accepted, client_id, name, position and changed: the fields that moved. It never deletes anything. It changes only what the command names, and it writes the change to the job's history with who asked for it. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `accepted` | true or false | True when the command ran. A command that cannot run is an error instead. | | `client_id` | id (text) | The id of the client. | | `position` | whole number | Where the change landed in the event log. Pass it as `after` on a read to see your own write. | | `name` | text | The name, as the app shows it. | | `changed` | list of text | The changed. | ## Needs every company The client book is the whole workspace's, not one company's. A credential that reaches only some companies is refused with no_access, so it can never read or change a person who also belongs to a company it cannot see. ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`read_only`](https://headhoncho.app/docs/api/errors#read_only) | 403 | This credential may read this area but not change it. | | [`not_found`](https://headhoncho.app/docs/api/errors#not_found) | 404 | No such record in the companies this credential reaches. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`missing_idempotency_key`](https://headhoncho.app/docs/api/errors#missing_idempotency_key) | 400 | Send an Idempotency-Key header on every command. | | [`idempotency_mismatch`](https://headhoncho.app/docs/api/errors#idempotency_mismatch) | 409 | This Idempotency-Key was used with a different body. | | [`idempotency_in_progress`](https://headhoncho.app/docs/api/errors#idempotency_in_progress) | 409 | A command with this Idempotency-Key is still running. Wait a moment and send it again. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [Create client](https://headhoncho.app/docs/api/create_client): Add a client to the book before they have a job. One phone number is one client. - [Delete client](https://headhoncho.app/docs/api/delete_client): Erase a person from the book. Their jobs stay, but lose the name and phone. It cannot be undone. - The same records in the app: [the Jobs panel](https://headhoncho.app/docs/jobs). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "accepted": true, "client_id": "cli_9c40", "position": 88502, "name": "Ron Azoulay", "changed": [ "name" ] } ``` ### cURL ```bash curl -X POST "https://api.headhoncho.app/api/v1/commands/update-client" \ -H "Authorization: Bearer hh_live_..." \ -H "Idempotency-Key: 6f1d2c9e-1b7a-4c1e-9a52-0d3f8e4b7a10" \ -H "Content-Type: application/json" \ -d '{ "client_id": "cli_9c40", "name": "Ron Azoulay" }' ``` ### Python ```python import requests import uuid response = requests.post( "https://api.headhoncho.app/api/v1/commands/update-client", headers={ "Authorization": "Bearer hh_live_...", "Idempotency-Key": str(uuid.uuid4()), }, json={ "client_id": "cli_9c40", "name": "Ron Azoulay", }, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/commands/update-client", { method: "POST", headers: { Authorization: "Bearer hh_live_...", "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "client_id": "cli_9c40", "name": "Ron Azoulay" }), }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: update_client Arguments: client_id (id, required), name (text, optional), phone (text, optional), secondary_phone (text, optional), email (text, optional) Access: do on Jobs Hints: readOnly=false, destructive=false, idempotent=true, openWorld=false Try asking: "Using HeadHoncho, update client with client_id cli_9c40 and name Ron Azoulay." ``` --- # Delete client Delete client is a command in the HeadHoncho API. Erase a person from the book. Their jobs stay, but lose the name and phone. It cannot be undone. Page: https://headhoncho.app/docs/api/delete_client | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **Delete client**, HeadHoncho API v1. It is a command, sent to the base address `https://api.headhoncho.app`. `POST /api/v1/commands/delete-client` The key needs the **Jobs** area at **do**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). It runs the app's own command `delete-client`. Send an `Idempotency-Key` header with every call: the same key with the same body returns the first answer and runs nothing twice. See [the model](https://headhoncho.app/docs/api/model#idempotency). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `client_id` | id, in the JSON body | Yes | From List clients. | `cli_9c40` | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back accepted, client_id, jobs_detached (how many jobs lost this person), addresses_detached, scrubbed and position. scrubbed is true when the client had jobs: the row is kept as "Deleted client" with no phone or email, because every job needs a client. A client with no jobs is removed outright. It never deletes anything. It changes only what the command names, and it writes the change to the job's history with who asked for it. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `accepted` | true or false | True when the command ran. A command that cannot run is an error instead. | | `client_id` | id (text) | The id of the client. | | `jobs_detached` | whole number | The jobs detached. | | `addresses_detached` | whole number | The addresses detached. | | `scrubbed` | true or false | The scrubbed. | | `position` | whole number | Where the change landed in the event log. Pass it as `after` on a read to see your own write. | ## Needs every company The client book is the whole workspace's, not one company's. A credential that reaches only some companies is refused with no_access, so it can never read or change a person who also belongs to a company it cannot see. ## Erasing This is the right to be forgotten, kept. The name, phone and email are gone for good, from the book and from the history of the client. The jobs and their money stay as business facts. Ask the person to confirm before you send it. ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`read_only`](https://headhoncho.app/docs/api/errors#read_only) | 403 | This credential may read this area but not change it. | | [`not_found`](https://headhoncho.app/docs/api/errors#not_found) | 404 | No such record in the companies this credential reaches. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`missing_idempotency_key`](https://headhoncho.app/docs/api/errors#missing_idempotency_key) | 400 | Send an Idempotency-Key header on every command. | | [`idempotency_mismatch`](https://headhoncho.app/docs/api/errors#idempotency_mismatch) | 409 | This Idempotency-Key was used with a different body. | | [`idempotency_in_progress`](https://headhoncho.app/docs/api/errors#idempotency_in_progress) | 409 | A command with this Idempotency-Key is still running. Wait a moment and send it again. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [Create client](https://headhoncho.app/docs/api/create_client): Add a client to the book before they have a job. One phone number is one client. - [Update client](https://headhoncho.app/docs/api/update_client): Correct a client's name, phones or email. Only the fields you send change. - The same records in the app: [the Jobs panel](https://headhoncho.app/docs/jobs). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "accepted": true, "client_id": "cli_9c40", "jobs_detached": 3, "addresses_detached": 2, "scrubbed": true, "position": 88510 } ``` ### cURL ```bash curl -X POST "https://api.headhoncho.app/api/v1/commands/delete-client" \ -H "Authorization: Bearer hh_live_..." \ -H "Idempotency-Key: 6f1d2c9e-1b7a-4c1e-9a52-0d3f8e4b7a10" \ -H "Content-Type: application/json" \ -d '{ "client_id": "cli_9c40" }' ``` ### Python ```python import requests import uuid response = requests.post( "https://api.headhoncho.app/api/v1/commands/delete-client", headers={ "Authorization": "Bearer hh_live_...", "Idempotency-Key": str(uuid.uuid4()), }, json={ "client_id": "cli_9c40", }, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/commands/delete-client", { method: "POST", headers: { Authorization: "Bearer hh_live_...", "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "client_id": "cli_9c40" }), }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: delete_client Arguments: client_id (id, required) Access: do on Jobs Hints: readOnly=false, destructive=true, idempotent=true, openWorld=false Try asking: "Using HeadHoncho, delete client with client_id cli_9c40." ``` --- # List leads List leads is a read in the HeadHoncho API. Leads in the companies this credential reaches, newest first, with stage, service, estimate and where each came from. Page: https://headhoncho.app/docs/api/list_leads | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **List leads**, HeadHoncho API v1. It is a read, sent to the base address `https://api.headhoncho.app`. `GET /api/v1/leads` The key needs the **Leads** area at **read**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). Send your key as `Authorization: Bearer hh_live_...`. See [API keys](https://headhoncho.app/docs/api/keys). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `company_id` | id, in the query | No | One company. Default: every company the credential reaches. | `cmp_14f5` | | `stage` | text, in the query | No | new, taken, quoted, won, lost or passed. One of `new`, `taken`, `quoted`, `won`, `lost`, `passed`. | `new` | | `bin` | text, in the query | No | Which leads: active (default, not in Archive), answer (still open), done (won, lost or passed) or archived. One of `active`, `answer`, `done`, `archived`. | `answer` | | `limit` | number, in the query | No | 1 to 200. Default 50. | `50` | | `cursor` | text, in the query | No | From the previous answer's next. | `eyJhZnRlciI6...` | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back items, one lead each in the Get a lead shape without history; next, a cursor for the following page or null; count, how many match in all. Leads in Trash are not listed. estimate is {amount, source}: source is person when someone set it, or price_list. quoted is a number in the company's currency, or null. It never changes a record. It only reads the companies the key reaches. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `items` | list of objects | The rows on this page. | | `items[].id` | id (text) | The id of this record. Ids are opaque text: keep them exactly as given. | | `items[].number` | whole number | The number people say out loud, such as the job number. | | `items[].ticket` | text | The job number the ticket shows. | | `items[].company` | object | The company. | | `items[].company.id` | id (text) | The id of this record. Ids are opaque text: keep them exactly as given. | | `items[].company.name` | text | The name, as the app shows it. | | `items[].stage` | text | One of `new`, `taken`, `quoted`, `won`, `lost`, `passed`. | | `items[].stage_since` | time (ISO 8601, with offset) | The moment: stage since. Carries its offset from UTC; `Z` is UTC. | | `items[].client_name` | text | The customer's name. Hidden when the key hides personal details. | | `items[].client_phone` | text | The customer's phone number. Hidden when the key hides personal details. | | `items[].address` | object | The address. | | `items[].address.line1` | text | The street address. Hidden when the key hides personal details. | | `items[].address.city` | text | The city. | | `items[].address.state` | text | The state or region. | | `items[].service` | object | The service. | | `items[].service.id` | id (text) | The id of this record. Ids are opaque text: keep them exactly as given. | | `items[].service.name` | text | The name, as the app shows it. | | `items[].wanted_start` | time (ISO 8601, with offset) | The moment: wanted start. Carries its offset from UTC; `Z` is UTC. | | `items[].wanted_end` | time (ISO 8601, with offset) | The moment: wanted end. Carries its offset from UTC; `Z` is UTC. | | `items[].urgent` | true or false | The urgent. | | `items[].notes` | text | Free-text notes. | | `items[].estimate` | object | The estimate. | | `items[].estimate.amount` | money (number) | The amount. In the company's currency. | | `items[].estimate.source` | text | The source. | | `items[].quoted` | value or null | The price quoted for the job. | | `items[].lost_reason` | text | The lost reason. | | `items[].pass_reason` | text | The pass reason. | | `items[].job` | value or null | The job. | | `items[].assigned_to` | value or null | The assigned to. | | `items[].source` | object | The source. | | `items[].source.kind` | text | What sort of thing this is. | | `items[].source.label` | text | The name the app shows for it. | | `items[].source.channel` | value or null | The channel. | | `items[].arrivals` | whole number | The arrivals. | | `items[].arrived_at` | time (ISO 8601, with offset) | When it was arrived. Carries its offset from UTC; `Z` is UTC. | | `items[].missing` | list of text | The missing. | | `items[].ready` | true or false | The ready. | | `items[].archived_at` | time or null | When it was archived. | | `items[].created_at` | time (ISO 8601, with offset) | When it was created. Carries its offset from UTC; `Z` is UTC. | | `next` | value or null | The cursor for the next page, or null on the last page. Pass it back as `cursor`. | | `count` | whole number | How many match in all, across every page. | ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`not_found`](https://headhoncho.app/docs/api/errors#not_found) | 404 | No such record in the companies this credential reaches. | | [`out_of_scope`](https://headhoncho.app/docs/api/errors#out_of_scope) | 404 | No such company in the companies this credential reaches. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [Get lead](https://headhoncho.app/docs/api/get_lead): One lead: who, what and when they asked for, the estimate, its stage and what happened to it so far. - [List needs you](https://headhoncho.app/docs/api/list_needs_you): Jobs that wait on a person, most urgent first, each with the reasons: no technician, unpaid cut, no answer and more. - [List conversion reviews](https://headhoncho.app/docs/api/list_conversion_reviews): Ad clicks the matcher would not guess at. Each waits for you to pick the job it produced, or to reject it. - The same records in the app: [the Leads panel](https://headhoncho.app/docs/marketing/sources). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "items": [ { "id": "lead_5d21", "number": 2041, "ticket": "L-2041", "company": { "id": "cmp_14f5", "name": "Sunrise Moving" }, "stage": "new", "stage_since": "2026-10-24T14:02:11Z", "client_name": "R. Azoulay", "client_phone": "+12175550142", "address": { "line1": "2590 Main St", "city": "Bloomington", "state": "IL" }, "service": { "id": "jt_02", "name": "Local move" }, "wanted_start": "2026-10-30T09:00:00Z", "wanted_end": "2026-10-30T12:00:00Z", "urgent": false, "notes": "Two flights of stairs", "estimate": { "amount": 1200.0, "source": "price_list" }, "quoted": null, "lost_reason": "", "pass_reason": "", "job": null, "assigned_to": null, "source": { "kind": "call", "label": "Voice line", "channel": null }, "arrivals": 1, "arrived_at": "2026-10-24T14:02:11Z", "missing": [ "postal_code" ], "ready": false, "archived_at": null, "created_at": "2026-10-24T14:02:11Z" } ], "next": null, "count": 1 } ``` ### cURL ```bash curl "https://api.headhoncho.app/api/v1/leads?company_id=cmp_14f5&stage=new" \ -H "Authorization: Bearer hh_live_..." ``` ### Python ```python import requests response = requests.get( "https://api.headhoncho.app/api/v1/leads", headers={"Authorization": "Bearer hh_live_..."}, params={ "company_id": "cmp_14f5", "stage": "new", }, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/leads?company_id=cmp_14f5&stage=new", { headers: { Authorization: "Bearer hh_live_..." }, }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: list_leads Arguments: company_id (id, optional), stage (text, optional), bin (text, optional), limit (number, optional), cursor (text, optional) Access: read on Leads Hints: readOnly=true, destructive=false, idempotent=true, openWorld=false Try asking: "Using HeadHoncho, list leads with company_id cmp_14f5." ``` --- # Get lead Get lead is a read in the HeadHoncho API. One lead: who, what and when they asked for, the estimate, its stage and what happened to it so far. Page: https://headhoncho.app/docs/api/get_lead | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **Get lead**, HeadHoncho API v1. It is a read, sent to the base address `https://api.headhoncho.app`. `GET /api/v1/leads/{lead_id}` The key needs the **Leads** area at **read**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). Send your key as `Authorization: Bearer hh_live_...`. See [API keys](https://headhoncho.app/docs/api/keys). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `lead_id` | id, in the path | Yes | The lead id, or its number. | `lead_5d21` | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back The lead. stage is new, taken, quoted, won, lost or passed. missing names the facts still needed before a job can be booked. job is set once the lead is booked. history lists what happened, oldest first: at, line and by. It never changes a record. It only reads the companies the key reaches. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `id` | id (text) | The id of this record. Ids are opaque text: keep them exactly as given. | | `number` | whole number | The number people say out loud, such as the job number. | | `ticket` | text | The job number the ticket shows. | | `company` | object | The company. | | `company.id` | id (text) | The id of this record. Ids are opaque text: keep them exactly as given. | | `company.name` | text | The name, as the app shows it. | | `stage` | text | How far along it is, as a code. | | `stage_since` | time (ISO 8601, with offset) | The moment: stage since. Carries its offset from UTC; `Z` is UTC. | | `client_name` | text | The customer's name. Hidden when the key hides personal details. | | `client_phone` | text | The customer's phone number. Hidden when the key hides personal details. | | `address` | object | The address. | | `address.line1` | text | The street address. Hidden when the key hides personal details. | | `address.city` | text | The city. | | `address.state` | text | The state or region. | | `service` | object | The service. | | `service.id` | id (text) | The id of this record. Ids are opaque text: keep them exactly as given. | | `service.name` | text | The name, as the app shows it. | | `wanted_start` | time (ISO 8601, with offset) | The moment: wanted start. Carries its offset from UTC; `Z` is UTC. | | `wanted_end` | time (ISO 8601, with offset) | The moment: wanted end. Carries its offset from UTC; `Z` is UTC. | | `urgent` | true or false | The urgent. | | `notes` | text | Free-text notes. | | `estimate` | object | The estimate. | | `estimate.amount` | money (number) | The amount. In the company's currency. | | `estimate.source` | text | The source. | | `quoted` | value or null | The price quoted for the job. | | `lost_reason` | text | The lost reason. | | `pass_reason` | text | The pass reason. | | `job` | value or null | The job. | | `assigned_to` | value or null | The assigned to. | | `source` | object | The source. | | `source.kind` | text | What sort of thing this is. | | `source.label` | text | The name the app shows for it. | | `source.channel` | value or null | The channel. | | `arrivals` | whole number | The arrivals. | | `arrived_at` | time (ISO 8601, with offset) | When it was arrived. Carries its offset from UTC; `Z` is UTC. | | `missing` | list of text | The missing. | | `ready` | true or false | The ready. | | `archived_at` | time or null | When it was archived. | | `created_at` | time (ISO 8601, with offset) | When it was created. Carries its offset from UTC; `Z` is UTC. | | `history` | list of objects | The history. | | `history[].at` | time (ISO 8601, with offset) | The moment it happened. Carries its offset from UTC; `Z` is UTC. | | `history[].line` | text | The line. | | `history[].by` | value or null | Who did it. A key shows as its name, then "for" and the member it acts as. | ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`not_found`](https://headhoncho.app/docs/api/errors#not_found) | 404 | No such record in the companies this credential reaches. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [List leads](https://headhoncho.app/docs/api/list_leads): Leads in the companies this credential reaches, newest first, with stage, service, estimate and where each came from. - [List needs you](https://headhoncho.app/docs/api/list_needs_you): Jobs that wait on a person, most urgent first, each with the reasons: no technician, unpaid cut, no answer and more. - [List conversion reviews](https://headhoncho.app/docs/api/list_conversion_reviews): Ad clicks the matcher would not guess at. Each waits for you to pick the job it produced, or to reject it. - The same records in the app: [the Leads panel](https://headhoncho.app/docs/marketing/sources). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "id": "lead_5d21", "number": 2041, "ticket": "L-2041", "company": { "id": "cmp_14f5", "name": "Sunrise Moving" }, "stage": "new", "stage_since": "2026-10-24T14:02:11Z", "client_name": "R. Azoulay", "client_phone": "+12175550142", "address": { "line1": "2590 Main St", "city": "Bloomington", "state": "IL" }, "service": { "id": "jt_02", "name": "Local move" }, "wanted_start": "2026-10-30T09:00:00Z", "wanted_end": "2026-10-30T12:00:00Z", "urgent": false, "notes": "Two flights of stairs", "estimate": { "amount": 1200.0, "source": "price_list" }, "quoted": null, "lost_reason": "", "pass_reason": "", "job": null, "assigned_to": null, "source": { "kind": "call", "label": "Voice line", "channel": null }, "arrivals": 1, "arrived_at": "2026-10-24T14:02:11Z", "missing": [ "postal_code" ], "ready": false, "archived_at": null, "created_at": "2026-10-24T14:02:11Z", "history": [ { "at": "2026-10-24T14:02:11Z", "line": "Came in · Voice line", "by": null } ] } ``` ### cURL ```bash curl "https://api.headhoncho.app/api/v1/leads/lead_5d21" \ -H "Authorization: Bearer hh_live_..." ``` ### Python ```python import requests response = requests.get( "https://api.headhoncho.app/api/v1/leads/lead_5d21", headers={"Authorization": "Bearer hh_live_..."}, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/leads/lead_5d21", { headers: { Authorization: "Bearer hh_live_..." }, }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: get_lead Arguments: lead_id (id, required) Access: read on Leads Hints: readOnly=true, destructive=false, idempotent=true, openWorld=false Try asking: "Using HeadHoncho, get lead with lead_id lead_5d21." ``` --- # List needs you List needs you is a read in the HeadHoncho API. Jobs that wait on a person, most urgent first, each with the reasons: no technician, unpaid cut, no answer and more. Page: https://headhoncho.app/docs/api/list_needs_you | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **List needs you**, HeadHoncho API v1. It is a read, sent to the base address `https://api.headhoncho.app`. `GET /api/v1/needs-you` The key needs the **Jobs** area at **read**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). Send your key as `Authorization: Bearer hh_live_...`. See [API keys](https://headhoncho.app/docs/api/keys). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `company_id` | id, in the query | No | One company. Default: every company the credential reaches. | `cmp_14f5` | | `limit` | number, in the query | No | 1 to 200. Default 50. | `50` | | `page` | number, in the query | No | Page number, from 1. | `1` | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back items, most urgent first: job (in the Get a job shape), band (now, today or later), due_at (when the harm lands) and reasons. Each reason has slug, label, severity (danger or warn), verb (the one thing that clears it), band and due_at. count is how many jobs wait in all. Jobs in Trash or Archive never appear. It never changes a record. It only reads the companies the key reaches. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `items` | list of objects | The rows on this page. | | `items[].job` | object | The job. | | `items[].job.id` | id (text) | The id of this record. Ids are opaque text: keep them exactly as given. | | `items[].job.number` | whole number | The number people say out loud, such as the job number. | | `items[].job.status` | object | The job status. | | `items[].job.status.id` | id (text) | The id of this record. Ids are opaque text: keep them exactly as given. | | `items[].job.status.name` | text | The name, as the app shows it. | | `items[].job.status.slug` | text | The same name as a lowercase code word. Match on this, not on the name. | | `items[].job.technicians` | list | The technicians. | | `items[].band` | text | The band. | | `items[].due_at` | time (ISO 8601, with offset) | When the due happened. Carries its offset from UTC; `Z` is UTC. | | `items[].reasons` | list of objects | The reasons. | | `items[].reasons[].slug` | text | The same name as a lowercase code word. Match on this, not on the name. | | `items[].reasons[].label` | text | The name the app shows for it. | | `items[].reasons[].severity` | text | The severity. | | `items[].reasons[].verb` | text | The verb. | | `items[].reasons[].band` | text | The band. | | `items[].reasons[].due_at` | time (ISO 8601, with offset) | When the due happened. Carries its offset from UTC; `Z` is UTC. | | `count` | whole number | How many match in all, across every page. | ## Same reasons as the app The reasons are the app's own catalogue, read with the same rules the Needs you list uses. Reasons a workspace has not switched on are left out, as they are in the app. ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`not_found`](https://headhoncho.app/docs/api/errors#not_found) | 404 | No such record in the companies this credential reaches. | | [`out_of_scope`](https://headhoncho.app/docs/api/errors#out_of_scope) | 404 | No such company in the companies this credential reaches. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [List leads](https://headhoncho.app/docs/api/list_leads): Leads in the companies this credential reaches, newest first, with stage, service, estimate and where each came from. - [Get lead](https://headhoncho.app/docs/api/get_lead): One lead: who, what and when they asked for, the estimate, its stage and what happened to it so far. - [List conversion reviews](https://headhoncho.app/docs/api/list_conversion_reviews): Ad clicks the matcher would not guess at. Each waits for you to pick the job it produced, or to reject it. - The same records in the app: [the Jobs panel](https://headhoncho.app/docs/jobs). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "items": [ { "job": { "id": "job_1138", "number": 1138, "status": { "id": "st_02", "name": "Scheduled", "slug": "scheduled" }, "technicians": [] }, "band": "now", "due_at": "2026-10-26T09:00:00Z", "reasons": [ { "slug": "no_tech", "label": "No tech", "severity": "danger", "verb": "Assign a tech", "band": "now", "due_at": "2026-10-26T09:00:00Z" } ] } ], "count": 1 } ``` ### cURL ```bash curl "https://api.headhoncho.app/api/v1/needs-you?company_id=cmp_14f5&limit=50" \ -H "Authorization: Bearer hh_live_..." ``` ### Python ```python import requests response = requests.get( "https://api.headhoncho.app/api/v1/needs-you", headers={"Authorization": "Bearer hh_live_..."}, params={ "company_id": "cmp_14f5", "limit": "50", }, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/needs-you?company_id=cmp_14f5&limit=50", { headers: { Authorization: "Bearer hh_live_..." }, }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: list_needs_you Arguments: company_id (id, optional), limit (number, optional), page (number, optional) Access: read on Jobs Hints: readOnly=true, destructive=false, idempotent=true, openWorld=false Try asking: "Using HeadHoncho, list needs you with company_id cmp_14f5." ``` --- # List conversion reviews List conversion reviews is a read in the HeadHoncho API. Ad clicks the matcher would not guess at. Each waits for you to pick the job it produced, or to reject it. Page: https://headhoncho.app/docs/api/list_conversion_reviews | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **List conversion reviews**, HeadHoncho API v1. It is a read, sent to the base address `https://api.headhoncho.app`. `GET /api/v1/conversion-reviews` The key needs the **Leads** area at **read**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). Send your key as `Authorization: Bearer hh_live_...`. See [API keys](https://headhoncho.app/docs/api/keys). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `company_id` | id, in the query | No | One company. Default: every company the credential reaches. | `cmp_14f5` | | `limit` | number, in the query | No | 1 to 200. Default 50. | `50` | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back items, newest call first: id (use it as conversion_id in Review a conversion), company_id, network, click_id, call_at, customer_phone, source_label, campaign_label, reason (no_job or ambiguous_job) and candidates: the jobs it might be, each with job_id, job_number, client_name and booked_at. count is how many wait. It never changes a record. It only reads the companies the key reaches. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `items` | list of objects | The rows on this page. | | `items[].id` | id (text) | The id of this record. Ids are opaque text: keep them exactly as given. | | `items[].company_id` | id (text) | The id of the company. | | `items[].network` | text | The ad platform the row came from. | | `items[].click_id` | id (text) | The Google click id (gclid) the call or visit carried. | | `items[].call_at` | time (ISO 8601, with offset) | When the call happened. Carries its offset from UTC; `Z` is UTC. | | `items[].customer_phone` | text | The customer's phone number. Hidden when the key hides personal details. | | `items[].source_label` | text | The source label. | | `items[].campaign_label` | text | The campaign label. | | `items[].reason` | text | The reason given. | | `items[].candidates` | list of objects | The candidates. | | `items[].candidates[].job_id` | id (text) | The id of the job. | | `items[].candidates[].job_number` | whole number | The job number people say out loud. | | `items[].candidates[].client_name` | text | The customer's name. Hidden when the key hides personal details. | | `items[].candidates[].booked_at` | time (ISO 8601, with offset) | When it was booked. Carries its offset from UTC; `Z` is UTC. | | `count` | whole number | How many match in all, across every page. | ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`not_found`](https://headhoncho.app/docs/api/errors#not_found) | 404 | No such record in the companies this credential reaches. | | [`out_of_scope`](https://headhoncho.app/docs/api/errors#out_of_scope) | 404 | No such company in the companies this credential reaches. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [List leads](https://headhoncho.app/docs/api/list_leads): Leads in the companies this credential reaches, newest first, with stage, service, estimate and where each came from. - [Get lead](https://headhoncho.app/docs/api/get_lead): One lead: who, what and when they asked for, the estimate, its stage and what happened to it so far. - [List needs you](https://headhoncho.app/docs/api/list_needs_you): Jobs that wait on a person, most urgent first, each with the reasons: no technician, unpaid cut, no answer and more. - The same records in the app: [the Leads panel](https://headhoncho.app/docs/marketing/sources). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "items": [ { "id": "cnv_7e20", "company_id": "cmp_14f5", "network": "google", "click_id": "Cj0KCQjw...", "call_at": "2026-10-11T18:22:03Z", "customer_phone": "+12175550142", "source_label": "Google Ads", "campaign_label": "Moving, Bloomington", "reason": "ambiguous_job", "candidates": [ { "job_id": "job_1058", "job_number": 1058, "client_name": "E. Shapiro", "booked_at": "2026-09-18T10:46:00Z" } ] } ], "count": 1 } ``` ### cURL ```bash curl "https://api.headhoncho.app/api/v1/conversion-reviews?company_id=cmp_14f5&limit=50" \ -H "Authorization: Bearer hh_live_..." ``` ### Python ```python import requests response = requests.get( "https://api.headhoncho.app/api/v1/conversion-reviews", headers={"Authorization": "Bearer hh_live_..."}, params={ "company_id": "cmp_14f5", "limit": "50", }, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/conversion-reviews?company_id=cmp_14f5&limit=50", { headers: { Authorization: "Bearer hh_live_..." }, }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: list_conversion_reviews Arguments: company_id (id, optional), limit (number, optional) Access: read on Leads Hints: readOnly=true, destructive=false, idempotent=true, openWorld=false Try asking: "Using HeadHoncho, list conversion reviews with company_id cmp_14f5." ``` --- # Create lead Create lead is a command in the HeadHoncho API. Add a lead to one company, the way a person adds one by hand. Send what you know; the rest can be filled in later. Page: https://headhoncho.app/docs/api/create_lead | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **Create lead**, HeadHoncho API v1. It is a command, sent to the base address `https://api.headhoncho.app`. `POST /api/v1/commands/create-lead` The key needs the **Leads** area at **do**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). It runs the app's own command `create-lead`. Send an `Idempotency-Key` header with every call: the same key with the same body returns the first answer and runs nothing twice. See [the model](https://headhoncho.app/docs/api/model#idempotency). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `company_id` | id, in the JSON body | Yes | From Who am I. | `cmp_14f5` | | `client_name` | text, in the JSON body | No | The customer, as they gave it. | `R. Azoulay` | | `client_phone` | text, in the JSON body | No | Any format; stored as E.164. | `+12175550142` | | `address` | object, in the JSON body | No | line1, city, state and postal_code, all four. line2 is optional. | `{"line1": "2590 Main St", "city": "Bloomington", "state": "IL", "postal_code": "61701"}` | | `job_type_id` | id, in the JSON body | No | The service asked for, from Who am I. | `jt_02` | | `wanted_start` | datetime, in the JSON body | No | ISO 8601. When they want it, with wanted_end. | `2026-10-30T09:00:00-05:00` | | `wanted_end` | datetime, in the JSON body | No | ISO 8601. The end of the window. | `2026-10-30T12:00:00-05:00` | | `urgency` | text, in the JSON body | No | urgent, high or normal. One of `urgent`, `high`, `normal`. | `normal` | | `notes` | text, in the JSON body | No | Anything the crew or the office should know. | `Two flights of stairs` | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back accepted, lead_id, ticket (for example L-2041), number, state (new) and position: the event position, usable as after= on the next read. A lead sent twice is two leads, so send it once; the Idempotency-Key protects a retry of the same call. It never deletes anything. It changes only what the command names, and it writes the change to the job's history with who asked for it. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `accepted` | true or false | True when the command ran. A command that cannot run is an error instead. | | `lead_id` | id (text) | The id of the lead. | | `state` | text | The state or region. | | `position` | whole number | Where the change landed in the event log. Pass it as `after` on a read to see your own write. | | `ticket` | text | The job number the ticket shows. | | `number` | whole number | The number people say out loud, such as the job number. | ## Which door this is It is the app's New lead button: a lead typed by hand. It is never kept out by the take rules and no AI reads it. A call or a message from a leads group reaches the app by its own door, not this one. ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`read_only`](https://headhoncho.app/docs/api/errors#read_only) | 403 | This credential may read this area but not change it. | | [`not_found`](https://headhoncho.app/docs/api/errors#not_found) | 404 | No such record in the companies this credential reaches. | | [`out_of_scope`](https://headhoncho.app/docs/api/errors#out_of_scope) | 404 | No such company in the companies this credential reaches. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`missing_idempotency_key`](https://headhoncho.app/docs/api/errors#missing_idempotency_key) | 400 | Send an Idempotency-Key header on every command. | | [`idempotency_mismatch`](https://headhoncho.app/docs/api/errors#idempotency_mismatch) | 409 | This Idempotency-Key was used with a different body. | | [`idempotency_in_progress`](https://headhoncho.app/docs/api/errors#idempotency_in_progress) | 409 | A command with this Idempotency-Key is still running. Wait a moment and send it again. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [Update lead](https://headhoncho.app/docs/api/update_lead): Change what a lead asked for: the customer, the address, the service, the time, the urgency or the notes. Only the fields you send change. - [Mark lead lost](https://headhoncho.app/docs/api/mark_lead_lost): Close an open lead as lost, with the reason. It moves to Archive on the company's own clock. - [Pass lead](https://headhoncho.app/docs/api/pass_lead): Say a new lead is not yours to take, with an optional reason. It leaves the list to answer. - [Book lead](https://headhoncho.app/docs/api/book_lead): Turn a lead into a job with everything the lead holds. The lead becomes won and is linked to the job. - [Dismiss lead](https://headhoncho.app/docs/api/dismiss_lead): Send a lead to Trash as a mistake. It counts nowhere and is erased after 30 days. - [Review conversion](https://headhoncho.app/docs/api/review_conversion): Decide an ad click the matcher would not guess at: pick the job it produced, or reject it. Only then does it reach the Google file. - [Schedule follow up](https://headhoncho.app/docs/api/schedule_follow_up): Book a date to chase a job or a draft lead again. The job moves onto Follow up when the company has that status. - [Update follow up](https://headhoncho.app/docs/api/update_follow_up): Move the date of an open follow-up, or change why it is open. - [Resolve follow up](https://headhoncho.app/docs/api/resolve_follow_up): Say the chase happened. The follow-up is closed, and the job goes back to the line when it was the last stop. - [Cancel follow up](https://headhoncho.app/docs/api/cancel_follow_up): Call off a follow-up that should never have been booked. It is removed, and no chase is recorded. - The same records in the app: [the Leads panel](https://headhoncho.app/docs/marketing/sources). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "accepted": true, "lead_id": "lead_5d21", "state": "new", "position": 88601, "ticket": "L-2041", "number": 2041 } ``` ### cURL ```bash curl -X POST "https://api.headhoncho.app/api/v1/commands/create-lead" \ -H "Authorization: Bearer hh_live_..." \ -H "Idempotency-Key: 6f1d2c9e-1b7a-4c1e-9a52-0d3f8e4b7a10" \ -H "Content-Type: application/json" \ -d '{ "company_id": "cmp_14f5", "client_name": "R. Azoulay", "client_phone": "+12175550142", "address": { "line1": "2590 Main St", "city": "Bloomington", "state": "IL", "postal_code": "61701" }, "job_type_id": "jt_02", "wanted_start": "2026-10-30T09:00:00-05:00", "wanted_end": "2026-10-30T12:00:00-05:00", "urgency": "normal", "notes": "Two flights of stairs" }' ``` ### Python ```python import requests import uuid response = requests.post( "https://api.headhoncho.app/api/v1/commands/create-lead", headers={ "Authorization": "Bearer hh_live_...", "Idempotency-Key": str(uuid.uuid4()), }, json={ "company_id": "cmp_14f5", "client_name": "R. Azoulay", "client_phone": "+12175550142", "address": { "line1": "2590 Main St", "city": "Bloomington", "state": "IL", "postal_code": "61701", }, "job_type_id": "jt_02", "wanted_start": "2026-10-30T09:00:00-05:00", "wanted_end": "2026-10-30T12:00:00-05:00", "urgency": "normal", "notes": "Two flights of stairs", }, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/commands/create-lead", { method: "POST", headers: { Authorization: "Bearer hh_live_...", "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "company_id": "cmp_14f5", "client_name": "R. Azoulay", "client_phone": "+12175550142", "address": { "line1": "2590 Main St", "city": "Bloomington", "state": "IL", "postal_code": "61701" }, "job_type_id": "jt_02", "wanted_start": "2026-10-30T09:00:00-05:00", "wanted_end": "2026-10-30T12:00:00-05:00", "urgency": "normal", "notes": "Two flights of stairs" }), }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: create_lead Arguments: company_id (id, required), client_name (text, optional), client_phone (text, optional), address (object, optional), job_type_id (id, optional), wanted_start (datetime, optional), wanted_end (datetime, optional), urgency (text, optional), notes (text, optional) Access: do on Leads Hints: readOnly=false, destructive=false, idempotent=false, openWorld=false Try asking: "Using HeadHoncho, create lead with company_id cmp_14f5 and client_name R. Azoulay." ``` --- # Update lead Update lead is a command in the HeadHoncho API. Change what a lead asked for: the customer, the address, the service, the time, the urgency or the notes. Only the fields you send change. Page: https://headhoncho.app/docs/api/update_lead | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **Update lead**, HeadHoncho API v1. It is a command, sent to the base address `https://api.headhoncho.app`. `POST /api/v1/commands/update-lead` The key needs the **Leads** area at **do**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). It runs the app's own command `update-lead`. Send an `Idempotency-Key` header with every call: the same key with the same body returns the first answer and runs nothing twice. See [the model](https://headhoncho.app/docs/api/model#idempotency). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `lead_id` | id, in the JSON body | Yes | The lead id, or its number. | `lead_5d21` | | `client_name` | text, in the JSON body | No | The customer. | None | | `client_phone` | text, in the JSON body | No | Any format; stored as E.164. | None | | `address` | object, in the JSON body | No | All four parts, as for Send in a lead. Send null to clear it. | None | | `job_type_id` | id, in the JSON body | No | The service, from Who am I. Send null to clear it. | None | | `wanted_start` | datetime, in the JSON body | No | ISO 8601, with wanted_end. Send null to clear the window. | None | | `wanted_end` | datetime, in the JSON body | No | ISO 8601. The end of the window. | None | | `urgency` | text, in the JSON body | No | urgent, high or normal. One of `urgent`, `high`, `normal`. | None | | `notes` | text, in the JSON body | No | Replaces the notes. | None | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back accepted, lead_id, state, position and changed: the fields that moved. A lead that is won, lost, archived or in Trash is refused with 422, because it is closed. It never deletes anything. It changes only what the command names, and it writes the change to the job's history with who asked for it. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `accepted` | true or false | True when the command ran. A command that cannot run is an error instead. | | `lead_id` | id (text) | The id of the lead. | | `state` | text | The state or region. | | `position` | whole number | Where the change landed in the event log. Pass it as `after` on a read to see your own write. | | `changed` | list of text | The changed. | ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`read_only`](https://headhoncho.app/docs/api/errors#read_only) | 403 | This credential may read this area but not change it. | | [`not_found`](https://headhoncho.app/docs/api/errors#not_found) | 404 | No such record in the companies this credential reaches. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`missing_idempotency_key`](https://headhoncho.app/docs/api/errors#missing_idempotency_key) | 400 | Send an Idempotency-Key header on every command. | | [`idempotency_mismatch`](https://headhoncho.app/docs/api/errors#idempotency_mismatch) | 409 | This Idempotency-Key was used with a different body. | | [`idempotency_in_progress`](https://headhoncho.app/docs/api/errors#idempotency_in_progress) | 409 | A command with this Idempotency-Key is still running. Wait a moment and send it again. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [Create lead](https://headhoncho.app/docs/api/create_lead): Add a lead to one company, the way a person adds one by hand. Send what you know; the rest can be filled in later. - [Mark lead lost](https://headhoncho.app/docs/api/mark_lead_lost): Close an open lead as lost, with the reason. It moves to Archive on the company's own clock. - [Pass lead](https://headhoncho.app/docs/api/pass_lead): Say a new lead is not yours to take, with an optional reason. It leaves the list to answer. - [Book lead](https://headhoncho.app/docs/api/book_lead): Turn a lead into a job with everything the lead holds. The lead becomes won and is linked to the job. - [Dismiss lead](https://headhoncho.app/docs/api/dismiss_lead): Send a lead to Trash as a mistake. It counts nowhere and is erased after 30 days. - [Review conversion](https://headhoncho.app/docs/api/review_conversion): Decide an ad click the matcher would not guess at: pick the job it produced, or reject it. Only then does it reach the Google file. - [Schedule follow up](https://headhoncho.app/docs/api/schedule_follow_up): Book a date to chase a job or a draft lead again. The job moves onto Follow up when the company has that status. - [Update follow up](https://headhoncho.app/docs/api/update_follow_up): Move the date of an open follow-up, or change why it is open. - [Resolve follow up](https://headhoncho.app/docs/api/resolve_follow_up): Say the chase happened. The follow-up is closed, and the job goes back to the line when it was the last stop. - [Cancel follow up](https://headhoncho.app/docs/api/cancel_follow_up): Call off a follow-up that should never have been booked. It is removed, and no chase is recorded. - The same records in the app: [the Leads panel](https://headhoncho.app/docs/marketing/sources). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "accepted": true, "lead_id": "lead_5d21", "state": "new", "position": 88601, "changed": [ "notes", "wanted_start", "wanted_end" ] } ``` ### cURL ```bash curl -X POST "https://api.headhoncho.app/api/v1/commands/update-lead" \ -H "Authorization: Bearer hh_live_..." \ -H "Idempotency-Key: 6f1d2c9e-1b7a-4c1e-9a52-0d3f8e4b7a10" \ -H "Content-Type: application/json" \ -d '{ "lead_id": "lead_5d21" }' ``` ### Python ```python import requests import uuid response = requests.post( "https://api.headhoncho.app/api/v1/commands/update-lead", headers={ "Authorization": "Bearer hh_live_...", "Idempotency-Key": str(uuid.uuid4()), }, json={ "lead_id": "lead_5d21", }, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/commands/update-lead", { method: "POST", headers: { Authorization: "Bearer hh_live_...", "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "lead_id": "lead_5d21" }), }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: update_lead Arguments: lead_id (id, required), client_name (text, optional), client_phone (text, optional), address (object, optional), job_type_id (id, optional), wanted_start (datetime, optional), wanted_end (datetime, optional), urgency (text, optional), notes (text, optional) Access: do on Leads Hints: readOnly=false, destructive=false, idempotent=true, openWorld=false Try asking: "Using HeadHoncho, update lead with lead_id lead_5d21." ``` --- # Mark lead lost Mark lead lost is a command in the HeadHoncho API. Close an open lead as lost, with the reason. It moves to Archive on the company's own clock. Page: https://headhoncho.app/docs/api/mark_lead_lost | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **Mark lead lost**, HeadHoncho API v1. It is a command, sent to the base address `https://api.headhoncho.app`. `POST /api/v1/commands/mark-lead-lost` The key needs the **Leads** area at **do**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). It runs the app's own command `mark-lead-lost`. Send an `Idempotency-Key` header with every call: the same key with the same body returns the first answer and runs nothing twice. See [the model](https://headhoncho.app/docs/api/model#idempotency). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `lead_id` | id, in the JSON body | Yes | The lead id, or its number. | `lead_5d21` | | `reason` | text, in the JSON body | Yes | Why it was lost. One of `price`, `timing`, `no_answer`, `went_elsewhere`, `not_our_work`. | `price` | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back accepted, lead_id, state (lost) and position. Only a lead that is new, taken or quoted can be marked lost; any other is refused with 422. It never deletes anything. It changes only what the command names, and it writes the change to the job's history with who asked for it. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `accepted` | true or false | True when the command ran. A command that cannot run is an error instead. | | `lead_id` | id (text) | The id of the lead. | | `state` | text | The state or region. | | `position` | whole number | Where the change landed in the event log. Pass it as `after` on a read to see your own write. | ## Setting an outcome A lead ends three ways: booked as a job (Book a lead as a job), lost (this call) or passed (Pass on a lead). ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`read_only`](https://headhoncho.app/docs/api/errors#read_only) | 403 | This credential may read this area but not change it. | | [`not_found`](https://headhoncho.app/docs/api/errors#not_found) | 404 | No such record in the companies this credential reaches. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`missing_idempotency_key`](https://headhoncho.app/docs/api/errors#missing_idempotency_key) | 400 | Send an Idempotency-Key header on every command. | | [`idempotency_mismatch`](https://headhoncho.app/docs/api/errors#idempotency_mismatch) | 409 | This Idempotency-Key was used with a different body. | | [`idempotency_in_progress`](https://headhoncho.app/docs/api/errors#idempotency_in_progress) | 409 | A command with this Idempotency-Key is still running. Wait a moment and send it again. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [Create lead](https://headhoncho.app/docs/api/create_lead): Add a lead to one company, the way a person adds one by hand. Send what you know; the rest can be filled in later. - [Update lead](https://headhoncho.app/docs/api/update_lead): Change what a lead asked for: the customer, the address, the service, the time, the urgency or the notes. Only the fields you send change. - [Pass lead](https://headhoncho.app/docs/api/pass_lead): Say a new lead is not yours to take, with an optional reason. It leaves the list to answer. - [Book lead](https://headhoncho.app/docs/api/book_lead): Turn a lead into a job with everything the lead holds. The lead becomes won and is linked to the job. - [Dismiss lead](https://headhoncho.app/docs/api/dismiss_lead): Send a lead to Trash as a mistake. It counts nowhere and is erased after 30 days. - [Review conversion](https://headhoncho.app/docs/api/review_conversion): Decide an ad click the matcher would not guess at: pick the job it produced, or reject it. Only then does it reach the Google file. - [Schedule follow up](https://headhoncho.app/docs/api/schedule_follow_up): Book a date to chase a job or a draft lead again. The job moves onto Follow up when the company has that status. - [Update follow up](https://headhoncho.app/docs/api/update_follow_up): Move the date of an open follow-up, or change why it is open. - [Resolve follow up](https://headhoncho.app/docs/api/resolve_follow_up): Say the chase happened. The follow-up is closed, and the job goes back to the line when it was the last stop. - [Cancel follow up](https://headhoncho.app/docs/api/cancel_follow_up): Call off a follow-up that should never have been booked. It is removed, and no chase is recorded. - The same records in the app: [the Leads panel](https://headhoncho.app/docs/marketing/sources). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "accepted": true, "lead_id": "lead_5d21", "state": "lost", "position": 88601 } ``` ### cURL ```bash curl -X POST "https://api.headhoncho.app/api/v1/commands/mark-lead-lost" \ -H "Authorization: Bearer hh_live_..." \ -H "Idempotency-Key: 6f1d2c9e-1b7a-4c1e-9a52-0d3f8e4b7a10" \ -H "Content-Type: application/json" \ -d '{ "lead_id": "lead_5d21", "reason": "price" }' ``` ### Python ```python import requests import uuid response = requests.post( "https://api.headhoncho.app/api/v1/commands/mark-lead-lost", headers={ "Authorization": "Bearer hh_live_...", "Idempotency-Key": str(uuid.uuid4()), }, json={ "lead_id": "lead_5d21", "reason": "price", }, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/commands/mark-lead-lost", { method: "POST", headers: { Authorization: "Bearer hh_live_...", "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "lead_id": "lead_5d21", "reason": "price" }), }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: mark_lead_lost Arguments: lead_id (id, required), reason (text, required) Access: do on Leads Hints: readOnly=false, destructive=false, idempotent=true, openWorld=false Try asking: "Using HeadHoncho, mark lead lost with lead_id lead_5d21 and reason price." ``` --- # Pass lead Pass lead is a command in the HeadHoncho API. Say a new lead is not yours to take, with an optional reason. It leaves the list to answer. Page: https://headhoncho.app/docs/api/pass_lead | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **Pass lead**, HeadHoncho API v1. It is a command, sent to the base address `https://api.headhoncho.app`. `POST /api/v1/commands/pass-lead` The key needs the **Leads** area at **do**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). It runs the app's own command `pass-lead`. Send an `Idempotency-Key` header with every call: the same key with the same body returns the first answer and runs nothing twice. See [the model](https://headhoncho.app/docs/api/model#idempotency). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `lead_id` | id, in the JSON body | Yes | The lead id, or its number. | `lead_5d21` | | `reason` | text, in the JSON body | No | Optional. Leave empty to skip the reason. One of `no_time`, `too_far`, `too_small`, `too_long`, `not_our_work`, `already_gone`, `price`. | `too_far` | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back accepted, lead_id, state (passed) and position. Only a new lead can be passed. A reason outside the app's list is refused with 422. It never deletes anything. It changes only what the command names, and it writes the change to the job's history with who asked for it. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `accepted` | true or false | True when the command ran. A command that cannot run is an error instead. | | `lead_id` | id (text) | The id of the lead. | | `state` | text | The state or region. | | `position` | whole number | Where the change landed in the event log. Pass it as `after` on a read to see your own write. | ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`read_only`](https://headhoncho.app/docs/api/errors#read_only) | 403 | This credential may read this area but not change it. | | [`not_found`](https://headhoncho.app/docs/api/errors#not_found) | 404 | No such record in the companies this credential reaches. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`missing_idempotency_key`](https://headhoncho.app/docs/api/errors#missing_idempotency_key) | 400 | Send an Idempotency-Key header on every command. | | [`idempotency_mismatch`](https://headhoncho.app/docs/api/errors#idempotency_mismatch) | 409 | This Idempotency-Key was used with a different body. | | [`idempotency_in_progress`](https://headhoncho.app/docs/api/errors#idempotency_in_progress) | 409 | A command with this Idempotency-Key is still running. Wait a moment and send it again. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [Create lead](https://headhoncho.app/docs/api/create_lead): Add a lead to one company, the way a person adds one by hand. Send what you know; the rest can be filled in later. - [Update lead](https://headhoncho.app/docs/api/update_lead): Change what a lead asked for: the customer, the address, the service, the time, the urgency or the notes. Only the fields you send change. - [Mark lead lost](https://headhoncho.app/docs/api/mark_lead_lost): Close an open lead as lost, with the reason. It moves to Archive on the company's own clock. - [Book lead](https://headhoncho.app/docs/api/book_lead): Turn a lead into a job with everything the lead holds. The lead becomes won and is linked to the job. - [Dismiss lead](https://headhoncho.app/docs/api/dismiss_lead): Send a lead to Trash as a mistake. It counts nowhere and is erased after 30 days. - [Review conversion](https://headhoncho.app/docs/api/review_conversion): Decide an ad click the matcher would not guess at: pick the job it produced, or reject it. Only then does it reach the Google file. - [Schedule follow up](https://headhoncho.app/docs/api/schedule_follow_up): Book a date to chase a job or a draft lead again. The job moves onto Follow up when the company has that status. - [Update follow up](https://headhoncho.app/docs/api/update_follow_up): Move the date of an open follow-up, or change why it is open. - [Resolve follow up](https://headhoncho.app/docs/api/resolve_follow_up): Say the chase happened. The follow-up is closed, and the job goes back to the line when it was the last stop. - [Cancel follow up](https://headhoncho.app/docs/api/cancel_follow_up): Call off a follow-up that should never have been booked. It is removed, and no chase is recorded. - The same records in the app: [the Leads panel](https://headhoncho.app/docs/marketing/sources). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "accepted": true, "lead_id": "lead_5d21", "state": "passed", "position": 88601 } ``` ### cURL ```bash curl -X POST "https://api.headhoncho.app/api/v1/commands/pass-lead" \ -H "Authorization: Bearer hh_live_..." \ -H "Idempotency-Key: 6f1d2c9e-1b7a-4c1e-9a52-0d3f8e4b7a10" \ -H "Content-Type: application/json" \ -d '{ "lead_id": "lead_5d21", "reason": "too_far" }' ``` ### Python ```python import requests import uuid response = requests.post( "https://api.headhoncho.app/api/v1/commands/pass-lead", headers={ "Authorization": "Bearer hh_live_...", "Idempotency-Key": str(uuid.uuid4()), }, json={ "lead_id": "lead_5d21", "reason": "too_far", }, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/commands/pass-lead", { method: "POST", headers: { Authorization: "Bearer hh_live_...", "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "lead_id": "lead_5d21", "reason": "too_far" }), }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: pass_lead Arguments: lead_id (id, required), reason (text, optional) Access: do on Leads Hints: readOnly=false, destructive=false, idempotent=true, openWorld=false Try asking: "Using HeadHoncho, pass lead with lead_id lead_5d21 and reason too_far." ``` --- # Book lead Book lead is a command in the HeadHoncho API. Turn a lead into a job with everything the lead holds. The lead becomes won and is linked to the job. Page: https://headhoncho.app/docs/api/book_lead | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **Book lead**, HeadHoncho API v1. It is a command, sent to the base address `https://api.headhoncho.app`. `POST /api/v1/commands/make-job-from-lead` The key needs the **Leads** area at **do**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). It runs the app's own command `make-job-from-lead`. Send an `Idempotency-Key` header with every call: the same key with the same body returns the first answer and runs nothing twice. See [the model](https://headhoncho.app/docs/api/model#idempotency). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `lead_id` | id, in the JSON body | Yes | The lead id, or its number. | `lead_5d21` | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back accepted, lead_id, state (won), job_id, job_number and position. If the address, the service or the time window is missing, the job opens as a draft, as it does in the app. A lead that is already won or passed is refused with 422, so booking twice makes one job. It never deletes anything. It changes only what the command names, and it writes the change to the job's history with who asked for it. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `accepted` | true or false | True when the command ran. A command that cannot run is an error instead. | | `lead_id` | id (text) | The id of the lead. | | `state` | text | The state or region. | | `position` | whole number | Where the change landed in the event log. Pass it as `after` on a read to see your own write. | | `job_id` | id (text) | The id of the job. | | `job_number` | whole number | The job number people say out loud. | ## One job per lead A won lead cannot be booked again. The job carries the quoted price when the lead was quoted, never the estimate. ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`read_only`](https://headhoncho.app/docs/api/errors#read_only) | 403 | This credential may read this area but not change it. | | [`not_found`](https://headhoncho.app/docs/api/errors#not_found) | 404 | No such record in the companies this credential reaches. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`missing_idempotency_key`](https://headhoncho.app/docs/api/errors#missing_idempotency_key) | 400 | Send an Idempotency-Key header on every command. | | [`idempotency_mismatch`](https://headhoncho.app/docs/api/errors#idempotency_mismatch) | 409 | This Idempotency-Key was used with a different body. | | [`idempotency_in_progress`](https://headhoncho.app/docs/api/errors#idempotency_in_progress) | 409 | A command with this Idempotency-Key is still running. Wait a moment and send it again. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [Create lead](https://headhoncho.app/docs/api/create_lead): Add a lead to one company, the way a person adds one by hand. Send what you know; the rest can be filled in later. - [Update lead](https://headhoncho.app/docs/api/update_lead): Change what a lead asked for: the customer, the address, the service, the time, the urgency or the notes. Only the fields you send change. - [Mark lead lost](https://headhoncho.app/docs/api/mark_lead_lost): Close an open lead as lost, with the reason. It moves to Archive on the company's own clock. - [Pass lead](https://headhoncho.app/docs/api/pass_lead): Say a new lead is not yours to take, with an optional reason. It leaves the list to answer. - [Dismiss lead](https://headhoncho.app/docs/api/dismiss_lead): Send a lead to Trash as a mistake. It counts nowhere and is erased after 30 days. - [Review conversion](https://headhoncho.app/docs/api/review_conversion): Decide an ad click the matcher would not guess at: pick the job it produced, or reject it. Only then does it reach the Google file. - [Schedule follow up](https://headhoncho.app/docs/api/schedule_follow_up): Book a date to chase a job or a draft lead again. The job moves onto Follow up when the company has that status. - [Update follow up](https://headhoncho.app/docs/api/update_follow_up): Move the date of an open follow-up, or change why it is open. - [Resolve follow up](https://headhoncho.app/docs/api/resolve_follow_up): Say the chase happened. The follow-up is closed, and the job goes back to the line when it was the last stop. - [Cancel follow up](https://headhoncho.app/docs/api/cancel_follow_up): Call off a follow-up that should never have been booked. It is removed, and no chase is recorded. - The same records in the app: [the Leads panel](https://headhoncho.app/docs/marketing/sources). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "accepted": true, "lead_id": "lead_5d21", "state": "won", "position": 88601, "job_id": "job_1203", "job_number": 1203 } ``` ### cURL ```bash curl -X POST "https://api.headhoncho.app/api/v1/commands/make-job-from-lead" \ -H "Authorization: Bearer hh_live_..." \ -H "Idempotency-Key: 6f1d2c9e-1b7a-4c1e-9a52-0d3f8e4b7a10" \ -H "Content-Type: application/json" \ -d '{ "lead_id": "lead_5d21" }' ``` ### Python ```python import requests import uuid response = requests.post( "https://api.headhoncho.app/api/v1/commands/make-job-from-lead", headers={ "Authorization": "Bearer hh_live_...", "Idempotency-Key": str(uuid.uuid4()), }, json={ "lead_id": "lead_5d21", }, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/commands/make-job-from-lead", { method: "POST", headers: { Authorization: "Bearer hh_live_...", "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "lead_id": "lead_5d21" }), }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: book_lead Arguments: lead_id (id, required) Access: do on Leads Hints: readOnly=false, destructive=false, idempotent=true, openWorld=false Try asking: "Using HeadHoncho, book lead with lead_id lead_5d21." ``` --- # Dismiss lead Dismiss lead is a command in the HeadHoncho API. Send a lead to Trash as a mistake. It counts nowhere and is erased after 30 days. Page: https://headhoncho.app/docs/api/dismiss_lead | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **Dismiss lead**, HeadHoncho API v1. It is a command, sent to the base address `https://api.headhoncho.app`. `POST /api/v1/commands/trash-leads` The key needs the **Leads** area at **do**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). It runs the app's own command `trash-leads`. Send an `Idempotency-Key` header with every call: the same key with the same body returns the first answer and runs nothing twice. See [the model](https://headhoncho.app/docs/api/model#idempotency). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `lead_id` | id, in the JSON body | Yes | The lead id, or its number. | `lead_5d21` | | `reason` | text, in the JSON body | Yes | Why it is a mistake. One of `spam`, `duplicate`, `test`, `mistake`. | `spam` | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back accepted, lead_id, state (trashed) and position. A lead in Trash is no longer listed here. Use Mark a lead lost or Pass on a lead for a real lead you do not win. It never deletes anything. It changes only what the command names, and it writes the change to the job's history with who asked for it. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `accepted` | true or false | True when the command ran. A command that cannot run is an error instead. | | `lead_id` | id (text) | The id of the lead. | | `state` | text | The state or region. | | `position` | whole number | Where the change landed in the event log. Pass it as `after` on a read to see your own write. | ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`read_only`](https://headhoncho.app/docs/api/errors#read_only) | 403 | This credential may read this area but not change it. | | [`not_found`](https://headhoncho.app/docs/api/errors#not_found) | 404 | No such record in the companies this credential reaches. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`missing_idempotency_key`](https://headhoncho.app/docs/api/errors#missing_idempotency_key) | 400 | Send an Idempotency-Key header on every command. | | [`idempotency_mismatch`](https://headhoncho.app/docs/api/errors#idempotency_mismatch) | 409 | This Idempotency-Key was used with a different body. | | [`idempotency_in_progress`](https://headhoncho.app/docs/api/errors#idempotency_in_progress) | 409 | A command with this Idempotency-Key is still running. Wait a moment and send it again. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [Create lead](https://headhoncho.app/docs/api/create_lead): Add a lead to one company, the way a person adds one by hand. Send what you know; the rest can be filled in later. - [Update lead](https://headhoncho.app/docs/api/update_lead): Change what a lead asked for: the customer, the address, the service, the time, the urgency or the notes. Only the fields you send change. - [Mark lead lost](https://headhoncho.app/docs/api/mark_lead_lost): Close an open lead as lost, with the reason. It moves to Archive on the company's own clock. - [Pass lead](https://headhoncho.app/docs/api/pass_lead): Say a new lead is not yours to take, with an optional reason. It leaves the list to answer. - [Book lead](https://headhoncho.app/docs/api/book_lead): Turn a lead into a job with everything the lead holds. The lead becomes won and is linked to the job. - [Review conversion](https://headhoncho.app/docs/api/review_conversion): Decide an ad click the matcher would not guess at: pick the job it produced, or reject it. Only then does it reach the Google file. - [Schedule follow up](https://headhoncho.app/docs/api/schedule_follow_up): Book a date to chase a job or a draft lead again. The job moves onto Follow up when the company has that status. - [Update follow up](https://headhoncho.app/docs/api/update_follow_up): Move the date of an open follow-up, or change why it is open. - [Resolve follow up](https://headhoncho.app/docs/api/resolve_follow_up): Say the chase happened. The follow-up is closed, and the job goes back to the line when it was the last stop. - [Cancel follow up](https://headhoncho.app/docs/api/cancel_follow_up): Call off a follow-up that should never have been booked. It is removed, and no chase is recorded. - The same records in the app: [the Leads panel](https://headhoncho.app/docs/marketing/sources). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "accepted": true, "lead_id": "lead_5d21", "state": "trashed", "position": 88620 } ``` ### cURL ```bash curl -X POST "https://api.headhoncho.app/api/v1/commands/trash-leads" \ -H "Authorization: Bearer hh_live_..." \ -H "Idempotency-Key: 6f1d2c9e-1b7a-4c1e-9a52-0d3f8e4b7a10" \ -H "Content-Type: application/json" \ -d '{ "lead_id": "lead_5d21", "reason": "spam" }' ``` ### Python ```python import requests import uuid response = requests.post( "https://api.headhoncho.app/api/v1/commands/trash-leads", headers={ "Authorization": "Bearer hh_live_...", "Idempotency-Key": str(uuid.uuid4()), }, json={ "lead_id": "lead_5d21", "reason": "spam", }, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/commands/trash-leads", { method: "POST", headers: { Authorization: "Bearer hh_live_...", "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "lead_id": "lead_5d21", "reason": "spam" }), }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: dismiss_lead Arguments: lead_id (id, required), reason (text, required) Access: do on Leads Hints: readOnly=false, destructive=true, idempotent=true, openWorld=false Try asking: "Using HeadHoncho, dismiss lead with lead_id lead_5d21 and reason spam." ``` --- # Review conversion Review conversion is a command in the HeadHoncho API. Decide an ad click the matcher would not guess at: pick the job it produced, or reject it. Only then does it reach the Google file. Page: https://headhoncho.app/docs/api/review_conversion | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **Review conversion**, HeadHoncho API v1. It is a command, sent to the base address `https://api.headhoncho.app`. `POST /api/v1/commands/review-conversion` The key needs the **Leads** area at **do**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). It runs the app's own command `review-conversion`. Send an `Idempotency-Key` header with every call: the same key with the same body returns the first answer and runs nothing twice. See [the model](https://headhoncho.app/docs/api/model#idempotency). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `conversion_id` | id, in the JSON body | Yes | From Conversions waiting for a person. | `cnv_7e20` | | `decision` | text, in the JSON body | Yes | include (the click produced a job) or reject. One of `include`, `reject`. | `include` | | `job_id` | id, in the JSON body | No | The job it produced. Required for include. | `job_1058` | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back accepted, conversion_id, state (matched or excluded) and position. A job that already holds another click, or that is in Trash, is refused with 422. It never deletes anything. It changes only what the command names, and it writes the change to the job's history with who asked for it. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `accepted` | true or false | True when the command ran. A command that cannot run is an error instead. | | `conversion_id` | id (text) | The id of the conversion. | | `state` | text | The state or region. | | `position` | whole number | Where the change landed in the event log. Pass it as `after` on a read to see your own write. | ## Why this is a leads command The app puts the review queue on the Leads panel, so it needs Leads access at do. The click ID area is read-only by nature and cannot hold it. ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`read_only`](https://headhoncho.app/docs/api/errors#read_only) | 403 | This credential may read this area but not change it. | | [`not_found`](https://headhoncho.app/docs/api/errors#not_found) | 404 | No such record in the companies this credential reaches. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`missing_idempotency_key`](https://headhoncho.app/docs/api/errors#missing_idempotency_key) | 400 | Send an Idempotency-Key header on every command. | | [`idempotency_mismatch`](https://headhoncho.app/docs/api/errors#idempotency_mismatch) | 409 | This Idempotency-Key was used with a different body. | | [`idempotency_in_progress`](https://headhoncho.app/docs/api/errors#idempotency_in_progress) | 409 | A command with this Idempotency-Key is still running. Wait a moment and send it again. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [Create lead](https://headhoncho.app/docs/api/create_lead): Add a lead to one company, the way a person adds one by hand. Send what you know; the rest can be filled in later. - [Update lead](https://headhoncho.app/docs/api/update_lead): Change what a lead asked for: the customer, the address, the service, the time, the urgency or the notes. Only the fields you send change. - [Mark lead lost](https://headhoncho.app/docs/api/mark_lead_lost): Close an open lead as lost, with the reason. It moves to Archive on the company's own clock. - [Pass lead](https://headhoncho.app/docs/api/pass_lead): Say a new lead is not yours to take, with an optional reason. It leaves the list to answer. - [Book lead](https://headhoncho.app/docs/api/book_lead): Turn a lead into a job with everything the lead holds. The lead becomes won and is linked to the job. - [Dismiss lead](https://headhoncho.app/docs/api/dismiss_lead): Send a lead to Trash as a mistake. It counts nowhere and is erased after 30 days. - [Schedule follow up](https://headhoncho.app/docs/api/schedule_follow_up): Book a date to chase a job or a draft lead again. The job moves onto Follow up when the company has that status. - [Update follow up](https://headhoncho.app/docs/api/update_follow_up): Move the date of an open follow-up, or change why it is open. - [Resolve follow up](https://headhoncho.app/docs/api/resolve_follow_up): Say the chase happened. The follow-up is closed, and the job goes back to the line when it was the last stop. - [Cancel follow up](https://headhoncho.app/docs/api/cancel_follow_up): Call off a follow-up that should never have been booked. It is removed, and no chase is recorded. - The same records in the app: [the Leads panel](https://headhoncho.app/docs/marketing/sources). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "accepted": true, "conversion_id": "cnv_7e20", "state": "matched", "position": 88630 } ``` ### cURL ```bash curl -X POST "https://api.headhoncho.app/api/v1/commands/review-conversion" \ -H "Authorization: Bearer hh_live_..." \ -H "Idempotency-Key: 6f1d2c9e-1b7a-4c1e-9a52-0d3f8e4b7a10" \ -H "Content-Type: application/json" \ -d '{ "conversion_id": "cnv_7e20", "decision": "include", "job_id": "job_1058" }' ``` ### Python ```python import requests import uuid response = requests.post( "https://api.headhoncho.app/api/v1/commands/review-conversion", headers={ "Authorization": "Bearer hh_live_...", "Idempotency-Key": str(uuid.uuid4()), }, json={ "conversion_id": "cnv_7e20", "decision": "include", "job_id": "job_1058", }, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/commands/review-conversion", { method: "POST", headers: { Authorization: "Bearer hh_live_...", "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "conversion_id": "cnv_7e20", "decision": "include", "job_id": "job_1058" }), }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: review_conversion Arguments: conversion_id (id, required), decision (text, required), job_id (id, optional) Access: do on Leads Hints: readOnly=false, destructive=false, idempotent=true, openWorld=false Try asking: "Using HeadHoncho, review conversion with conversion_id cnv_7e20 and decision include and job_id job_1058." ``` --- # Schedule follow up Schedule follow up is a command in the HeadHoncho API. Book a date to chase a job or a draft lead again. The job moves onto Follow up when the company has that status. Page: https://headhoncho.app/docs/api/schedule_follow_up | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **Schedule follow up**, HeadHoncho API v1. It is a command, sent to the base address `https://api.headhoncho.app`. `POST /api/v1/commands/schedule-follow-up` The key needs the **Jobs** area at **do**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). It runs the app's own command `schedule-follow-up`. Send an `Idempotency-Key` header with every call: the same key with the same body returns the first answer and runs nothing twice. See [the model](https://headhoncho.app/docs/api/model#idempotency). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `job_id` | id, in the JSON body | Yes | The job id, or its number. | `job_1138` | | `due_at` | datetime, in the JSON body | Yes | ISO 8601. When to chase. | `2026-10-28T10:00:00-05:00` | | `reason` | text, in the JSON body | No | Why it is open. Up to 200 characters. | `Waiting on the quote` | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back accepted, job_id, number, follow_up_id, status_id and position. A job on the line moves to Follow up, and a finished job reopens onto it. A job already on a detour keeps its status and gains one more stop. It never deletes anything. It changes only what the command names, and it writes the change to the job's history with who asked for it. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `accepted` | true or false | True when the command ran. A command that cannot run is an error instead. | | `job_id` | id (text) | The id of the job. | | `number` | whole number | The number people say out loud, such as the job number. | | `follow_up_id` | id (text) | The id of the follow up. | | `status_id` | id (text) | The id of the status. | | `position` | whole number | Where the change landed in the event log. Pass it as `after` on a read to see your own write. | ## Jobs, not the Leads panel A follow-up belongs to a job. A lead that has been booked as a draft job takes one; a lead still in the Leads list does not. ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`read_only`](https://headhoncho.app/docs/api/errors#read_only) | 403 | This credential may read this area but not change it. | | [`not_found`](https://headhoncho.app/docs/api/errors#not_found) | 404 | No such record in the companies this credential reaches. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`missing_idempotency_key`](https://headhoncho.app/docs/api/errors#missing_idempotency_key) | 400 | Send an Idempotency-Key header on every command. | | [`idempotency_mismatch`](https://headhoncho.app/docs/api/errors#idempotency_mismatch) | 409 | This Idempotency-Key was used with a different body. | | [`idempotency_in_progress`](https://headhoncho.app/docs/api/errors#idempotency_in_progress) | 409 | A command with this Idempotency-Key is still running. Wait a moment and send it again. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [Create lead](https://headhoncho.app/docs/api/create_lead): Add a lead to one company, the way a person adds one by hand. Send what you know; the rest can be filled in later. - [Update lead](https://headhoncho.app/docs/api/update_lead): Change what a lead asked for: the customer, the address, the service, the time, the urgency or the notes. Only the fields you send change. - [Mark lead lost](https://headhoncho.app/docs/api/mark_lead_lost): Close an open lead as lost, with the reason. It moves to Archive on the company's own clock. - [Pass lead](https://headhoncho.app/docs/api/pass_lead): Say a new lead is not yours to take, with an optional reason. It leaves the list to answer. - [Book lead](https://headhoncho.app/docs/api/book_lead): Turn a lead into a job with everything the lead holds. The lead becomes won and is linked to the job. - [Dismiss lead](https://headhoncho.app/docs/api/dismiss_lead): Send a lead to Trash as a mistake. It counts nowhere and is erased after 30 days. - [Review conversion](https://headhoncho.app/docs/api/review_conversion): Decide an ad click the matcher would not guess at: pick the job it produced, or reject it. Only then does it reach the Google file. - [Update follow up](https://headhoncho.app/docs/api/update_follow_up): Move the date of an open follow-up, or change why it is open. - [Resolve follow up](https://headhoncho.app/docs/api/resolve_follow_up): Say the chase happened. The follow-up is closed, and the job goes back to the line when it was the last stop. - [Cancel follow up](https://headhoncho.app/docs/api/cancel_follow_up): Call off a follow-up that should never have been booked. It is removed, and no chase is recorded. - The same records in the app: [the Jobs panel](https://headhoncho.app/docs/jobs). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "accepted": true, "job_id": "job_1138", "number": 1138, "follow_up_id": "fup_31a7", "status_id": "st_09", "position": 88640 } ``` ### cURL ```bash curl -X POST "https://api.headhoncho.app/api/v1/commands/schedule-follow-up" \ -H "Authorization: Bearer hh_live_..." \ -H "Idempotency-Key: 6f1d2c9e-1b7a-4c1e-9a52-0d3f8e4b7a10" \ -H "Content-Type: application/json" \ -d '{ "job_id": "job_1138", "due_at": "2026-10-28T10:00:00-05:00", "reason": "Waiting on the quote" }' ``` ### Python ```python import requests import uuid response = requests.post( "https://api.headhoncho.app/api/v1/commands/schedule-follow-up", headers={ "Authorization": "Bearer hh_live_...", "Idempotency-Key": str(uuid.uuid4()), }, json={ "job_id": "job_1138", "due_at": "2026-10-28T10:00:00-05:00", "reason": "Waiting on the quote", }, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/commands/schedule-follow-up", { method: "POST", headers: { Authorization: "Bearer hh_live_...", "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "job_id": "job_1138", "due_at": "2026-10-28T10:00:00-05:00", "reason": "Waiting on the quote" }), }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: schedule_follow_up Arguments: job_id (id, required), due_at (datetime, required), reason (text, optional) Access: do on Jobs Hints: readOnly=false, destructive=false, idempotent=false, openWorld=false Try asking: "Using HeadHoncho, schedule follow up with job_id job_1138 and due_at 2026-10-28T10:00:00-05:00 and reason Waiting on the quote." ``` --- # Update follow up Update follow up is a command in the HeadHoncho API. Move the date of an open follow-up, or change why it is open. Page: https://headhoncho.app/docs/api/update_follow_up | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **Update follow up**, HeadHoncho API v1. It is a command, sent to the base address `https://api.headhoncho.app`. `POST /api/v1/commands/update-follow-up` The key needs the **Jobs** area at **do**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). It runs the app's own command `update-follow-up`. Send an `Idempotency-Key` header with every call: the same key with the same body returns the first answer and runs nothing twice. See [the model](https://headhoncho.app/docs/api/model#idempotency). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `follow_up_id` | id, in the JSON body | Yes | From Schedule a follow-up. | `fup_31a7` | | `due_at` | datetime, in the JSON body | No | ISO 8601. The new date. | `2026-10-29T10:00:00-05:00` | | `reason` | text, in the JSON body | No | The new reason. Up to 200 characters. | `Customer asked for Friday` | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back accepted, follow_up_id, job_id, position and changed: the fields that moved. A follow-up that is already resolved is refused with 422; schedule a new one. It never deletes anything. It changes only what the command names, and it writes the change to the job's history with who asked for it. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `accepted` | true or false | True when the command ran. A command that cannot run is an error instead. | | `follow_up_id` | id (text) | The id of the follow up. | | `job_id` | id (text) | The id of the job. | | `position` | whole number | Where the change landed in the event log. Pass it as `after` on a read to see your own write. | | `changed` | list of text | The changed. | ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`read_only`](https://headhoncho.app/docs/api/errors#read_only) | 403 | This credential may read this area but not change it. | | [`not_found`](https://headhoncho.app/docs/api/errors#not_found) | 404 | No such record in the companies this credential reaches. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`missing_idempotency_key`](https://headhoncho.app/docs/api/errors#missing_idempotency_key) | 400 | Send an Idempotency-Key header on every command. | | [`idempotency_mismatch`](https://headhoncho.app/docs/api/errors#idempotency_mismatch) | 409 | This Idempotency-Key was used with a different body. | | [`idempotency_in_progress`](https://headhoncho.app/docs/api/errors#idempotency_in_progress) | 409 | A command with this Idempotency-Key is still running. Wait a moment and send it again. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [Create lead](https://headhoncho.app/docs/api/create_lead): Add a lead to one company, the way a person adds one by hand. Send what you know; the rest can be filled in later. - [Update lead](https://headhoncho.app/docs/api/update_lead): Change what a lead asked for: the customer, the address, the service, the time, the urgency or the notes. Only the fields you send change. - [Mark lead lost](https://headhoncho.app/docs/api/mark_lead_lost): Close an open lead as lost, with the reason. It moves to Archive on the company's own clock. - [Pass lead](https://headhoncho.app/docs/api/pass_lead): Say a new lead is not yours to take, with an optional reason. It leaves the list to answer. - [Book lead](https://headhoncho.app/docs/api/book_lead): Turn a lead into a job with everything the lead holds. The lead becomes won and is linked to the job. - [Dismiss lead](https://headhoncho.app/docs/api/dismiss_lead): Send a lead to Trash as a mistake. It counts nowhere and is erased after 30 days. - [Review conversion](https://headhoncho.app/docs/api/review_conversion): Decide an ad click the matcher would not guess at: pick the job it produced, or reject it. Only then does it reach the Google file. - [Schedule follow up](https://headhoncho.app/docs/api/schedule_follow_up): Book a date to chase a job or a draft lead again. The job moves onto Follow up when the company has that status. - [Resolve follow up](https://headhoncho.app/docs/api/resolve_follow_up): Say the chase happened. The follow-up is closed, and the job goes back to the line when it was the last stop. - [Cancel follow up](https://headhoncho.app/docs/api/cancel_follow_up): Call off a follow-up that should never have been booked. It is removed, and no chase is recorded. - The same records in the app: [the Jobs panel](https://headhoncho.app/docs/jobs). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "accepted": true, "follow_up_id": "fup_31a7", "job_id": "job_1138", "position": 88650, "changed": [ "due_at" ] } ``` ### cURL ```bash curl -X POST "https://api.headhoncho.app/api/v1/commands/update-follow-up" \ -H "Authorization: Bearer hh_live_..." \ -H "Idempotency-Key: 6f1d2c9e-1b7a-4c1e-9a52-0d3f8e4b7a10" \ -H "Content-Type: application/json" \ -d '{ "follow_up_id": "fup_31a7", "due_at": "2026-10-29T10:00:00-05:00", "reason": "Customer asked for Friday" }' ``` ### Python ```python import requests import uuid response = requests.post( "https://api.headhoncho.app/api/v1/commands/update-follow-up", headers={ "Authorization": "Bearer hh_live_...", "Idempotency-Key": str(uuid.uuid4()), }, json={ "follow_up_id": "fup_31a7", "due_at": "2026-10-29T10:00:00-05:00", "reason": "Customer asked for Friday", }, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/commands/update-follow-up", { method: "POST", headers: { Authorization: "Bearer hh_live_...", "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "follow_up_id": "fup_31a7", "due_at": "2026-10-29T10:00:00-05:00", "reason": "Customer asked for Friday" }), }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: update_follow_up Arguments: follow_up_id (id, required), due_at (datetime, optional), reason (text, optional) Access: do on Jobs Hints: readOnly=false, destructive=false, idempotent=true, openWorld=false Try asking: "Using HeadHoncho, update follow up with follow_up_id fup_31a7 and due_at 2026-10-29T10:00:00-05:00." ``` --- # Resolve follow up Resolve follow up is a command in the HeadHoncho API. Say the chase happened. The follow-up is closed, and the job goes back to the line when it was the last stop. Page: https://headhoncho.app/docs/api/resolve_follow_up | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **Resolve follow up**, HeadHoncho API v1. It is a command, sent to the base address `https://api.headhoncho.app`. `POST /api/v1/commands/resolve-follow-up` The key needs the **Jobs** area at **do**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). It runs the app's own command `resolve-follow-up`. Send an `Idempotency-Key` header with every call: the same key with the same body returns the first answer and runs nothing twice. See [the model](https://headhoncho.app/docs/api/model#idempotency). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `follow_up_id` | id, in the JSON body | Yes | From Schedule a follow-up. | `fup_31a7` | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back accepted, follow_up_id, job_id, position and already_resolved: true when it was closed before, in which case nothing changed. The row is stamped, never removed. It never deletes anything. It changes only what the command names, and it writes the change to the job's history with who asked for it. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `accepted` | true or false | True when the command ran. A command that cannot run is an error instead. | | `follow_up_id` | id (text) | The id of the follow up. | | `job_id` | id (text) | The id of the job. | | `already_resolved` | true or false | The already resolved. | | `position` | whole number | Where the change landed in the event log. Pass it as `after` on a read to see your own write. | ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`read_only`](https://headhoncho.app/docs/api/errors#read_only) | 403 | This credential may read this area but not change it. | | [`not_found`](https://headhoncho.app/docs/api/errors#not_found) | 404 | No such record in the companies this credential reaches. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`missing_idempotency_key`](https://headhoncho.app/docs/api/errors#missing_idempotency_key) | 400 | Send an Idempotency-Key header on every command. | | [`idempotency_mismatch`](https://headhoncho.app/docs/api/errors#idempotency_mismatch) | 409 | This Idempotency-Key was used with a different body. | | [`idempotency_in_progress`](https://headhoncho.app/docs/api/errors#idempotency_in_progress) | 409 | A command with this Idempotency-Key is still running. Wait a moment and send it again. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [Create lead](https://headhoncho.app/docs/api/create_lead): Add a lead to one company, the way a person adds one by hand. Send what you know; the rest can be filled in later. - [Update lead](https://headhoncho.app/docs/api/update_lead): Change what a lead asked for: the customer, the address, the service, the time, the urgency or the notes. Only the fields you send change. - [Mark lead lost](https://headhoncho.app/docs/api/mark_lead_lost): Close an open lead as lost, with the reason. It moves to Archive on the company's own clock. - [Pass lead](https://headhoncho.app/docs/api/pass_lead): Say a new lead is not yours to take, with an optional reason. It leaves the list to answer. - [Book lead](https://headhoncho.app/docs/api/book_lead): Turn a lead into a job with everything the lead holds. The lead becomes won and is linked to the job. - [Dismiss lead](https://headhoncho.app/docs/api/dismiss_lead): Send a lead to Trash as a mistake. It counts nowhere and is erased after 30 days. - [Review conversion](https://headhoncho.app/docs/api/review_conversion): Decide an ad click the matcher would not guess at: pick the job it produced, or reject it. Only then does it reach the Google file. - [Schedule follow up](https://headhoncho.app/docs/api/schedule_follow_up): Book a date to chase a job or a draft lead again. The job moves onto Follow up when the company has that status. - [Update follow up](https://headhoncho.app/docs/api/update_follow_up): Move the date of an open follow-up, or change why it is open. - [Cancel follow up](https://headhoncho.app/docs/api/cancel_follow_up): Call off a follow-up that should never have been booked. It is removed, and no chase is recorded. - The same records in the app: [the Jobs panel](https://headhoncho.app/docs/jobs). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "accepted": true, "follow_up_id": "fup_31a7", "job_id": "job_1138", "already_resolved": false, "position": 88660 } ``` ### cURL ```bash curl -X POST "https://api.headhoncho.app/api/v1/commands/resolve-follow-up" \ -H "Authorization: Bearer hh_live_..." \ -H "Idempotency-Key: 6f1d2c9e-1b7a-4c1e-9a52-0d3f8e4b7a10" \ -H "Content-Type: application/json" \ -d '{ "follow_up_id": "fup_31a7" }' ``` ### Python ```python import requests import uuid response = requests.post( "https://api.headhoncho.app/api/v1/commands/resolve-follow-up", headers={ "Authorization": "Bearer hh_live_...", "Idempotency-Key": str(uuid.uuid4()), }, json={ "follow_up_id": "fup_31a7", }, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/commands/resolve-follow-up", { method: "POST", headers: { Authorization: "Bearer hh_live_...", "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "follow_up_id": "fup_31a7" }), }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: resolve_follow_up Arguments: follow_up_id (id, required) Access: do on Jobs Hints: readOnly=false, destructive=false, idempotent=true, openWorld=false Try asking: "Using HeadHoncho, resolve follow up with follow_up_id fup_31a7." ``` --- # Cancel follow up Cancel follow up is a command in the HeadHoncho API. Call off a follow-up that should never have been booked. It is removed, and no chase is recorded. Page: https://headhoncho.app/docs/api/cancel_follow_up | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **Cancel follow up**, HeadHoncho API v1. It is a command, sent to the base address `https://api.headhoncho.app`. `POST /api/v1/commands/cancel-follow-up` The key needs the **Jobs** area at **do**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). It runs the app's own command `cancel-follow-up`. Send an `Idempotency-Key` header with every call: the same key with the same body returns the first answer and runs nothing twice. See [the model](https://headhoncho.app/docs/api/model#idempotency). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `follow_up_id` | id, in the JSON body | Yes | From Schedule a follow-up. | `fup_31a7` | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back accepted, follow_up_id, job_id and position. Only an open follow-up can be cancelled. Use Resolve a follow-up when the chase did happen. It never deletes anything. It changes only what the command names, and it writes the change to the job's history with who asked for it. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `accepted` | true or false | True when the command ran. A command that cannot run is an error instead. | | `follow_up_id` | id (text) | The id of the follow up. | | `job_id` | id (text) | The id of the job. | | `position` | whole number | Where the change landed in the event log. Pass it as `after` on a read to see your own write. | ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`read_only`](https://headhoncho.app/docs/api/errors#read_only) | 403 | This credential may read this area but not change it. | | [`not_found`](https://headhoncho.app/docs/api/errors#not_found) | 404 | No such record in the companies this credential reaches. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`missing_idempotency_key`](https://headhoncho.app/docs/api/errors#missing_idempotency_key) | 400 | Send an Idempotency-Key header on every command. | | [`idempotency_mismatch`](https://headhoncho.app/docs/api/errors#idempotency_mismatch) | 409 | This Idempotency-Key was used with a different body. | | [`idempotency_in_progress`](https://headhoncho.app/docs/api/errors#idempotency_in_progress) | 409 | A command with this Idempotency-Key is still running. Wait a moment and send it again. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [Create lead](https://headhoncho.app/docs/api/create_lead): Add a lead to one company, the way a person adds one by hand. Send what you know; the rest can be filled in later. - [Update lead](https://headhoncho.app/docs/api/update_lead): Change what a lead asked for: the customer, the address, the service, the time, the urgency or the notes. Only the fields you send change. - [Mark lead lost](https://headhoncho.app/docs/api/mark_lead_lost): Close an open lead as lost, with the reason. It moves to Archive on the company's own clock. - [Pass lead](https://headhoncho.app/docs/api/pass_lead): Say a new lead is not yours to take, with an optional reason. It leaves the list to answer. - [Book lead](https://headhoncho.app/docs/api/book_lead): Turn a lead into a job with everything the lead holds. The lead becomes won and is linked to the job. - [Dismiss lead](https://headhoncho.app/docs/api/dismiss_lead): Send a lead to Trash as a mistake. It counts nowhere and is erased after 30 days. - [Review conversion](https://headhoncho.app/docs/api/review_conversion): Decide an ad click the matcher would not guess at: pick the job it produced, or reject it. Only then does it reach the Google file. - [Schedule follow up](https://headhoncho.app/docs/api/schedule_follow_up): Book a date to chase a job or a draft lead again. The job moves onto Follow up when the company has that status. - [Update follow up](https://headhoncho.app/docs/api/update_follow_up): Move the date of an open follow-up, or change why it is open. - [Resolve follow up](https://headhoncho.app/docs/api/resolve_follow_up): Say the chase happened. The follow-up is closed, and the job goes back to the line when it was the last stop. - The same records in the app: [the Jobs panel](https://headhoncho.app/docs/jobs). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "accepted": true, "follow_up_id": "fup_31a7", "job_id": "job_1138", "position": 88670 } ``` ### cURL ```bash curl -X POST "https://api.headhoncho.app/api/v1/commands/cancel-follow-up" \ -H "Authorization: Bearer hh_live_..." \ -H "Idempotency-Key: 6f1d2c9e-1b7a-4c1e-9a52-0d3f8e4b7a10" \ -H "Content-Type: application/json" \ -d '{ "follow_up_id": "fup_31a7" }' ``` ### Python ```python import requests import uuid response = requests.post( "https://api.headhoncho.app/api/v1/commands/cancel-follow-up", headers={ "Authorization": "Bearer hh_live_...", "Idempotency-Key": str(uuid.uuid4()), }, json={ "follow_up_id": "fup_31a7", }, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/commands/cancel-follow-up", { method: "POST", headers: { Authorization: "Bearer hh_live_...", "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "follow_up_id": "fup_31a7" }), }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: cancel_follow_up Arguments: follow_up_id (id, required) Access: do on Jobs Hints: readOnly=false, destructive=true, idempotent=true, openWorld=false Try asking: "Using HeadHoncho, cancel follow up with follow_up_id fup_31a7." ``` --- # Get statistics summary Get statistics summary is a read in the HeadHoncho API. Jobs and leads for a range and the money they left: profit, lead cost, cost per lead, profit after leads, ad spend and profit after advertising. Page: https://headhoncho.app/docs/api/get_statistics_summary | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **Get statistics summary**, HeadHoncho API v1. It is a read, sent to the base address `https://api.headhoncho.app`. `GET /api/v1/statistics/summary` The key needs the **Statistics and marketing** area at **read**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). Send your key as `Authorization: Bearer hh_live_...`. See [API keys](https://headhoncho.app/docs/api/keys). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `company_id` | id, in the query | No | One company. Default: every company the credential reaches. | `cmp_14f5` | | `from` | date, in the query | No | First day. Default: the last 30 days, as the Statistics panel does. | `2026-10-01` | | `to` | date, in the query | No | Last day, included. Default: today in the company's time zone. | `2026-10-26` | | `by_date` | text, in the query | No | Which date puts a job in the range: created (default), scheduled or closed. One of `created`, `scheduled`, `closed`. | `created` | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back from, to and by_date (the date that puts a job in the range); companies it covers; jobs (total is every job in the range, leads is the jobs with a client name, a phone and an address, closed, canceled, canceled_by_phone, closing_rate in percent, callbacks); money (collected, parts, gross_profit, labour, net_profit, expenses, company_cut, lead_cost is the ad spend the range's jobs carry (each platform's spend divided by its jobs in the range, times the jobs), cost_per_lead is the Google Ads spend divided by the jobs whose source is Google Ads, profit_after_leads is net_profit less lead_cost, ad_spend is the range's spend as the ad platforms report it, spend_with_no_lead is the spend of a platform that brought no job, profit_after_advertising is net_profit less ad_spend); averages (ticket, close, return_per_lead). A figure with nothing behind it yet is null, never zero: cost_per_lead is null with no Google Ads account or no Google Ads job, and the three ad_spend figures are null with no ad account connected. It never changes a record. It only reads the companies the key reaches. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `from` | date (YYYY-MM-DD) | The first day of the range, inclusive. | | `to` | date (YYYY-MM-DD) | The last day of the range, inclusive. | | `by_date` | text | One of `created`, `scheduled`, `closed`. | | `currency` | text | The three-letter currency code (ISO 4217). Every money value in the answer is in it. | | `companies` | list of objects | The companies. | | `companies[].id` | id (text) | The id of this record. Ids are opaque text: keep them exactly as given. | | `companies[].name` | text | The name, as the app shows it. | | `jobs` | object | The jobs. | | `jobs.total` | whole number | The total, in the company's currency. | | `jobs.leads` | whole number | The leads. | | `jobs.closed` | whole number | True when the job is closed. | | `jobs.canceled` | whole number | The canceled. | | `jobs.canceled_by_phone` | whole number | The canceled by phone. | | `jobs.closing_rate` | number | The closing rate. | | `jobs.callbacks` | whole number | The callbacks. | | `money` | object | The money. | | `money.collected` | money (number) | The money received on the job so far. In the company's currency. | | `money.parts` | money (number) | The parts. In the company's currency. | | `money.gross_profit` | money (number) | The gross profit. In the company's currency. | | `money.labour` | number | The labour. | | `money.net_profit` | money (number) | The net profit. In the company's currency. | | `money.expenses` | money (number) | The expenses. In the company's currency. | | `money.company_cut` | number | The company cut. | | `money.lead_cost` | money (number) | The lead cost. In the company's currency. | | `money.cost_per_lead` | money (number) | The cost per lead. In the company's currency. | | `money.profit_after_leads` | money (number) | The profit after leads. In the company's currency. | | `money.ad_spend` | money (number) | The ad spend. In the company's currency. | | `money.spend_with_no_lead` | money (number) | The spend with no lead. In the company's currency. | | `money.profit_after_advertising` | money (number) | The profit after advertising. In the company's currency. | | `averages` | object | The averages. | | `averages.ticket` | number | The job number the ticket shows. | | `averages.close` | number | The close. | | `averages.return_per_lead` | number | The return per lead. | ## The same numbers as the app These are the tiles of the Statistics panel, from the same function, for the same range. Trashed jobs count in none of them. ## Jobs and leads jobs.total is the jobs created in the range, which is by_date=created, the default. jobs.leads is the part of them with a client name, a phone and an address. Choose scheduled or closed to count by another date; money follows the same jobs. ad_spend alone is the range's own spend, so it follows the dates and not the jobs. ## Several companies With no company_id the figures add up across every company the credential reaches, on the first company's clock. ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`not_found`](https://headhoncho.app/docs/api/errors#not_found) | 404 | No such record in the companies this credential reaches. | | [`out_of_scope`](https://headhoncho.app/docs/api/errors#out_of_scope) | 404 | No such company in the companies this credential reaches. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [Get statistics areas](https://headhoncho.app/docs/api/get_statistics_areas): Every place the work happened, by postal code and city: jobs, closes, cancels, average ticket and profit, with a point to put on a map. - [List area jobs](https://headhoncho.app/docs/api/list_area_jobs): The jobs behind one area on the map, newest first, twenty-five a page, with status, price, profit and where they came from. - [List job pins](https://headhoncho.app/docs/api/list_job_pins): Each job in the range that has a point on the map, newest first, up to 400, with its status, price and profit. Narrow it with a box. - The same records in the app: [the Statistics panel](https://headhoncho.app/docs/statistics). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "from": "2026-09-27", "to": "2026-10-26", "by_date": "created", "currency": "USD", "companies": [ { "id": "cmp_14f5", "name": "Sunrise Moving" } ], "jobs": { "total": 64, "leads": 58, "closed": 41, "canceled": 9, "canceled_by_phone": 4, "closing_rate": 82.0, "callbacks": 2 }, "money": { "collected": 71240.0, "parts": 6120.0, "gross_profit": 65120.0, "labour": 31200.0, "net_profit": 33920.0, "expenses": 37320.0, "company_cut": 36040.0, "lead_cost": 10400.0, "cost_per_lead": 179.31, "profit_after_leads": 23520.0, "ad_spend": 10400.0, "spend_with_no_lead": 0.0, "profit_after_advertising": 23520.0 }, "averages": { "ticket": 1420.5, "close": 1737.56, "return_per_lead": 386.56 } } ``` ### cURL ```bash curl "https://api.headhoncho.app/api/v1/statistics/summary?company_id=cmp_14f5&from=2026-10-01" \ -H "Authorization: Bearer hh_live_..." ``` ### Python ```python import requests response = requests.get( "https://api.headhoncho.app/api/v1/statistics/summary", headers={"Authorization": "Bearer hh_live_..."}, params={ "company_id": "cmp_14f5", "from": "2026-10-01", }, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/statistics/summary?company_id=cmp_14f5&from=2026-10-01", { headers: { Authorization: "Bearer hh_live_..." }, }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: get_statistics_summary Arguments: company_id (id, optional), from (date, optional), to (date, optional), by_date (text, optional) Access: read on Statistics and marketing Hints: readOnly=true, destructive=false, idempotent=true, openWorld=false Try asking: "Using HeadHoncho, get statistics summary with company_id cmp_14f5." ``` --- # Get statistics areas Get statistics areas is a read in the HeadHoncho API. Every place the work happened, by postal code and city: jobs, closes, cancels, average ticket and profit, with a point to put on a map. Page: https://headhoncho.app/docs/api/get_statistics_areas | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **Get statistics areas**, HeadHoncho API v1. It is a read, sent to the base address `https://api.headhoncho.app`. `GET /api/v1/statistics/areas` The key needs the **Statistics and marketing** area at **read**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). Send your key as `Authorization: Bearer hh_live_...`. See [API keys](https://headhoncho.app/docs/api/keys). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `company_id` | id, in the query | No | One company. Default: every company the credential reaches. | `cmp_14f5` | | `from` | date, in the query | No | First day. Default: the last 30 days, as the Statistics panel does. | `2026-10-01` | | `to` | date, in the query | No | Last day, included. Default: today in the company's time zone. | `2026-10-26` | | `by_date` | text, in the query | No | Which date puts a job in the range: created (default), scheduled or closed. One of `created`, `scheduled`, `closed`. | `created` | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back from, to, by_date, then areas, one per place: key, label, city, state, postal_code, jobs, closed, canceled, decided, closing_rate (a share from 0 to 1, null with nothing decided), average_ticket, net, net_per_job, lat and lng (the middle of its jobs), pinned and last_job. workspace: net_per_job and closing_rate for the whole range, to compare a place against. It never changes a record. It only reads the companies the key reaches. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `from` | date (YYYY-MM-DD) | The first day of the range, inclusive. | | `to` | date (YYYY-MM-DD) | The last day of the range, inclusive. | | `by_date` | text | One of `created`, `scheduled`, `closed`. | | `areas` | list of objects | The areas. | | `areas[].key` | text | A short code for this item. Match on it in code. | | `areas[].label` | text | The name the app shows for it. | | `areas[].city` | text | The city. | | `areas[].state` | text | The state or region. | | `areas[].postal_code` | text | The postal code. | | `areas[].jobs` | whole number | The jobs. | | `areas[].closed` | whole number | True when the job is closed. | | `areas[].canceled` | whole number | The canceled. | | `areas[].decided` | whole number | The decided. | | `areas[].closing_rate` | number | The closing rate. | | `areas[].average_ticket` | number | The average ticket. | | `areas[].net` | money (number) | The net amount, after what is owed either way. In the company's currency. | | `areas[].net_per_job` | money (number) | The net per job. In the company's currency. | | `areas[].lat` | number | The lat. | | `areas[].lng` | number | The lng. | | `areas[].pinned` | whole number | The pinned. | | `areas[].last_job` | date (YYYY-MM-DD) | The last job. | | `workspace` | object | The workspace. | | `workspace.net_per_job` | money (number) | The net per job. In the company's currency. | | `workspace.closing_rate` | number | The closing rate. | ## Places, not people Each row is a postal code and city, never a street. The point is the average of the jobs in it. The app's above and below average labels are not given: read the figures. ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`not_found`](https://headhoncho.app/docs/api/errors#not_found) | 404 | No such record in the companies this credential reaches. | | [`out_of_scope`](https://headhoncho.app/docs/api/errors#out_of_scope) | 404 | No such company in the companies this credential reaches. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [Get statistics summary](https://headhoncho.app/docs/api/get_statistics_summary): Jobs and leads for a range and the money they left: profit, lead cost, cost per lead, profit after leads, ad spend and profit after advertising. - [List area jobs](https://headhoncho.app/docs/api/list_area_jobs): The jobs behind one area on the map, newest first, twenty-five a page, with status, price, profit and where they came from. - [List job pins](https://headhoncho.app/docs/api/list_job_pins): Each job in the range that has a point on the map, newest first, up to 400, with its status, price and profit. Narrow it with a box. - The same records in the app: [the Statistics panel](https://headhoncho.app/docs/statistics). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "from": "2026-09-27", "to": "2026-10-26", "by_date": "created", "areas": [ { "key": "61701|Bloomington", "label": "61701 · Bloomington", "city": "Bloomington", "state": "IL", "postal_code": "61701", "jobs": 21, "closed": 14, "canceled": 2, "decided": 16, "closing_rate": 0.875, "average_ticket": 1510.0, "net": 11840.0, "net_per_job": 563.81, "lat": 40.4842, "lng": -88.9937, "pinned": 21, "last_job": "2026-10-25" }, { "key": "none", "label": "No address", "city": "", "state": "", "postal_code": "", "jobs": 3, "closed": 1, "canceled": 0, "decided": 1, "closing_rate": 1.0, "average_ticket": 900.0, "net": 410.0, "net_per_job": 136.67, "lat": null, "lng": null, "pinned": 0, "last_job": "2026-10-19" } ], "workspace": { "net_per_job": 530.0, "closing_rate": 0.82 } } ``` ### cURL ```bash curl "https://api.headhoncho.app/api/v1/statistics/areas?company_id=cmp_14f5&from=2026-10-01" \ -H "Authorization: Bearer hh_live_..." ``` ### Python ```python import requests response = requests.get( "https://api.headhoncho.app/api/v1/statistics/areas", headers={"Authorization": "Bearer hh_live_..."}, params={ "company_id": "cmp_14f5", "from": "2026-10-01", }, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/statistics/areas?company_id=cmp_14f5&from=2026-10-01", { headers: { Authorization: "Bearer hh_live_..." }, }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: get_statistics_areas Arguments: company_id (id, optional), from (date, optional), to (date, optional), by_date (text, optional) Access: read on Statistics and marketing Hints: readOnly=true, destructive=false, idempotent=true, openWorld=false Try asking: "Using HeadHoncho, get statistics areas with company_id cmp_14f5." ``` --- # List area jobs List area jobs is a read in the HeadHoncho API. The jobs behind one area on the map, newest first, twenty-five a page, with status, price, profit and where they came from. Page: https://headhoncho.app/docs/api/list_area_jobs | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **List area jobs**, HeadHoncho API v1. It is a read, sent to the base address `https://api.headhoncho.app`. `GET /api/v1/statistics/area-jobs` The key needs the **Statistics and marketing** area at **read**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). Send your key as `Authorization: Bearer hh_live_...`. See [API keys](https://headhoncho.app/docs/api/keys). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `company_id` | id, in the query | No | One company. Default: every company the credential reaches. | `cmp_14f5` | | `from` | date, in the query | No | First day. Default: the last 30 days, as the Statistics panel does. | `2026-10-01` | | `to` | date, in the query | No | Last day, included. Default: today in the company's time zone. | `2026-10-26` | | `by_date` | text, in the query | No | Which date puts a job in the range: created (default), scheduled or closed. One of `created`, `scheduled`, `closed`. | `created` | | `postal_code` | text, in the query | No | The area's postal code, from Jobs by area. Empty for the jobs with none. | `61701` | | `city` | text, in the query | No | The area's city, from Jobs by area. A postal code can cover several cities. | `Bloomington` | | `page` | number, in the query | No | Default 1. | `1` | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back items, one job each: job_id, number, client_name, client_phone, address, status (name, slug), quoted_price, net (profit on the job), created_at, scheduled_start, workers, source, lat, lng; total, page, pages, page_size and label. It never changes a record. It only reads the companies the key reaches. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `items` | list of objects | The rows on this page. | | `items[].job_id` | id (text) | The id of the job. | | `items[].number` | whole number | The number people say out loud, such as the job number. | | `items[].client_name` | text | The customer's name. Hidden when the key hides personal details. | | `items[].client_phone` | text | The customer's phone number. Hidden when the key hides personal details. | | `items[].address` | text | The address. | | `items[].status` | object | The job status. | | `items[].status.name` | text | The name, as the app shows it. | | `items[].status.slug` | text | The same name as a lowercase code word. Match on this, not on the name. | | `items[].quoted_price` | money (number) | The quoted price. In the company's currency. | | `items[].net` | money (number) | The net amount, after what is owed either way. In the company's currency. | | `items[].created_at` | time (ISO 8601, with offset) | When it was created. Carries its offset from UTC; `Z` is UTC. | | `items[].scheduled_start` | time (ISO 8601, with offset) | When the visit is planned to start. Carries its offset from UTC; `Z` is UTC. | | `items[].workers` | list of text | The workers. | | `items[].source` | text | The source. | | `items[].lat` | number | The lat. | | `items[].lng` | number | The lng. | | `total` | whole number | The total, in the company's currency. | | `page` | whole number | The page number, starting at 1. | | `pages` | whole number | How many pages there are. | | `page_size` | whole number | The page size. | | `label` | text | The name the app shows for it. | ## Personal details A key made to hide personal details gets initials for the customer, the last four digits of the phone, no street, and the point rounded to about a kilometre. ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`not_found`](https://headhoncho.app/docs/api/errors#not_found) | 404 | No such record in the companies this credential reaches. | | [`out_of_scope`](https://headhoncho.app/docs/api/errors#out_of_scope) | 404 | No such company in the companies this credential reaches. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [Get statistics summary](https://headhoncho.app/docs/api/get_statistics_summary): Jobs and leads for a range and the money they left: profit, lead cost, cost per lead, profit after leads, ad spend and profit after advertising. - [Get statistics areas](https://headhoncho.app/docs/api/get_statistics_areas): Every place the work happened, by postal code and city: jobs, closes, cancels, average ticket and profit, with a point to put on a map. - [List job pins](https://headhoncho.app/docs/api/list_job_pins): Each job in the range that has a point on the map, newest first, up to 400, with its status, price and profit. Narrow it with a box. - The same records in the app: [the Statistics panel](https://headhoncho.app/docs/statistics). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "items": [ { "job_id": "job_1138", "number": 1138, "client_name": "R. Azoulay", "client_phone": "+12175550142", "address": "2590 Main St, Bloomington, IL 61701", "status": { "name": "Closed", "slug": "closed" }, "quoted_price": 1450.0, "net": 610.0, "created_at": "2026-10-11T18:25:40Z", "scheduled_start": "2026-10-16T09:00:00-05:00", "workers": [ "Dana R." ], "source": "Google Ads", "lat": 40.4842, "lng": -88.9937 } ], "total": 21, "page": 1, "pages": 1, "page_size": 25, "label": "61701 · Bloomington" } ``` ### cURL ```bash curl "https://api.headhoncho.app/api/v1/statistics/area-jobs?company_id=cmp_14f5&from=2026-10-01" \ -H "Authorization: Bearer hh_live_..." ``` ### Python ```python import requests response = requests.get( "https://api.headhoncho.app/api/v1/statistics/area-jobs", headers={"Authorization": "Bearer hh_live_..."}, params={ "company_id": "cmp_14f5", "from": "2026-10-01", }, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/statistics/area-jobs?company_id=cmp_14f5&from=2026-10-01", { headers: { Authorization: "Bearer hh_live_..." }, }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: list_area_jobs Arguments: company_id (id, optional), from (date, optional), to (date, optional), by_date (text, optional), postal_code (text, optional), city (text, optional), page (number, optional) Access: read on Statistics and marketing Hints: readOnly=true, destructive=false, idempotent=true, openWorld=false Try asking: "Using HeadHoncho, list area jobs with company_id cmp_14f5." ``` --- # List job pins List job pins is a read in the HeadHoncho API. Each job in the range that has a point on the map, newest first, up to 400, with its status, price and profit. Narrow it with a box. Page: https://headhoncho.app/docs/api/list_job_pins | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **List job pins**, HeadHoncho API v1. It is a read, sent to the base address `https://api.headhoncho.app`. `GET /api/v1/statistics/job-pins` The key needs the **Statistics and marketing** area at **read**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). Send your key as `Authorization: Bearer hh_live_...`. See [API keys](https://headhoncho.app/docs/api/keys). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `company_id` | id, in the query | No | One company. Default: every company the credential reaches. | `cmp_14f5` | | `from` | date, in the query | No | First day. Default: the last 30 days, as the Statistics panel does. | `2026-10-01` | | `to` | date, in the query | No | Last day, included. Default: today in the company's time zone. | `2026-10-26` | | `by_date` | text, in the query | No | Which date puts a job in the range: created (default), scheduled or closed. One of `created`, `scheduled`, `closed`. | `created` | | `bbox` | text, in the query | No | A box as south,west,north,east. Default: the whole range. | `40.3,-89.1,40.6,-88.8` | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back items, one job each, in the Jobs in one area shape; truncated, true when more than the limit matched; limit. A job with no point is not listed here but still counts in Jobs by area. It never changes a record. It only reads the companies the key reaches. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `items` | list of objects | The rows on this page. | | `items[].job_id` | id (text) | The id of the job. | | `items[].number` | whole number | The number people say out loud, such as the job number. | | `items[].client_name` | text | The customer's name. Hidden when the key hides personal details. | | `items[].client_phone` | text | The customer's phone number. Hidden when the key hides personal details. | | `items[].address` | text | The address. | | `items[].status` | object | The job status. | | `items[].status.name` | text | The name, as the app shows it. | | `items[].status.slug` | text | The same name as a lowercase code word. Match on this, not on the name. | | `items[].quoted_price` | money (number) | The quoted price. In the company's currency. | | `items[].net` | money (number) | The net amount, after what is owed either way. In the company's currency. | | `items[].created_at` | time (ISO 8601, with offset) | When it was created. Carries its offset from UTC; `Z` is UTC. | | `items[].scheduled_start` | time (ISO 8601, with offset) | When the visit is planned to start. Carries its offset from UTC; `Z` is UTC. | | `items[].workers` | list of text | The workers. | | `items[].source` | text | The source. | | `items[].lat` | number | The lat. | | `items[].lng` | number | The lng. | | `truncated` | true or false | The truncated. | | `limit` | whole number | The most rows this page holds. | ## Personal details A key made to hide personal details gets initials for the customer, the last four digits of the phone, no street, and the point rounded to about a kilometre. ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`not_found`](https://headhoncho.app/docs/api/errors#not_found) | 404 | No such record in the companies this credential reaches. | | [`out_of_scope`](https://headhoncho.app/docs/api/errors#out_of_scope) | 404 | No such company in the companies this credential reaches. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [Get statistics summary](https://headhoncho.app/docs/api/get_statistics_summary): Jobs and leads for a range and the money they left: profit, lead cost, cost per lead, profit after leads, ad spend and profit after advertising. - [Get statistics areas](https://headhoncho.app/docs/api/get_statistics_areas): Every place the work happened, by postal code and city: jobs, closes, cancels, average ticket and profit, with a point to put on a map. - [List area jobs](https://headhoncho.app/docs/api/list_area_jobs): The jobs behind one area on the map, newest first, twenty-five a page, with status, price, profit and where they came from. - The same records in the app: [the Statistics panel](https://headhoncho.app/docs/statistics). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "items": [ { "job_id": "job_1138", "number": 1138, "client_name": "R. Azoulay", "client_phone": "+12175550142", "address": "2590 Main St, Bloomington, IL 61701", "status": { "name": "Closed", "slug": "closed" }, "quoted_price": 1450.0, "net": 610.0, "created_at": "2026-10-11T18:25:40Z", "scheduled_start": "2026-10-16T09:00:00-05:00", "workers": [ "Dana R." ], "source": "Google Ads", "lat": 40.4842, "lng": -88.9937 } ], "truncated": false, "limit": 400 } ``` ### cURL ```bash curl "https://api.headhoncho.app/api/v1/statistics/job-pins?company_id=cmp_14f5&from=2026-10-01" \ -H "Authorization: Bearer hh_live_..." ``` ### Python ```python import requests response = requests.get( "https://api.headhoncho.app/api/v1/statistics/job-pins", headers={"Authorization": "Bearer hh_live_..."}, params={ "company_id": "cmp_14f5", "from": "2026-10-01", }, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/statistics/job-pins?company_id=cmp_14f5&from=2026-10-01", { headers: { Authorization: "Bearer hh_live_..." }, }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: list_job_pins Arguments: company_id (id, optional), from (date, optional), to (date, optional), by_date (text, optional), bbox (text, optional) Access: read on Statistics and marketing Hints: readOnly=true, destructive=false, idempotent=true, openWorld=false Try asking: "Using HeadHoncho, list job pins with company_id cmp_14f5." ``` --- # List ad accounts List ad accounts is a read in the HeadHoncho API. The ad accounts and call tracking each company has connected, and how each one is doing. Page: https://headhoncho.app/docs/api/list_ad_accounts | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **List ad accounts**, HeadHoncho API v1. It is a read, sent to the base address `https://api.headhoncho.app`. `GET /api/v1/ad-accounts` The key needs the **Statistics and marketing** area at **read**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). Send your key as `Authorization: Bearer hh_live_...`. See [API keys](https://headhoncho.app/docs/api/keys). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `company_id` | id, in the query | No | One company. Default: every company the credential reaches. | `cmp_14f5` | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back items, one connected ad account each: id, company, provider, account_id, account_name, account_timezone, currency, status, status_detail, live, connected_by, connected_at, last_synced_at, last_spend_rows. call_tracking, the CallRail connections: id, company, provider, account_id, account_name, status, status_detail, live, last_synced_at, key_hint. No key or token is ever shown. It never changes a record. It only reads the companies the key reaches. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `items` | list of objects | The rows on this page. | | `items[].id` | id (text) | The id of this record. Ids are opaque text: keep them exactly as given. | | `items[].company` | object | The company. | | `items[].company.id` | id (text) | The id of this record. Ids are opaque text: keep them exactly as given. | | `items[].company.name` | text | The name, as the app shows it. | | `items[].provider` | text | The provider. | | `items[].account_id` | id (text) | The id of the account. | | `items[].account_name` | text | The account name. | | `items[].account_timezone` | text | The account timezone. | | `items[].currency` | text | The three-letter currency code (ISO 4217). Every money value in the answer is in it. | | `items[].status` | text | The job status. | | `items[].status_detail` | text | The status detail. | | `items[].live` | true or false | The live. | | `items[].connected_by` | text | The connected by. | | `items[].connected_at` | time (ISO 8601, with offset) | When it was connected. Carries its offset from UTC; `Z` is UTC. | | `items[].last_synced_at` | time (ISO 8601, with offset) | When it was last synced. Carries its offset from UTC; `Z` is UTC. | | `items[].last_spend_rows` | whole number | The last spend rows. | | `call_tracking` | list of objects | The call tracking. | | `call_tracking[].id` | id (text) | The id of this record. Ids are opaque text: keep them exactly as given. | | `call_tracking[].company` | object | The company. | | `call_tracking[].company.id` | id (text) | The id of this record. Ids are opaque text: keep them exactly as given. | | `call_tracking[].company.name` | text | The name, as the app shows it. | | `call_tracking[].provider` | text | The provider. | | `call_tracking[].account_id` | id (text) | The id of the account. | | `call_tracking[].account_name` | text | The account name. | | `call_tracking[].status` | text | The job status. | | `call_tracking[].status_detail` | text | The status detail. | | `call_tracking[].live` | true or false | The live. | | `call_tracking[].last_synced_at` | time (ISO 8601, with offset) | When it was last synced. Carries its offset from UTC; `Z` is UTC. | | `call_tracking[].key_hint` | text | The key hint. | ## Connecting an account Signing in to Google, Meta or Microsoft and choosing the ad account both happen in the app. Once connected, the account shows here. ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`not_found`](https://headhoncho.app/docs/api/errors#not_found) | 404 | No such record in the companies this credential reaches. | | [`out_of_scope`](https://headhoncho.app/docs/api/errors#out_of_scope) | 404 | No such company in the companies this credential reaches. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [List campaigns](https://headhoncho.app/docs/api/list_campaigns): Spend by campaign for a range, with the calls, leads, lead cost, revenue and profit each one produced, and the revenue that could not be placed. - [List agency jobs](https://headhoncho.app/docs/api/list_agency_jobs): The agency's jobs feed on a key: one row per job that opened or closed in the range, in the agency's sixteen columns, a page at a time. - [Get agency feed](https://headhoncho.app/docs/api/get_agency_feed): How the workspace sends closed jobs to its agency: the webhook address, the daily file, whether it is on, and the last tries. - The same records in the app: [the Statistics panel](https://headhoncho.app/docs/statistics). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "items": [ { "id": "adc_5e10", "company": { "id": "cmp_14f5", "name": "Sunrise Moving" }, "provider": "google_ads", "account_id": "123-456-7890", "account_name": "Sunrise Moving Ads", "account_timezone": "America/Chicago", "currency": "USD", "status": "connected", "status_detail": "", "live": true, "connected_by": "Ariel T.", "connected_at": "2026-09-02T14:10:00Z", "last_synced_at": "2026-10-26T13:00:04Z", "last_spend_rows": 31 } ], "call_tracking": [ { "id": "cn_2b90", "company": { "id": "cmp_14f5", "name": "Sunrise Moving" }, "provider": "callrail", "account_id": "ACC1f3", "account_name": "Sunrise Moving", "status": "connected", "status_detail": "", "live": true, "last_synced_at": "2026-10-26T13:00:04Z", "key_hint": "...91af" } ] } ``` ### cURL ```bash curl "https://api.headhoncho.app/api/v1/ad-accounts?company_id=cmp_14f5" \ -H "Authorization: Bearer hh_live_..." ``` ### Python ```python import requests response = requests.get( "https://api.headhoncho.app/api/v1/ad-accounts", headers={"Authorization": "Bearer hh_live_..."}, params={ "company_id": "cmp_14f5", }, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/ad-accounts?company_id=cmp_14f5", { headers: { Authorization: "Bearer hh_live_..." }, }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: list_ad_accounts Arguments: company_id (id, optional) Access: read on Statistics and marketing Hints: readOnly=true, destructive=false, idempotent=true, openWorld=false Try asking: "Using HeadHoncho, list ad accounts with company_id cmp_14f5." ``` --- # List campaigns List campaigns is a read in the HeadHoncho API. Spend by campaign for a range, with the calls, leads, lead cost, revenue and profit each one produced, and the revenue that could not be placed. Page: https://headhoncho.app/docs/api/list_campaigns | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **List campaigns**, HeadHoncho API v1. It is a read, sent to the base address `https://api.headhoncho.app`. `GET /api/v1/campaigns` The key needs the **Statistics and marketing** area at **read**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). Send your key as `Authorization: Bearer hh_live_...`. See [API keys](https://headhoncho.app/docs/api/keys). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `company_id` | id, in the query | No | One company. Default: the first company the credential reaches. | `cmp_14f5` | | `from` | date, in the query | No | First day. Default: the last 30 days. | `2026-09-27` | | `to` | date, in the query | No | Last day, included. Default: today. | `2026-10-26` | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back from, to, company_id; rows, one per campaign: campaign_id, campaign, channel, tracking (tracked, partly_tracked or untracked) and tracking_label, spend, leads, cost_per_lead, jobs, cost_per_job, revenue, subcontractors, parts, fees, profit, roas. leads is every job placed on the campaign it came from; cost_per_lead is the campaign's spend divided by those jobs, never the platform's click price. jobs and cost_per_job are kept for older integrations: jobs is the same count and cost_per_job the same figure. totals for the table. unattributed_revenue: money no campaign could be named for. A ratio with nothing to divide by is null. It never changes a record. It only reads the companies the key reaches. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `from` | date (YYYY-MM-DD) | The first day of the range, inclusive. | | `to` | date (YYYY-MM-DD) | The last day of the range, inclusive. | | `company_id` | id (text) | The id of the company. | | `currency` | text | The three-letter currency code (ISO 4217). Every money value in the answer is in it. | | `rows` | list of objects | The rows. | | `rows[].campaign_id` | id (text) | The ad platform's id for the campaign. | | `rows[].campaign` | text | The ad campaign's name. | | `rows[].channel` | text | The channel. | | `rows[].tracking` | text | The tracking. | | `rows[].tracking_label` | text | The tracking label. | | `rows[].spend` | money (number) | What was spent. In the company's currency. | | `rows[].leads` | whole number | The leads. | | `rows[].cost_per_lead` | money (number) | The cost per lead. In the company's currency. | | `rows[].jobs` | whole number | The jobs. | | `rows[].cost_per_job` | money (number) | The cost per job. In the company's currency. | | `rows[].revenue` | number | The revenue. | | `rows[].subcontractors` | number | The subcontractors. | | `rows[].parts` | money (number) | The parts. In the company's currency. | | `rows[].fees` | money (number) | What the payment processor kept. In the company's currency. | | `rows[].profit` | money (number) | The job's profit, worked out the way the app works it out. In the company's currency. | | `rows[].roas` | number | The roas. | | `totals` | object | The totals. | | `totals.spend` | money (number) | What was spent. In the company's currency. | | `totals.leads` | whole number | The leads. | | `totals.cost_per_lead` | money (number) | The cost per lead. In the company's currency. | | `totals.jobs` | whole number | The jobs. | | `totals.cost_per_job` | money (number) | The cost per job. In the company's currency. | | `totals.revenue` | number | The revenue. | | `totals.profit` | money (number) | The job's profit, worked out the way the app works it out. In the company's currency. | | `totals.roas` | number | The roas. | | `unattributed_revenue` | number | The unattributed revenue. | ## The same numbers as the app These are the rows of the Marketing campaign table. A click ID names a network, never a campaign, so a job is placed on a campaign by the name the call tracker recorded. Money that cannot be placed is shown, never dropped. ## One company A campaign table is one company's. Ask for another with company_id. ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`not_found`](https://headhoncho.app/docs/api/errors#not_found) | 404 | No such record in the companies this credential reaches. | | [`out_of_scope`](https://headhoncho.app/docs/api/errors#out_of_scope) | 404 | No such company in the companies this credential reaches. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [List ad accounts](https://headhoncho.app/docs/api/list_ad_accounts): The ad accounts and call tracking each company has connected, and how each one is doing. - [List agency jobs](https://headhoncho.app/docs/api/list_agency_jobs): The agency's jobs feed on a key: one row per job that opened or closed in the range, in the agency's sixteen columns, a page at a time. - [Get agency feed](https://headhoncho.app/docs/api/get_agency_feed): How the workspace sends closed jobs to its agency: the webhook address, the daily file, whether it is on, and the last tries. - The same records in the app: [the Statistics panel](https://headhoncho.app/docs/statistics). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "from": "2026-09-27", "to": "2026-10-26", "company_id": "cmp_14f5", "currency": "USD", "rows": [ { "campaign_id": "cam_77c1", "campaign": "Moving - Bloomington", "channel": "search", "tracking": "partly_tracked", "tracking_label": "Partly tracked: 31% of calls carried no click ID", "spend": 4210.4, "leads": 58, "cost_per_lead": 72.59, "jobs": 58, "cost_per_job": 72.59, "revenue": 27650.0, "subcontractors": 9800.0, "parts": 1200.0, "fees": 0.0, "profit": 12439.6, "roas": 6.57 } ], "totals": { "spend": 4210.4, "leads": 58, "cost_per_lead": 72.59, "jobs": 58, "cost_per_job": 72.59, "revenue": 27650.0, "profit": 12439.6, "roas": 6.57 }, "unattributed_revenue": 1450.0 } ``` ### cURL ```bash curl "https://api.headhoncho.app/api/v1/campaigns?company_id=cmp_14f5&from=2026-09-27" \ -H "Authorization: Bearer hh_live_..." ``` ### Python ```python import requests response = requests.get( "https://api.headhoncho.app/api/v1/campaigns", headers={"Authorization": "Bearer hh_live_..."}, params={ "company_id": "cmp_14f5", "from": "2026-09-27", }, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/campaigns?company_id=cmp_14f5&from=2026-09-27", { headers: { Authorization: "Bearer hh_live_..." }, }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: list_campaigns Arguments: company_id (id, optional), from (date, optional), to (date, optional) Access: read on Statistics and marketing Hints: readOnly=true, destructive=false, idempotent=true, openWorld=false Try asking: "Using HeadHoncho, list campaigns with company_id cmp_14f5." ``` --- # List agency jobs List agency jobs is a read in the HeadHoncho API. The agency's jobs feed on a key: one row per job that opened or closed in the range, in the agency's sixteen columns, a page at a time. Page: https://headhoncho.app/docs/api/list_agency_jobs | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **List agency jobs**, HeadHoncho API v1. It is a read, sent to the base address `https://api.headhoncho.app`. `GET /api/v1/agency/jobs` The key needs the **Statistics and marketing** area at **read**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). Send your key as `Authorization: Bearer hh_live_...`. See [API keys](https://headhoncho.app/docs/api/keys). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `from` | date, in the query | No | First day. Default: 45 days ago. | `2026-09-11` | | `to` | date, in the query | No | Last day, included. Default: today. At most a year from from. | `2026-10-26` | | `company_id` | id, in the query | No | One company. Default: every company the credential reaches. | `cmp_14f5` | | `page` | number, in the query | No | Default 1. | `1` | | `per_page` | number, in the query | No | 1 to 500. Default 200. | `200` | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back from, to, timezone, date_format, columns (the agency's headings), keys, count (rows in all), page, per_page, next (the next page number or null) and rows in the sixteen columns, oldest first. Money is text with two decimals, as the agency's file prints it. It never changes a record. It only reads the companies the key reaches. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `from` | date (YYYY-MM-DD) | The first day of the range, inclusive. | | `to` | date (YYYY-MM-DD) | The last day of the range, inclusive. | | `timezone` | text | The timezone. | | `date_format` | text | The date format. | | `columns` | list of text | The columns. | | `keys` | list of text | The keys. | | `count` | whole number | How many match in all, across every page. | | `page` | whole number | The page number, starting at 1. | | `per_page` | whole number | The per page. | | `next` | value or null | The cursor for the next page, or null on the last page. Pass it back as `cursor`. | | `rows` | list of objects | The rows. | | `rows[].ticket` | whole number | The job number the ticket shows. | | `rows[].status` | text | The job status. | | `rows[].customer_phone` | text | The customer's phone number. Hidden when the key hides personal details. | | `rows[].start_date` | date and time (company time zone) | The start date. | | `rows[].close_date` | date and time (company time zone) | The close date. | | `rows[].total` | money (decimal as text) | The total, in the company's currency. | | `rows[].company_total` | money (decimal as text) | The company total. In the company's currency. | | `rows[].job_source` | text | Where the job came from, such as Google Ads. | | `rows[].gclid` | text | The Google click id the call or visit carried. | | `rows[].callrail_call_id` | id (text) | The id of the callrail call. | | `rows[].campaign_id` | id (text) | The ad platform's id for the campaign. | | `rows[].callrail_call_start` | date and time (company time zone) | The callrail call start. | | `rows[].lead_source` | text | How the lead first reached the business. | | `rows[].paid_date` | date (YYYY-MM-DD) | The paid date. | | `rows[].time_zone` | text | The company's time zone name, such as America/Chicago. | | `rows[].callrail_source_name` | text | The callrail source name. | ## Same rows, now on a key This is the feed an agency pulled with its own token, with the same sixteen columns under the same names as the file and the webhook. Only the door changed: a key with access to Statistics and marketing reads it. ## Masked until the match is paid gclid and callrail_call_id print whole once the job's match is paid for: the Google Click IDs report is turned on in Statistics › Reports and the job's one credit is paid (jobs opened before the first Turn on are free). Until then both print masked, their first and last characters around an ellipsis. The webhook and the daily file follow the same rule. ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`not_found`](https://headhoncho.app/docs/api/errors#not_found) | 404 | No such record in the companies this credential reaches. | | [`out_of_scope`](https://headhoncho.app/docs/api/errors#out_of_scope) | 404 | No such company in the companies this credential reaches. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [List ad accounts](https://headhoncho.app/docs/api/list_ad_accounts): The ad accounts and call tracking each company has connected, and how each one is doing. - [List campaigns](https://headhoncho.app/docs/api/list_campaigns): Spend by campaign for a range, with the calls, leads, lead cost, revenue and profit each one produced, and the revenue that could not be placed. - [Get agency feed](https://headhoncho.app/docs/api/get_agency_feed): How the workspace sends closed jobs to its agency: the webhook address, the daily file, whether it is on, and the last tries. - The same records in the app: [the Statistics panel](https://headhoncho.app/docs/statistics). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "from": "2026-09-11", "to": "2026-10-26", "timezone": "America/Chicago", "date_format": "YYYY-MM-DD HH:MM", "columns": [ "Ticket", "Status", "Customer phone (E.164)", "Start date", "Close date", "Total", "Company total", "Job source", "gclid", "CallRail call id", "Campaign ID", "CallRail call start", "Lead source", "Paid date", "Time zone", "CallRail source name" ], "keys": [ "ticket", "status", "customer_phone", "start_date", "close_date", "total", "company_total", "job_source", "gclid", "callrail_call_id", "campaign_id", "callrail_call_start", "lead_source", "paid_date", "time_zone", "callrail_source_name" ], "count": 1, "page": 1, "per_page": 200, "next": null, "rows": [ { "ticket": 1138, "status": "Closed", "customer_phone": "+12175550142", "start_date": "2026-10-11 13:25", "close_date": "2026-10-16 11:40", "total": "1450.00", "company_total": "610.00", "job_source": "Google Ads", "gclid": "Cj0KCQjw...", "callrail_call_id": "CAL8f2e1", "campaign_id": "2184930112", "callrail_call_start": "2026-10-11 13:22", "lead_source": "call", "paid_date": "2026-10-16", "time_zone": "America/Chicago", "callrail_source_name": "pool - google ads" } ] } ``` ### cURL ```bash curl "https://api.headhoncho.app/api/v1/agency/jobs?from=2026-09-11&to=2026-10-26" \ -H "Authorization: Bearer hh_live_..." ``` ### Python ```python import requests response = requests.get( "https://api.headhoncho.app/api/v1/agency/jobs", headers={"Authorization": "Bearer hh_live_..."}, params={ "from": "2026-09-11", "to": "2026-10-26", }, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/agency/jobs?from=2026-09-11&to=2026-10-26", { headers: { Authorization: "Bearer hh_live_..." }, }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: list_agency_jobs Arguments: from (date, optional), to (date, optional), company_id (id, optional), page (number, optional), per_page (number, optional) Access: read on Statistics and marketing Hints: readOnly=true, destructive=false, idempotent=true, openWorld=false Try asking: "Using HeadHoncho, list agency jobs with from 2026-09-11." ``` --- # Get agency feed Get agency feed is a read in the HeadHoncho API. How the workspace sends closed jobs to its agency: the webhook address, the daily file, whether it is on, and the last tries. Page: https://headhoncho.app/docs/api/get_agency_feed | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **Get agency feed**, HeadHoncho API v1. It is a read, sent to the base address `https://api.headhoncho.app`. `GET /api/v1/agency/feed` The key needs the **Company settings** area at **read**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). Send your key as `Authorization: Bearer hh_live_...`. See [API keys](https://headhoncho.app/docs/api/keys). ## Parameters This call takes no parameters. ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back feed (webhook_url, webhook_secret_hint, api_token_hint, daily_to, daily_hour, enabled, changed_at), columns and keys of the rows it sends, deliveries (the last 50 webhook tries: id, job_id, ticket, event_kind, status, attempt, response_code, error, attempted_at) and exports (the last 14 daily files). Secrets are never shown, only their last characters. It never changes a record. It only reads the companies the key reaches. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `feed` | object | The feed. | | `feed.webhook_url` | text | The webhook url. | | `feed.webhook_secret_hint` | text | The webhook secret hint. | | `feed.api_token_hint` | text | The api token hint. | | `feed.daily_to` | text | The daily to. | | `feed.daily_hour` | whole number | The daily hour. | | `feed.enabled` | true or false | The enabled. | | `feed.changed_at` | time (ISO 8601, with offset) | When it was changed. Carries its offset from UTC; `Z` is UTC. | | `date_format` | text | The date format. | | `event` | text | The kind of event, as a code. | | `columns` | list of text | The columns. | | `keys` | list of text | The keys. | | `deliveries` | list of objects | The deliveries. | | `deliveries[].id` | id (text) | The id of this record. Ids are opaque text: keep them exactly as given. | | `deliveries[].job_id` | id (text) | The id of the job. | | `deliveries[].ticket` | whole number | The job number the ticket shows. | | `deliveries[].event_kind` | text | The event kind. | | `deliveries[].status` | text | The job status. | | `deliveries[].attempt` | whole number | The attempt. | | `deliveries[].response_code` | whole number | The response code. | | `deliveries[].error` | text | The error. | | `deliveries[].attempted_at` | time (ISO 8601, with offset) | When it was attempted. Carries its offset from UTC; `Z` is UTC. | | `exports` | list of objects | The exports. | | `exports[].id` | id (text) | The id of this record. Ids are opaque text: keep them exactly as given. | | `exports[].sent_to` | text | The sent to. | | `exports[].period_key` | date (YYYY-MM-DD) | The period key. | | `exports[].rows` | whole number | The rows. | | `exports[].status` | text | The job status. | | `exports[].error` | text | The error. | | `exports[].sent_at` | time (ISO 8601, with offset) | When the sent happened. Carries its offset from UTC; `Z` is UTC. | ## Owners and admins only The feed belongs to the whole workspace, as in the app, where only an owner or an admin opens it. The key must reach every company. ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [List ad accounts](https://headhoncho.app/docs/api/list_ad_accounts): The ad accounts and call tracking each company has connected, and how each one is doing. - [List campaigns](https://headhoncho.app/docs/api/list_campaigns): Spend by campaign for a range, with the calls, leads, lead cost, revenue and profit each one produced, and the revenue that could not be placed. - [List agency jobs](https://headhoncho.app/docs/api/list_agency_jobs): The agency's jobs feed on a key: one row per job that opened or closed in the range, in the agency's sixteen columns, a page at a time. - The same records in the app: [Settings](https://headhoncho.app/docs/settings). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "feed": { "webhook_url": "https://agency.example.com/hooks/headhoncho", "webhook_secret_hint": "...a91f", "api_token_hint": "...7c20", "daily_to": "files@agency.example.com", "daily_hour": 6, "enabled": true, "changed_at": "2026-10-12T15:04:10Z" }, "date_format": "YYYY-MM-DD HH:MM", "event": "job.closed", "columns": [ "Ticket", "Status", "Customer phone (E.164)" ], "keys": [ "ticket", "status", "customer_phone" ], "deliveries": [ { "id": "dlv_31aa", "job_id": "job_1138", "ticket": 1138, "event_kind": "job.closed", "status": "sent", "attempt": 1, "response_code": 200, "error": "", "attempted_at": "2026-10-16T11:41:02Z" } ], "exports": [ { "id": "exp_90b2", "sent_to": "files@agency.example.com", "period_key": "2026-10-25", "rows": 12, "status": "sent", "error": "", "sent_at": "2026-10-26T11:00:03Z" } ] } ``` ### cURL ```bash curl "https://api.headhoncho.app/api/v1/agency/feed" \ -H "Authorization: Bearer hh_live_..." ``` ### Python ```python import requests response = requests.get( "https://api.headhoncho.app/api/v1/agency/feed", headers={"Authorization": "Bearer hh_live_..."}, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/agency/feed", { headers: { Authorization: "Bearer hh_live_..." }, }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: get_agency_feed Arguments: none Access: read on Company settings Hints: readOnly=true, destructive=false, idempotent=true, openWorld=false Try asking: "Using HeadHoncho, get agency feed." ``` --- # Update agency feed Update agency feed is a command in the HeadHoncho API. Change how closed jobs reach the agency: the webhook address, the daily file address and hour, or switch the feed on or off. Secrets are not touched. Page: https://headhoncho.app/docs/api/update_agency_feed | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **Update agency feed**, HeadHoncho API v1. It is a command, sent to the base address `https://api.headhoncho.app`. `POST /api/v1/commands/update-agency-feed` The key needs the **Company settings** area at **do**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). It runs the app's own command `update-agency-feed`. Send an `Idempotency-Key` header with every call: the same key with the same body returns the first answer and runs nothing twice. See [the model](https://headhoncho.app/docs/api/model#idempotency). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `webhook_url` | text, in the JSON body | No | Where each closed job is sent. Empty turns the webhook off. | `https://agency.example.com/hooks/headhoncho` | | `daily_to` | text, in the JSON body | No | The email address that gets the daily file. Empty turns the file off. | `files@agency.example.com` | | `daily_hour` | number, in the JSON body | No | The hour of the day, 0 to 23, in the workspace's time zone. | `6` | | `enabled` | boolean, in the JSON body | No | false stops every door of the feed. true starts it again. | `true` | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back accepted, position, and the feed as it now stands: feed_id, webhook_url, webhook_secret_hint, api_token_hint, daily_to, daily_hour, enabled. Only the fields you send change. It never deletes anything. It changes only what the command names, and it writes the change to the job's history with who asked for it. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `accepted` | true or false | True when the command ran. A command that cannot run is an error instead. | | `position` | whole number | Where the change landed in the event log. Pass it as `after` on a read to see your own write. | | `feed_id` | id (text) | The id of the feed. | | `webhook_url` | text | The webhook url. | | `webhook_secret_hint` | text | The webhook secret hint. | | `api_token_hint` | text | The api token hint. | | `daily_to` | text | The daily to. | | `daily_hour` | whole number | The daily hour. | | `enabled` | true or false | The enabled. | ## Not the secrets The webhook secret and the agency's token are made and shown once, in the app. They are not available here. ## Owners and admins only As in the app, only an owner or an admin may change the feed, and the key must reach every company. ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`read_only`](https://headhoncho.app/docs/api/errors#read_only) | 403 | This credential may read this area but not change it. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`missing_idempotency_key`](https://headhoncho.app/docs/api/errors#missing_idempotency_key) | 400 | Send an Idempotency-Key header on every command. | | [`idempotency_mismatch`](https://headhoncho.app/docs/api/errors#idempotency_mismatch) | 409 | This Idempotency-Key was used with a different body. | | [`idempotency_in_progress`](https://headhoncho.app/docs/api/errors#idempotency_in_progress) | 409 | A command with this Idempotency-Key is still running. Wait a moment and send it again. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [Update company](https://headhoncho.app/docs/api/update_company): Change one company's own facts: name, service area, time zone, country, color, week, opening hours or service places. Only what you send changes. - [Create company](https://headhoncho.app/docs/api/create_company): Add another company to the workspace. It starts with the first company's time zone and country unless you send your own. - [Update organization](https://headhoncho.app/docs/api/update_organization): Rename the workspace. A company still carrying the old workspace name is renamed with it. - [Add job type](https://headhoncho.app/docs/api/add_job_type): Add a kind of work the business does, such as Local move or Roof repair. A name already in use is refused. - [Update job type](https://headhoncho.app/docs/api/update_job_type): Rename a job type, move it in the list, or retire it so new jobs cannot pick it. Old jobs keep it. - [Update job status](https://headhoncho.app/docs/api/update_job_status): Rename a status, change its look, move it in the list, or retire it. A rename shows on every job at once. Its slug and band stay. - [Set status band](https://headhoncho.app/docs/api/set_status_band): Put a status on the line (a step every job passes) or off it as a detour (a place a job gets stuck). The line closes up behind it. - [Replace job status](https://headhoncho.app/docs/api/replace_job_status): Let another status stand in for this one: move its jobs onto the new status, retire the old word, or both. Name an existing status or a new one. - [Add job status](https://headhoncho.app/docs/api/add_job_status): Add a status to the workspace's list, on the line or as a detour. It carries no role: it is a name and a color. - [Reorder line](https://headhoncho.app/docs/api/reorder_line): Set the order of the statuses on the line, the order every picker offers. Send every status on the line, once each. - [Sync callrail](https://headhoncho.app/docs/api/sync_callrail): Pull the company's new CallRail calls and forms now, match them to jobs, and say how many landed. The hourly sync does this on its own. - [Update callrail tracking](https://headhoncho.app/docs/api/update_callrail_tracking): Set the tracking phone numbers on a company's CallRail connection. They replace the list whole. The webhook signing key is set in the app. - [Refresh sources](https://headhoncho.app/docs/api/refresh_sources): Clear the Call center source stamped on a company's jobs, pull all its CallRail history again and re-read every call, so each job's source is worked out afresh. - [Sync ad platform](https://headhoncho.app/docs/api/sync_ad_platform): Pull a company's latest campaigns and spend from one ad platform now. The hourly sync does this on its own. - The same records in the app: [Settings](https://headhoncho.app/docs/settings). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "accepted": true, "position": 88601, "feed_id": "agf_08d1", "webhook_url": "https://agency.example.com/hooks/headhoncho", "webhook_secret_hint": "...a91f", "api_token_hint": "...7c20", "daily_to": "files@agency.example.com", "daily_hour": 6, "enabled": true } ``` ### cURL ```bash curl -X POST "https://api.headhoncho.app/api/v1/commands/update-agency-feed" \ -H "Authorization: Bearer hh_live_..." \ -H "Idempotency-Key: 6f1d2c9e-1b7a-4c1e-9a52-0d3f8e4b7a10" \ -H "Content-Type: application/json" \ -d '{ "webhook_url": "https://agency.example.com/hooks/headhoncho", "daily_to": "files@agency.example.com", "daily_hour": 6, "enabled": true }' ``` ### Python ```python import requests import uuid response = requests.post( "https://api.headhoncho.app/api/v1/commands/update-agency-feed", headers={ "Authorization": "Bearer hh_live_...", "Idempotency-Key": str(uuid.uuid4()), }, json={ "webhook_url": "https://agency.example.com/hooks/headhoncho", "daily_to": "files@agency.example.com", "daily_hour": 6, "enabled": True, }, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/commands/update-agency-feed", { method: "POST", headers: { Authorization: "Bearer hh_live_...", "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "webhook_url": "https://agency.example.com/hooks/headhoncho", "daily_to": "files@agency.example.com", "daily_hour": 6, "enabled": true }), }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: update_agency_feed Arguments: webhook_url (text, optional), daily_to (text, optional), daily_hour (number, optional), enabled (boolean, optional) Access: do on Company settings Hints: readOnly=false, destructive=false, idempotent=true, openWorld=false Try asking: "Using HeadHoncho, update agency feed with webhook_url https://agency.example.com/hooks/headhoncho." ``` --- # Sync callrail Sync callrail is a command in the HeadHoncho API. Pull the company's new CallRail calls and forms now, match them to jobs, and say how many landed. The hourly sync does this on its own. Page: https://headhoncho.app/docs/api/sync_callrail | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **Sync callrail**, HeadHoncho API v1. It is a command, sent to the base address `https://api.headhoncho.app`. `POST /api/v1/commands/sync-callrail` The key needs the **Company settings** area at **do**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). It runs the app's own command `sync-callrail`. Send an `Idempotency-Key` header with every call: the same key with the same body returns the first answer and runs nothing twice. See [the model](https://headhoncho.app/docs/api/model#idempotency). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `company_id` | id, in the JSON body | Yes | The company, from Who am I. | `cmp_14f5` | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back accepted, position, connection_id, calls_landed, conversions_matched, needs_review (calls that could be more than one job, waiting for a person) and forms_landed. If CallRail refused, calls_landed is 0 and error says why. A company with no CallRail connected is refused with 422. It never deletes anything. It changes only what the command names, and it writes the change to the job's history with who asked for it. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `accepted` | true or false | True when the command ran. A command that cannot run is an error instead. | | `position` | whole number | Where the change landed in the event log. Pass it as `after` on a read to see your own write. | | `connection_id` | id (text) | The id of the connection. | | `calls_landed` | whole number | The calls landed. | | `conversions_matched` | whole number | The conversions matched. | | `needs_review` | whole number | The needs review. | | `forms_landed` | whole number | The forms landed. | ## It calls CallRail Each call makes real requests to CallRail on this company's own key and charges your API credits as any command does. ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`read_only`](https://headhoncho.app/docs/api/errors#read_only) | 403 | This credential may read this area but not change it. | | [`not_found`](https://headhoncho.app/docs/api/errors#not_found) | 404 | No such record in the companies this credential reaches. | | [`out_of_scope`](https://headhoncho.app/docs/api/errors#out_of_scope) | 404 | No such company in the companies this credential reaches. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`missing_idempotency_key`](https://headhoncho.app/docs/api/errors#missing_idempotency_key) | 400 | Send an Idempotency-Key header on every command. | | [`idempotency_mismatch`](https://headhoncho.app/docs/api/errors#idempotency_mismatch) | 409 | This Idempotency-Key was used with a different body. | | [`idempotency_in_progress`](https://headhoncho.app/docs/api/errors#idempotency_in_progress) | 409 | A command with this Idempotency-Key is still running. Wait a moment and send it again. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [Update company](https://headhoncho.app/docs/api/update_company): Change one company's own facts: name, service area, time zone, country, color, week, opening hours or service places. Only what you send changes. - [Create company](https://headhoncho.app/docs/api/create_company): Add another company to the workspace. It starts with the first company's time zone and country unless you send your own. - [Update organization](https://headhoncho.app/docs/api/update_organization): Rename the workspace. A company still carrying the old workspace name is renamed with it. - [Add job type](https://headhoncho.app/docs/api/add_job_type): Add a kind of work the business does, such as Local move or Roof repair. A name already in use is refused. - [Update job type](https://headhoncho.app/docs/api/update_job_type): Rename a job type, move it in the list, or retire it so new jobs cannot pick it. Old jobs keep it. - [Update job status](https://headhoncho.app/docs/api/update_job_status): Rename a status, change its look, move it in the list, or retire it. A rename shows on every job at once. Its slug and band stay. - [Set status band](https://headhoncho.app/docs/api/set_status_band): Put a status on the line (a step every job passes) or off it as a detour (a place a job gets stuck). The line closes up behind it. - [Replace job status](https://headhoncho.app/docs/api/replace_job_status): Let another status stand in for this one: move its jobs onto the new status, retire the old word, or both. Name an existing status or a new one. - [Add job status](https://headhoncho.app/docs/api/add_job_status): Add a status to the workspace's list, on the line or as a detour. It carries no role: it is a name and a color. - [Reorder line](https://headhoncho.app/docs/api/reorder_line): Set the order of the statuses on the line, the order every picker offers. Send every status on the line, once each. - [Update agency feed](https://headhoncho.app/docs/api/update_agency_feed): Change how closed jobs reach the agency: the webhook address, the daily file address and hour, or switch the feed on or off. Secrets are not touched. - [Update callrail tracking](https://headhoncho.app/docs/api/update_callrail_tracking): Set the tracking phone numbers on a company's CallRail connection. They replace the list whole. The webhook signing key is set in the app. - [Refresh sources](https://headhoncho.app/docs/api/refresh_sources): Clear the Call center source stamped on a company's jobs, pull all its CallRail history again and re-read every call, so each job's source is worked out afresh. - [Sync ad platform](https://headhoncho.app/docs/api/sync_ad_platform): Pull a company's latest campaigns and spend from one ad platform now. The hourly sync does this on its own. - The same records in the app: [Settings](https://headhoncho.app/docs/settings). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "accepted": true, "position": 88601, "connection_id": "cn_2b90", "calls_landed": 6, "conversions_matched": 4, "needs_review": 1, "forms_landed": 2 } ``` ### cURL ```bash curl -X POST "https://api.headhoncho.app/api/v1/commands/sync-callrail" \ -H "Authorization: Bearer hh_live_..." \ -H "Idempotency-Key: 6f1d2c9e-1b7a-4c1e-9a52-0d3f8e4b7a10" \ -H "Content-Type: application/json" \ -d '{ "company_id": "cmp_14f5" }' ``` ### Python ```python import requests import uuid response = requests.post( "https://api.headhoncho.app/api/v1/commands/sync-callrail", headers={ "Authorization": "Bearer hh_live_...", "Idempotency-Key": str(uuid.uuid4()), }, json={ "company_id": "cmp_14f5", }, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/commands/sync-callrail", { method: "POST", headers: { Authorization: "Bearer hh_live_...", "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "company_id": "cmp_14f5" }), }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: sync_callrail Arguments: company_id (id, required) Access: do on Company settings Hints: readOnly=false, destructive=false, idempotent=true, openWorld=false Try asking: "Using HeadHoncho, sync callrail with company_id cmp_14f5." ``` --- # Update callrail tracking Update callrail tracking is a command in the HeadHoncho API. Set the tracking phone numbers on a company's CallRail connection. They replace the list whole. The webhook signing key is set in the app. Page: https://headhoncho.app/docs/api/update_callrail_tracking | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **Update callrail tracking**, HeadHoncho API v1. It is a command, sent to the base address `https://api.headhoncho.app`. `POST /api/v1/commands/update-callrail-tracking` The key needs the **Company settings** area at **do**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). It runs the app's own command `update-callrail-tracking`. Send an `Idempotency-Key` header with every call: the same key with the same body returns the first answer and runs nothing twice. See [the model](https://headhoncho.app/docs/api/model#idempotency). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `company_id` | id, in the JSON body | Yes | The company, from Who am I. | `cmp_14f5` | | `tracking_numbers` | text, in the JSON body | Yes | Phone numbers in any format, separated by commas or new lines. Up to 200. Stored as E.164. An empty value clears the list. | `+13095550100, +13095550101` | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back accepted, position, connection_id, tracking_numbers as stored, webhook_key_hint (the last characters of the signing key, or empty) and webhook_url, the address CallRail posts each finished call to. It never deletes anything. It changes only what the command names, and it writes the change to the job's history with who asked for it. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `accepted` | true or false | True when the command ran. A command that cannot run is an error instead. | | `position` | whole number | Where the change landed in the event log. Pass it as `after` on a read to see your own write. | | `connection_id` | id (text) | The id of the connection. | | `tracking_numbers` | list of text | The tracking numbers. | | `webhook_key_hint` | text | The webhook key hint. | | `webhook_url` | text | The webhook url. | ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`read_only`](https://headhoncho.app/docs/api/errors#read_only) | 403 | This credential may read this area but not change it. | | [`not_found`](https://headhoncho.app/docs/api/errors#not_found) | 404 | No such record in the companies this credential reaches. | | [`out_of_scope`](https://headhoncho.app/docs/api/errors#out_of_scope) | 404 | No such company in the companies this credential reaches. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`missing_idempotency_key`](https://headhoncho.app/docs/api/errors#missing_idempotency_key) | 400 | Send an Idempotency-Key header on every command. | | [`idempotency_mismatch`](https://headhoncho.app/docs/api/errors#idempotency_mismatch) | 409 | This Idempotency-Key was used with a different body. | | [`idempotency_in_progress`](https://headhoncho.app/docs/api/errors#idempotency_in_progress) | 409 | A command with this Idempotency-Key is still running. Wait a moment and send it again. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [Update company](https://headhoncho.app/docs/api/update_company): Change one company's own facts: name, service area, time zone, country, color, week, opening hours or service places. Only what you send changes. - [Create company](https://headhoncho.app/docs/api/create_company): Add another company to the workspace. It starts with the first company's time zone and country unless you send your own. - [Update organization](https://headhoncho.app/docs/api/update_organization): Rename the workspace. A company still carrying the old workspace name is renamed with it. - [Add job type](https://headhoncho.app/docs/api/add_job_type): Add a kind of work the business does, such as Local move or Roof repair. A name already in use is refused. - [Update job type](https://headhoncho.app/docs/api/update_job_type): Rename a job type, move it in the list, or retire it so new jobs cannot pick it. Old jobs keep it. - [Update job status](https://headhoncho.app/docs/api/update_job_status): Rename a status, change its look, move it in the list, or retire it. A rename shows on every job at once. Its slug and band stay. - [Set status band](https://headhoncho.app/docs/api/set_status_band): Put a status on the line (a step every job passes) or off it as a detour (a place a job gets stuck). The line closes up behind it. - [Replace job status](https://headhoncho.app/docs/api/replace_job_status): Let another status stand in for this one: move its jobs onto the new status, retire the old word, or both. Name an existing status or a new one. - [Add job status](https://headhoncho.app/docs/api/add_job_status): Add a status to the workspace's list, on the line or as a detour. It carries no role: it is a name and a color. - [Reorder line](https://headhoncho.app/docs/api/reorder_line): Set the order of the statuses on the line, the order every picker offers. Send every status on the line, once each. - [Update agency feed](https://headhoncho.app/docs/api/update_agency_feed): Change how closed jobs reach the agency: the webhook address, the daily file address and hour, or switch the feed on or off. Secrets are not touched. - [Sync callrail](https://headhoncho.app/docs/api/sync_callrail): Pull the company's new CallRail calls and forms now, match them to jobs, and say how many landed. The hourly sync does this on its own. - [Refresh sources](https://headhoncho.app/docs/api/refresh_sources): Clear the Call center source stamped on a company's jobs, pull all its CallRail history again and re-read every call, so each job's source is worked out afresh. - [Sync ad platform](https://headhoncho.app/docs/api/sync_ad_platform): Pull a company's latest campaigns and spend from one ad platform now. The hourly sync does this on its own. - The same records in the app: [Settings](https://headhoncho.app/docs/settings). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "accepted": true, "position": 88601, "connection_id": "cn_2b90", "tracking_numbers": [ "+13095550100", "+13095550101" ], "webhook_key_hint": "...c4d2", "webhook_url": "https://api.headhoncho.app/api/webhooks/callrail/6f1d2a9e-5b0c-4c61-9a0e-3b7b1d8e90aa/" } ``` ### cURL ```bash curl -X POST "https://api.headhoncho.app/api/v1/commands/update-callrail-tracking" \ -H "Authorization: Bearer hh_live_..." \ -H "Idempotency-Key: 6f1d2c9e-1b7a-4c1e-9a52-0d3f8e4b7a10" \ -H "Content-Type: application/json" \ -d '{ "company_id": "cmp_14f5", "tracking_numbers": "+13095550100, +13095550101" }' ``` ### Python ```python import requests import uuid response = requests.post( "https://api.headhoncho.app/api/v1/commands/update-callrail-tracking", headers={ "Authorization": "Bearer hh_live_...", "Idempotency-Key": str(uuid.uuid4()), }, json={ "company_id": "cmp_14f5", "tracking_numbers": "+13095550100, +13095550101", }, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/commands/update-callrail-tracking", { method: "POST", headers: { Authorization: "Bearer hh_live_...", "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "company_id": "cmp_14f5", "tracking_numbers": "+13095550100, +13095550101" }), }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: update_callrail_tracking Arguments: company_id (id, required), tracking_numbers (text, required) Access: do on Company settings Hints: readOnly=false, destructive=false, idempotent=true, openWorld=false Try asking: "Using HeadHoncho, update callrail tracking with company_id cmp_14f5 and tracking_numbers +13095550100, +13095550101." ``` --- # Refresh sources Refresh sources is a command in the HeadHoncho API. Clear the Call center source stamped on a company's jobs, pull all its CallRail history again and re-read every call, so each job's source is worked out afresh. Page: https://headhoncho.app/docs/api/refresh_sources | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **Refresh sources**, HeadHoncho API v1. It is a command, sent to the base address `https://api.headhoncho.app`. `POST /api/v1/commands/refresh-sources` The key needs the **Company settings** area at **do**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). It runs the app's own command `refresh-sources`. Send an `Idempotency-Key` header with every call: the same key with the same body returns the first answer and runs nothing twice. See [the model](https://headhoncho.app/docs/api/model#idempotency). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `company_id` | id, in the JSON body | Yes | The company, from Who am I. | `cmp_14f5` | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back accepted, position, sources_cleared (jobs that lost the stamp), sources_renamed, connected (false when the company has no CallRail), and when connected: calls_landed, passes, complete, forms_landed, attribution_read, and error if CallRail refused part. It never deletes anything. It changes only what the command names, and it writes the change to the job's history with who asked for it. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `accepted` | true or false | True when the command ran. A command that cannot run is an error instead. | | `position` | whole number | Where the change landed in the event log. Pass it as `after` on a read to see your own write. | | `sources_cleared` | whole number | The sources cleared. | | `sources_renamed` | whole number | The sources renamed. | | `connected` | true or false | The connected. | | `calls_landed` | whole number | The calls landed. | | `passes` | whole number | The passes. | | `complete` | true or false | The complete. | | `forms_landed` | whole number | The forms landed. | | `attribution_read` | whole number | The attribution read. | ## It can take a while It changes the recorded source on many jobs and reads all of the company's calls. Each change lands in the job's history, by the credential's name. Run it when the app tells you to, not on a clock. ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`read_only`](https://headhoncho.app/docs/api/errors#read_only) | 403 | This credential may read this area but not change it. | | [`not_found`](https://headhoncho.app/docs/api/errors#not_found) | 404 | No such record in the companies this credential reaches. | | [`out_of_scope`](https://headhoncho.app/docs/api/errors#out_of_scope) | 404 | No such company in the companies this credential reaches. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`missing_idempotency_key`](https://headhoncho.app/docs/api/errors#missing_idempotency_key) | 400 | Send an Idempotency-Key header on every command. | | [`idempotency_mismatch`](https://headhoncho.app/docs/api/errors#idempotency_mismatch) | 409 | This Idempotency-Key was used with a different body. | | [`idempotency_in_progress`](https://headhoncho.app/docs/api/errors#idempotency_in_progress) | 409 | A command with this Idempotency-Key is still running. Wait a moment and send it again. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [Update company](https://headhoncho.app/docs/api/update_company): Change one company's own facts: name, service area, time zone, country, color, week, opening hours or service places. Only what you send changes. - [Create company](https://headhoncho.app/docs/api/create_company): Add another company to the workspace. It starts with the first company's time zone and country unless you send your own. - [Update organization](https://headhoncho.app/docs/api/update_organization): Rename the workspace. A company still carrying the old workspace name is renamed with it. - [Add job type](https://headhoncho.app/docs/api/add_job_type): Add a kind of work the business does, such as Local move or Roof repair. A name already in use is refused. - [Update job type](https://headhoncho.app/docs/api/update_job_type): Rename a job type, move it in the list, or retire it so new jobs cannot pick it. Old jobs keep it. - [Update job status](https://headhoncho.app/docs/api/update_job_status): Rename a status, change its look, move it in the list, or retire it. A rename shows on every job at once. Its slug and band stay. - [Set status band](https://headhoncho.app/docs/api/set_status_band): Put a status on the line (a step every job passes) or off it as a detour (a place a job gets stuck). The line closes up behind it. - [Replace job status](https://headhoncho.app/docs/api/replace_job_status): Let another status stand in for this one: move its jobs onto the new status, retire the old word, or both. Name an existing status or a new one. - [Add job status](https://headhoncho.app/docs/api/add_job_status): Add a status to the workspace's list, on the line or as a detour. It carries no role: it is a name and a color. - [Reorder line](https://headhoncho.app/docs/api/reorder_line): Set the order of the statuses on the line, the order every picker offers. Send every status on the line, once each. - [Update agency feed](https://headhoncho.app/docs/api/update_agency_feed): Change how closed jobs reach the agency: the webhook address, the daily file address and hour, or switch the feed on or off. Secrets are not touched. - [Sync callrail](https://headhoncho.app/docs/api/sync_callrail): Pull the company's new CallRail calls and forms now, match them to jobs, and say how many landed. The hourly sync does this on its own. - [Update callrail tracking](https://headhoncho.app/docs/api/update_callrail_tracking): Set the tracking phone numbers on a company's CallRail connection. They replace the list whole. The webhook signing key is set in the app. - [Sync ad platform](https://headhoncho.app/docs/api/sync_ad_platform): Pull a company's latest campaigns and spend from one ad platform now. The hourly sync does this on its own. - The same records in the app: [Settings](https://headhoncho.app/docs/settings). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "accepted": true, "position": 88601, "sources_cleared": 14, "sources_renamed": 3, "connected": true, "calls_landed": 212, "passes": 1, "complete": true, "forms_landed": 9, "attribution_read": 212 } ``` ### cURL ```bash curl -X POST "https://api.headhoncho.app/api/v1/commands/refresh-sources" \ -H "Authorization: Bearer hh_live_..." \ -H "Idempotency-Key: 6f1d2c9e-1b7a-4c1e-9a52-0d3f8e4b7a10" \ -H "Content-Type: application/json" \ -d '{ "company_id": "cmp_14f5" }' ``` ### Python ```python import requests import uuid response = requests.post( "https://api.headhoncho.app/api/v1/commands/refresh-sources", headers={ "Authorization": "Bearer hh_live_...", "Idempotency-Key": str(uuid.uuid4()), }, json={ "company_id": "cmp_14f5", }, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/commands/refresh-sources", { method: "POST", headers: { Authorization: "Bearer hh_live_...", "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "company_id": "cmp_14f5" }), }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: refresh_sources Arguments: company_id (id, required) Access: do on Company settings Hints: readOnly=false, destructive=false, idempotent=true, openWorld=false Try asking: "Using HeadHoncho, refresh sources with company_id cmp_14f5." ``` --- # Sync ad platform Sync ad platform is a command in the HeadHoncho API. Pull a company's latest campaigns and spend from one ad platform now. The hourly sync does this on its own. Page: https://headhoncho.app/docs/api/sync_ad_platform | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json | Everything in one file: https://headhoncho.app/docs/api/llms-full.txt ## The request Reference for **Sync ad platform**, HeadHoncho API v1. It is a command, sent to the base address `https://api.headhoncho.app`. `POST /api/v1/commands/sync-ad-platform` The key needs the **Company settings** area at **do**. An answered call costs 1 credit; a refusal costs nothing. See [credits](https://headhoncho.app/docs/api/errors#credits). It runs the app's own command `sync-ad-platform`. Send an `Idempotency-Key` header with every call: the same key with the same body returns the first answer and runs nothing twice. See [the model](https://headhoncho.app/docs/api/model#idempotency). ## Parameters | Name | Kind | Required | Description | Example | | --- | --- | --- | --- | --- | | `company_id` | id, in the JSON body | Yes | The company, from Who am I. | `cmp_14f5` | | `provider` | text, in the JSON body | Yes | The platform to pull. One of `google_ads`, `meta_ads`, `microsoft_ads`. | `google_ads` | ## Try it with your key Paste your key and change the values. The box builds the call as a cURL line and a fetch line, ready to copy. It never sends anything itself. Paste your key on the web page and it fills a cURL line and a fetch line with your key and the example values. The page never sends the key anywhere. The same lines with a placeholder key are under Examples below. ## What comes back accepted, position, connection_id, rows_landed (spend days), campaigns, ad_groups and ad_group_rows_landed. If the platform refused, rows_landed is 0 and error says why. A platform that is not connected, or was disconnected, is refused with 422. It never deletes anything. It changes only what the command names, and it writes the change to the job's history with who asked for it. ## Every field in the answer Types are read from the example answer. Money is a plain number in the company's currency. A time carries its offset from UTC (`Z` is UTC). Ids are opaque text. A field with no line of its own here has its name spelled out; the common fields mean the same on every page. | Field | Type | Meaning | | --- | --- | --- | | `accepted` | true or false | True when the command ran. A command that cannot run is an error instead. | | `position` | whole number | Where the change landed in the event log. Pass it as `after` on a read to see your own write. | | `connection_id` | id (text) | The id of the connection. | | `rows_landed` | whole number | The rows landed. | | `campaigns` | whole number | The campaigns. | | `ad_groups` | whole number | The ad groups. | | `ad_group_rows_landed` | whole number | The ad group rows landed. | ## It calls the platform Each call makes real requests to the ad platform on this company's own sign-in. It pulls the usual recent days. The long re-pull stays with the weekly job. ## Errors that apply | Code | Status | What it means | | --- | --- | --- | | [`missing_key`](https://headhoncho.app/docs/api/errors#missing_key) | 401 | Send your key as Authorization: Bearer hh_live_... | | [`unknown_key`](https://headhoncho.app/docs/api/errors#unknown_key) | 401 | That key is not one we issued, or it was revoked. | | [`no_access`](https://headhoncho.app/docs/api/errors#no_access) | 403 | This credential does not reach that. Ask the person who made it for access. | | [`read_only`](https://headhoncho.app/docs/api/errors#read_only) | 403 | This credential may read this area but not change it. | | [`not_found`](https://headhoncho.app/docs/api/errors#not_found) | 404 | No such record in the companies this credential reaches. | | [`out_of_scope`](https://headhoncho.app/docs/api/errors#out_of_scope) | 404 | No such company in the companies this credential reaches. | | [`invalid`](https://headhoncho.app/docs/api/errors#invalid) | 422 | Some fields were refused. See fields. | | [`missing_idempotency_key`](https://headhoncho.app/docs/api/errors#missing_idempotency_key) | 400 | Send an Idempotency-Key header on every command. | | [`idempotency_mismatch`](https://headhoncho.app/docs/api/errors#idempotency_mismatch) | 409 | This Idempotency-Key was used with a different body. | | [`idempotency_in_progress`](https://headhoncho.app/docs/api/errors#idempotency_in_progress) | 409 | A command with this Idempotency-Key is still running. Wait a moment and send it again. | | [`no_credits`](https://headhoncho.app/docs/api/errors#no_credits) | 402 | Out of credits. Top up on Settings › Credits, or turn on auto top-up. | ## Related - [Update company](https://headhoncho.app/docs/api/update_company): Change one company's own facts: name, service area, time zone, country, color, week, opening hours or service places. Only what you send changes. - [Create company](https://headhoncho.app/docs/api/create_company): Add another company to the workspace. It starts with the first company's time zone and country unless you send your own. - [Update organization](https://headhoncho.app/docs/api/update_organization): Rename the workspace. A company still carrying the old workspace name is renamed with it. - [Add job type](https://headhoncho.app/docs/api/add_job_type): Add a kind of work the business does, such as Local move or Roof repair. A name already in use is refused. - [Update job type](https://headhoncho.app/docs/api/update_job_type): Rename a job type, move it in the list, or retire it so new jobs cannot pick it. Old jobs keep it. - [Update job status](https://headhoncho.app/docs/api/update_job_status): Rename a status, change its look, move it in the list, or retire it. A rename shows on every job at once. Its slug and band stay. - [Set status band](https://headhoncho.app/docs/api/set_status_band): Put a status on the line (a step every job passes) or off it as a detour (a place a job gets stuck). The line closes up behind it. - [Replace job status](https://headhoncho.app/docs/api/replace_job_status): Let another status stand in for this one: move its jobs onto the new status, retire the old word, or both. Name an existing status or a new one. - [Add job status](https://headhoncho.app/docs/api/add_job_status): Add a status to the workspace's list, on the line or as a detour. It carries no role: it is a name and a color. - [Reorder line](https://headhoncho.app/docs/api/reorder_line): Set the order of the statuses on the line, the order every picker offers. Send every status on the line, once each. - [Update agency feed](https://headhoncho.app/docs/api/update_agency_feed): Change how closed jobs reach the agency: the webhook address, the daily file address and hour, or switch the feed on or off. Secrets are not touched. - [Sync callrail](https://headhoncho.app/docs/api/sync_callrail): Pull the company's new CallRail calls and forms now, match them to jobs, and say how many landed. The hourly sync does this on its own. - [Update callrail tracking](https://headhoncho.app/docs/api/update_callrail_tracking): Set the tracking phone numbers on a company's CallRail connection. They replace the list whole. The webhook signing key is set in the app. - [Refresh sources](https://headhoncho.app/docs/api/refresh_sources): Clear the Call center source stamped on a company's jobs, pull all its CallRail history again and re-read every call, so each job's source is worked out afresh. - The same records in the app: [Settings](https://headhoncho.app/docs/settings). - How the API fits together: [the model](https://headhoncho.app/docs/api/model), [API keys](https://headhoncho.app/docs/api/keys), [errors](https://headhoncho.app/docs/api/errors) and [the MCP server](https://headhoncho.app/docs/api/mcp). ## Examples ### Answer ```json { "accepted": true, "position": 88601, "connection_id": "adc_5e10", "rows_landed": 62, "campaigns": 7, "ad_groups": 19, "ad_group_rows_landed": 140 } ``` ### cURL ```bash curl -X POST "https://api.headhoncho.app/api/v1/commands/sync-ad-platform" \ -H "Authorization: Bearer hh_live_..." \ -H "Idempotency-Key: 6f1d2c9e-1b7a-4c1e-9a52-0d3f8e4b7a10" \ -H "Content-Type: application/json" \ -d '{ "company_id": "cmp_14f5", "provider": "google_ads" }' ``` ### Python ```python import requests import uuid response = requests.post( "https://api.headhoncho.app/api/v1/commands/sync-ad-platform", headers={ "Authorization": "Bearer hh_live_...", "Idempotency-Key": str(uuid.uuid4()), }, json={ "company_id": "cmp_14f5", "provider": "google_ads", }, ) response.raise_for_status() print(response.json()) ``` ### JavaScript ```javascript const response = await fetch("https://api.headhoncho.app/api/v1/commands/sync-ad-platform", { method: "POST", headers: { Authorization: "Bearer hh_live_...", "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "company_id": "cmp_14f5", "provider": "google_ads" }), }); const data = await response.json(); console.log(data); ``` ### Your AI ```text Tool: sync_ad_platform Arguments: company_id (id, required), provider (text, required) Access: do on Company settings Hints: readOnly=false, destructive=false, idempotent=true, openWorld=false Try asking: "Using HeadHoncho, sync ad platform with company_id cmp_14f5 and provider google_ads." ```