HeadHoncho

Building with HeadHoncho

Short rules for a coding agent writing against the HeadHoncho API: auth, idempotency, pages, errors and which endpoint does which job.

Read as Markdown

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. The OpenAPI file (YAML) generates a client. All the docs are also one Markdown file: 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.

## 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/<verb> 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=<position>` 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.
  • A key holds each area at read or do. A read-only key calling a command is refused with `read_only`. An area the key lacks is `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`.
  • 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`. 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=<position> 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 with what causes it and how to fix it.
  • A 422 `invalid` names each refused field in error.fields. Fix the field. Do not resend unchanged.
  • A 402 `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 thisCall
See who the key is, its companies and the ids commands takeWhoami
List jobs and leads, newest first, a page at a timeList jobs
Read one job by id or numberGet job
Open a job or a leadCreate job
Move a job to another statusChange job status
Put a technician on a jobAssign worker
Add a note to a jobAdd job note
See what a job quoted, collected and left as profitGet job money
Record a payment on a jobRecord payment
See what each technician is owedList balances
Read the raw rows an ad platform or call tracker reportedRead table
Get the file Google Ads needs to credit the jobsExport click id report

Every endpoint, by group. Each id is a page at /docs/api/<id> 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.
  • Do not store the key in a repository, a log or a page a browser loads.

See also: recipes, the MCP server and the changelog.