API reference: admin

Every endpoint a staff token can use: everything the admin panel does.

Every endpoint of the admin half of the API, 724 in all, grouped by area. How to sign in, the envelope every answer uses, paging, errors and permissions are on REST API and webhooks; this page is the list.

A staff token is needed for every address here. It can do exactly what its owner can do on the screens, or less if it was narrowed when it was made, and nothing in a module the workspace has switched off.

Customers and leads

MethodAddressWhat it does
POST/api/v1/categoriesAdd an entry to a list; returns its id and name.
GET/api/v1/customersList the customers the caller may see, alphabetically.
POST/api/v1/customersCreate a customer.
GET/api/v1/customers/{customer}Show one customer with its contacts, notes and files.
PUT / PATCH/api/v1/customers/{customer}Change a customer.
DELETE/api/v1/customers/{customer}Delete a customer.
POST/api/v1/customers/{customer}/contactsAdd a contact to a customer.
GET/api/v1/customers/{customer}/contacts/{contact}Show one contact as the contact form does, with their custom fields and which parts of the portal they may use.
PUT / PATCH/api/v1/customers/{customer}/contacts/{contact}Change a contact.
DELETE/api/v1/customers/{customer}/contacts/{contact}Remove a contact. When it was the primary contact, the longest-standing of the others becomes primary.
GET/api/v1/customers/{customer}/contacts/{contact}/privacyA contact's privacy page: their details, whether they were anonymised, whether their company has invoices (which anonymising keeps), and their consents - the current answer for each purpose and the history.
POST/api/v1/customers/{customer}/contacts/{contact}/privacy/anonymiseAnonymise a contact: their name, email and phone are replaced, their portal account closed and their consents removed. Cannot be undone; invoices and other financial records are kept. 422 when already done.
GET/api/v1/customers/{customer}/contacts/{contact}/privacy/consentWhat recording a contact's consent offers: the purposes that can be answered, how staff may say it was obtained, and the current answers.
POST/api/v1/customers/{customer}/contacts/{contact}/privacy/consentRecord that a contact gave or withdrew a consent.
GET/api/v1/customers/{customer}/contacts/{contact}/privacy/exportDownload everything held about a contact, as a zip of JSON and CSV files. It includes internal notes: read it before sending it on.
PATCH/api/v1/customers/{customer}/contacts/{contact}/revokeTake a contact's portal access away (their password is removed) without deleting their details.
POST/api/v1/customers/{customer}/filesUpload files to a customer; returns the files added.
DELETE/api/v1/customers/{customer}/files/{attachment}Remove one of a customer's files.
GET/api/v1/customers/{customer}/privacy-exportDownload everything held about a customer and the people at it, as a zip of JSON and CSV files.
GET/api/v1/customers/{customer}/vaultList a customer's vault entries, without their passwords or notes.
POST/api/v1/customers/{customer}/vaultSave a credential to a customer's vault.
PUT / PATCH/api/v1/customers/{customer}/vault/{entry}Change a vault entry.
DELETE/api/v1/customers/{customer}/vault/{entry}Remove a vault entry.
POST/api/v1/customers/{customer}/vault/{entry}/revealHand over one password, and record that the caller took it.
GET/api/v1/lead-formsList every web form, by name, with its address and how many leads it has brought in.
POST/api/v1/lead-formsCreate a form. It starts with five questions (name, email, phone, company and "how can we help?"), so it works at once.
GET/api/v1/lead-forms/{form}Show one form with its questions, in order.
PUT / PATCH/api/v1/lead-forms/{form}Change a form's settings.
DELETE/api/v1/lead-forms/{form}Delete a form. Its public address stops working; its leads stay.
POST/api/v1/lead-forms/{form}/fieldsAdd a question to a form, at the end.
POST/api/v1/lead-forms/{form}/fields/orderPut a form's questions in a new order; returns them in that order.
PUT / PATCH/api/v1/lead-forms/{form}/fields/{field}Change a question.
DELETE/api/v1/lead-forms/{form}/fields/{field}Remove a question.
POST/api/v1/lead-forms/{form}/regenerateGive a form a new public address, for one whose old address has got out. The old link and embed code stop working at once.
GET/api/v1/leadsList the leads the caller may see, newest first.
POST/api/v1/leadsCreate a lead - also the endpoint a website contact form posts to.
POST/api/v1/leads/duplicatesFind leads and customers that look like the one given - the "have we got this one already?" check the lead form runs while somebody types.
GET/api/v1/leads/{lead}Show one lead with its notes, files and custom fields.
PUT / PATCH/api/v1/leads/{lead}Change a lead.
DELETE/api/v1/leads/{lead}Delete a lead.
POST/api/v1/leads/{lead}/convertConvert a lead into a customer, with a primary contact from its name and address. Returns the new customer as {id, name} (read it in full from /customers/{id}) and the lead, now marked converted.
POST/api/v1/leads/{lead}/filesUpload files to a lead; returns the files added.
DELETE/api/v1/leads/{lead}/files/{attachment}Remove one of a lead's files.
PATCH/api/v1/leads/{lead}/junkMark a lead as junk, or restore a junk one - the action toggles.
PATCH/api/v1/leads/{lead}/lostMark a lead as lost, or reopen a lost one - the action toggles.
PATCH/api/v1/leads/{lead}/moveMove a lead to another status - a drag on the pipeline board.
POST/api/v1/leads/{lead}/privacy/anonymiseAnonymise a lead. Cannot be undone. 422 when already done.
GET/api/v1/leads/{lead}/privacy/consentWhat recording a lead's consent offers: the purposes that can be answered, how staff may say it was obtained, the current answers and the history.
POST/api/v1/leads/{lead}/privacy/consentRecord that a lead gave or withdrew a consent.
GET/api/v1/leads/{lead}/privacy/exportDownload everything held about a lead, as a zip of JSON and CSV files.
POST/api/v1/notesAdd a note to a lead or a customer.
DELETE/api/v1/notes/{note}Delete a note. Only its author may, or an administrator.
GET/api/v1/portal-registrationsList registrations, newest first, with how many there are in each state.
POST/api/v1/portal-registrations/{registration}/approveApprove a registration waiting for staff: the contact can sign in, and is told so by email. 422 for one already answered or not confirmed.
POST/api/v1/portal-registrations/{registration}/declineDecline a registration, removing the customer and contact it created (a customer invoiced since is kept).
GET/api/v1/privacy-requestsList removal requests, newest first.
POST/api/v1/privacy-requests/{privacyRequest}/approveCarry out a removal request: the contact is told by email, then anonymised. Cannot be undone. 422 for one already answered; 404 while the GDPR tools are off.
POST/api/v1/privacy-requests/{privacyRequest}/declineDecline a removal request and tell the contact why.
GET/api/v1/settings/leadsRead the lead settings, with the choices each one offers.
PUT / PATCH/api/v1/settings/leadsSave the lead settings; returns them as saved.

Invoices, payments, subscriptions and expenses

MethodAddressWhat it does
GET/api/v1/credit-notesList the credit notes the caller may see, newest first. Filters: q (number, reference or customer) and status (open, closed, void). The response's summary.available_credit is the credit still unspent across every open note, as the list page shows it.
POST/api/v1/credit-notesRaise a credit note with the next number.
GET/api/v1/credit-notes/{credit_note}One credit note with its lines, tax summary, the credit still available and every entry spending it (applied to an invoice, or refunded).
PUT / PATCH/api/v1/credit-notes/{credit_note}Change a credit note, with the same fields as raising one. Fields left out keep their current value; items, when sent, replace the lines as a whole, and when left out the lines stay exactly as they are. Refused with 409 once any of its credit has been used.
DELETE/api/v1/credit-notes/{credit_note}Delete a credit note. Refused with 422 while any of its credit is in use.
POST/api/v1/credit-notes/{credit_note}/applyApply credit to one of the same customer's sent invoices; answers with the credit note. Body: invoice_id, amount (no more than the credit left or the invoice's balance), entry_date.
DELETE/api/v1/credit-notes/{credit_note}/entries/{entry}Remove one entry (an application or a refund), putting the credit back; answers with the credit note.
POST/api/v1/credit-notes/{credit_note}/refundRefund credit to the customer rather than setting it against an invoice; answers with the credit note. Body: amount, entry_date, payment_method_id, note.
PATCH/api/v1/credit-notes/{credit_note}/voidVoid a credit note that has not been used; answers with the note.
GET/api/v1/expensesList the expenses the caller may see, newest first. Filters: q (name, reference or description), category (an expense category id) and billable_only=1 (billable and not yet invoiced). The response's summary.total is the sum of every expense the caller may see.
POST/api/v1/expensesRecord an expense. Body: name, description, reference, amount, expense_date, expense_category_id, customer_id, project_id, currency_id, payment_method_id, tax_id, tax_2_id, is_billable, custom_fields (keyed by slug) and a receipt (multipart: pdf, png, jpg or webp).
GET/api/v1/expenses/{expense}One expense - what the edit form is filled with.
PUT / PATCH/api/v1/expenses/{expense}Update an expense, with the same fields as recording one; fields left out keep their current value, the tax rates it was paid at included unless a tax is sent. A new receipt replaces the old.
DELETE/api/v1/expenses/{expense}Delete an expense.
GET/api/v1/invoicesList the invoices the caller may see, newest first.
POST/api/v1/invoicesRaise a draft invoice with the next number.
GET/api/v1/invoices/{invoice}One invoice with its lines, tax summary, payments (and their refunds), the credit applied to it and its custom fields.
PUT / PATCH/api/v1/invoices/{invoice}Change an invoice, with the same fields as creating one. Fields left out keep their current value; items, when sent, replace the lines as a whole, and when left out the lines stay exactly as they are. scheduled_send_at is only ever changed by sending it. Refused with 409 once a payment has been recorded against it.
DELETE/api/v1/invoices/{invoice}Delete an invoice.
GET/api/v1/invoices/{invoice}/e-invoiceDownload the invoice as a UBL 2.1 e-invoice (application/xml). Refused with 409 for a draft.
POST/api/v1/invoices/{invoice}/paymentsRecord a payment received against a sent invoice; answers with the payment, 201. Body: amount (no more than the balance), payment_date, payment_method_id, transaction_id, note, custom_fields. Refused with 422 on a draft.
PATCH/api/v1/invoices/{invoice}/statusSet the status by hand: draft, sent or cancelled (status). Paid and partly paid follow from the payments and cannot be set.
GET/api/v1/itemsList catalogue items by name. Filters: q (name or description) and group (an item group id).
POST/api/v1/itemsAdd an item. Body: name, description, rate, unit, item_group_id, tax_id, tax_2_id, is_active, image (multipart, png/jpg/gif/webp up to 2 MB) and custom_fields.
GET/api/v1/items/{item}One item with its custom fields - what the edit form is filled with.
PUT / PATCH/api/v1/items/{item}Update an item, with the same fields as adding one; fields left out keep their current value. remove_image=1 takes its picture away. Lines already on documents keep their own copy.
DELETE/api/v1/items/{item}Remove an item from the catalogue. Documents that used it are unchanged.
GET/api/v1/payment-batchesList batch payments, newest first.
POST/api/v1/payment-batchesRecord one amount received and put it against invoices; answers with the batch, 201.
GET/api/v1/payment-batches/outstanding/{customer}What a customer owes: their unpaid invoices the caller may see, oldest due first - the order money is usually meant to be applied in.
GET/api/v1/payment-batches/{batch}One batch with the payment it put against each invoice.
DELETE/api/v1/payment-batches/{batch}Reverse a whole batch: every payment in it is removed and each invoice goes back to what its remaining payments say.
GET/api/v1/paymentsList payments on invoices the caller may see, newest first, each with its refunds. Filters: q (transaction id or invoice number).
DELETE/api/v1/payments/{payment}Delete a payment; the invoice's balance and status follow. Refused with 422 while the payment has refunds recorded against it.
POST/api/v1/payments/{payment}/refundRefund some or all of a payment; answers with the payment and its refunds. Body: amount, reason, and online=1 to send the money back through the payment provider the payment came in by (otherwise the refund is only recorded).
GET/api/v1/recurring-expensesList the standing expenses within the caller's expenses scope: active ones first, then by next run.
POST/api/v1/recurring-expensesSet up a standing expense. Body: name, description, reference, amount, currency_id, expense_category_id, payment_method_id, tax_id, tax_2_id, tax_inclusive, customer_id, project_id, is_billable, auto_invoice, auto_send_invoice, billing_unit (day, week, month, year), billing_interval, starts_at, ends_at, total_cycles and is_active.
POST/api/v1/recurring-expenses/{recurringExpense}/runRecord the one that is due now, without waiting for the scheduler; answers with the expense recorded, 201. Refused with 422 when nothing is due.
GET/api/v1/recurring-expenses/{recurring_expense}One standing expense - what the edit form is filled with.
PUT / PATCH/api/v1/recurring-expenses/{recurring_expense}Update a standing expense, with the same fields as setting one up; fields left out keep their current value, the tax rates included unless a tax is sent. Moving the first date before the first run moves the next run with it.
DELETE/api/v1/recurring-expenses/{recurring_expense}Delete a standing expense. The expenses it already recorded are kept.
DELETE/api/v1/refunds/{refund}Remove a refund recorded by hand; the invoice goes back to what its payments say. A refund made through a payment provider is refused (422).
GET/api/v1/subscriptionsList the subscriptions the caller may see, next to bill first. Filters: q (name or customer) and status. The response's summary carries the list page's figures: active count, due count and the recurring total.
POST/api/v1/subscriptionsSet up a subscription (it starts as a draft; activate it with the status endpoint).
GET/api/v1/subscriptions/{subscription}One subscription with its lines, tax summary and the invoices it has raised.
PUT / PATCH/api/v1/subscriptions/{subscription}Change a subscription, with the same fields as setting one up. Fields left out keep their current value; items, when sent, replace the lines as a whole, and when left out the lines stay exactly as they are. Its billing schedule is kept.
DELETE/api/v1/subscriptions/{subscription}Delete a subscription. The invoices it already raised are kept.
POST/api/v1/subscriptions/{subscription}/billRaise the next invoice now, without waiting for the scheduler; answers with the invoice's id and number, 201. Refused with 422 when the subscription is not active and due.
PATCH/api/v1/subscriptions/{subscription}/statusStart, pause, resume or cancel (status: draft, active, paused, cancelled).
GET/api/v1/contract-templatesList every contract template by name, wording included.
POST/api/v1/contract-templatesSave a new template.
GET/api/v1/contract-templates/{template}One template, as its edit form shows it. Needs contracts.edit, as the form does.
PUT / PATCH/api/v1/contract-templates/{template}Change a template. Body as for create; fields left out keep their current value.
DELETE/api/v1/contract-templates/{template}Remove a template. Contracts made from it are not affected.
GET/api/v1/contractsList the contracts the caller may see, newest first.
POST/api/v1/contractsCreate a contract.
GET/api/v1/contracts/{contract}One contract with its wording, custom fields, every signature given (with how, when and from where) and the statement signers agree to.
PUT / PATCH/api/v1/contracts/{contract}Change a contract, with the same fields as creating one; fields left out keep their current value. Refused (409) once anybody has signed it.
DELETE/api/v1/contracts/{contract}Delete a contract for good. (PATCH ../trash moves it to the trash instead.)
POST/api/v1/contracts/{contract}/countersignSign on behalf of the business. Needs document_signing.sign as well as contracts.view.
POST/api/v1/contracts/{contract}/duplicateMake an unsigned copy of a contract, hidden from the customer until somebody has looked at it. Answers 201 with the copy.
POST/api/v1/contracts/{contract}/save-as-templateKeep a contract's wording, value, term and signing set-up as a template. Body: name (unique among the templates). Answers 201 with the template, as GET /api/v1/contract-templates/{template} returns it.
POST/api/v1/contracts/{contract}/signRecord the customer's signature, given in person in front of the caller, who is recorded as the witness.
PATCH/api/v1/contracts/{contract}/trashMove a contract into the trash, or back out of it. Answers with the contract; is_trashed says where it now is.
GET/api/v1/estimate-requestsList the estimate requests the caller may see, newest first.
GET/api/v1/estimate-requests/fieldsList the questions in the order they are asked, inactive ones included. meta.types names the kinds of question there are.
POST/api/v1/estimate-requests/fieldsAdd a question at the end of the form.
POST/api/v1/estimate-requests/fields/orderPut the questions in a new order. Body: order (question ids, first to last). Answers with the questions in their new order.
PUT / PATCH/api/v1/estimate-requests/fields/{field}Change a question. Body as for create; fields left out keep their current value.
DELETE/api/v1/estimate-requests/fields/{field}Remove a question. Answers already given are kept on each request.
GET/api/v1/estimate-requests/statusesList the statuses in order, each with how many of the requests the caller may see are in it. meta.colours lists the colours a status may take.
POST/api/v1/estimate-requests/statusesAdd a status of the workspace's own. Body: name, colour, sort_order (optional), is_finished. Its key is made from the name. Answers 201.
PUT / PATCH/api/v1/estimate-requests/statuses/{status}Rename, recolour or reorder a status. Body as for create; fields left out keep their current value, and the key never changes.
DELETE/api/v1/estimate-requests/statuses/{status}Remove a status. Refused (422) for a built-in one, or while any request is still in it.
GET/api/v1/estimate-requests/{estimateRequest}One estimate request with the answers to the workspace's own questions and the files that came with it.
DELETE/api/v1/estimate-requests/{estimateRequest}Delete a request and its files. An estimate written in reply stays.
PATCH/api/v1/estimate-requests/{estimateRequest}/assignHand a request to a member of staff, or take it off them. Body: assigned_to (an active staff user id, or null).
PATCH/api/v1/estimate-requests/{estimateRequest}/statusMove a request to another status. Body: status (one of the workspace's status keys).
GET/api/v1/estimatesList the estimates the caller may see, newest first.
POST/api/v1/estimatesCreate a draft estimate, numbered from the workspace's sequence.
GET/api/v1/estimates/{estimate}One estimate with its lines, tax summary, custom fields, signatures, the discussion (internal comments included) and the request it answers.
PUT / PATCH/api/v1/estimates/{estimate}Change an estimate, with the same fields as creating one. Fields left out keep their current value; items, when sent, replace the lines as a whole, and when left out the lines stay exactly as they are. An accepted estimate must have its acceptance revoked first (409), a converted one cannot be changed at all (409), and saving clears any signature, since it was given to different figures.
DELETE/api/v1/estimates/{estimate}Delete an estimate.
POST/api/v1/estimates/{estimate}/convertTurn an estimate into an invoice, once. Answers 201 with the new invoice's id and number; 409 when it has already been invoiced.
POST/api/v1/estimates/{estimate}/projectOpen the project an estimate describes. Body: project_template_id (optional). Answers 201 with the new project's id and name.
POST/api/v1/estimates/{estimate}/revoke-acceptanceUndo an acceptance so the estimate can be edited again. Refused (422) for an estimate that was never accepted or has already been invoiced.
PATCH/api/v1/estimates/{estimate}/statusMark an estimate draft, sent, accepted or declined.
GET/api/v1/proposalsList the proposals the caller may see, newest first.
POST/api/v1/proposalsCreate a draft proposal, numbered from the workspace's sequence.
GET/api/v1/proposals/{proposal}One proposal with its body, recipient, lines, tax summary, custom fields, signatures and the discussion (internal comments included).
PUT / PATCH/api/v1/proposals/{proposal}Change a proposal, with the same fields as creating one. Fields left out keep their current value; items, when sent, replace the lines as a whole, and when left out the lines stay exactly as they are. Sending customer_id or lead_id readdresses it: the other is then cleared unless sent too. An accepted proposal must have its acceptance revoked first (409), a converted one cannot be changed at all (409), and saving clears any signature.
DELETE/api/v1/proposals/{proposal}Delete a proposal.
POST/api/v1/proposals/{proposal}/convertTurn a proposal into an estimate or an invoice, once.
POST/api/v1/proposals/{proposal}/projectOpen the project a proposal describes. Body: project_template_id (optional). Answers 201 with the new project's id and name.
POST/api/v1/proposals/{proposal}/revoke-acceptanceUndo an acceptance so the proposal can be edited again. Refused (422) for a proposal that was never accepted or has already been converted.
PATCH/api/v1/proposals/{proposal}/statusMove a proposal to draft, sent, open, revised, accepted or declined.
POST/api/v1/sales-documents/thread-orderRemember which way round the caller reads a discussion: order "newest" or "oldest" (anything else is read as oldest). Returned as thread_order on every estimate and proposal, with the comments in that order.
POST/api/v1/sales-documents/{kind}/{document}/commentsPost a comment on an estimate or a proposal.
DELETE/api/v1/sales-documents/{kind}/{document}/comments/{comment}Delete a comment. Allowed to its author, or to anyone who may delete that kind of document.
PATCH/api/v1/sales-documents/{kind}/{document}/comments/{comment}/internalFlip a comment between internal and shared with the customer; its files follow. Allowed to its author, or to anyone who may edit that kind of document.

Projects, tasks and time

MethodAddressWhat it does
GET/api/v1/goalsList the goals, latest end date first, each with its progress and state. Somebody who cannot create goals sees only the ones they have a stake in: the company's, their own and their teams'.
POST/api/v1/goalsSet a goal.
GET/api/v1/goals/lookupsThe choices the goal form offers: the kinds of target (and which can belong to a person or team), the staff and the teams.
GET/api/v1/goals/{goal}One goal with its progress.
PUT / PATCH/api/v1/goals/{goal}Change a goal. Takes the same body as setting one; any field left out keeps its current value.
DELETE/api/v1/goals/{goal}Remove a goal.
GET/api/v1/my-listThe caller's list in the order they arranged it, with the labels they have used and how many lines are still open.
POST/api/v1/my-listAdd a line to the bottom of the list. Refused (422) once 500 lines are open.
POST/api/v1/my-list/orderPut the list in a new order.
GET/api/v1/my-list/{todo}One line of the caller's list.
PUT / PATCH/api/v1/my-list/{todo}Change a line. Any field left out keeps its current value.
DELETE/api/v1/my-list/{todo}Remove a line from the list.
POST/api/v1/my-list/{todo}/taskTurn a line into a real task assigned to the caller, once. Needs permission to create tasks.
PATCH/api/v1/my-list/{todo}/tickTick a line, or untick it.
GET/api/v1/project-templatesEvery project template, by name, with how many tasks and milestones it carries.
POST/api/v1/project-templatesCreate an empty template.
GET/api/v1/project-templates/{template}One template's details and the parts of its blueprint.
PUT / PATCH/api/v1/project-templates/{template}Change a template's details. Takes the same body as creating one; any field left out keeps its current value (the web form reads a missing rate as nought).
DELETE/api/v1/project-templates/{template}Delete a template. Projects already started from it are untouched.
POST/api/v1/project-templates/{template}/startStart a new project from a template.
GET/api/v1/projectsList the projects the caller may see, newest first.
POST/api/v1/projectsCreate a project.
GET/api/v1/projects/feedbackList what customers said about the projects the caller may see, newest first, with the average rating, the count and the count per rating.
GET/api/v1/projects/lookupsThe choices the project form offers: the categories this person may file a project under, the templates a project can be started from, the staff who can be members and every customer-portal switch a project can override, with the workspace default for each.
GET/api/v1/projects/{project}One project with its members, milestones, custom fields, portal switches, counts and the tabs the caller may open on it.
PUT / PATCH/api/v1/projects/{project}Change a project. Takes the same body as creating one; any field left out keeps its current value, and `remove_cover` clears the cover picture.
DELETE/api/v1/projects/{project}Delete a project and its tasks. Time logged against them is kept.
POST/api/v1/projects/{project}/commentsPost on a project's discussion thread; everyone on the project is told.
DELETE/api/v1/projects/{project}/comments/{comment}Delete a comment. For its author, or somebody who may delete projects.
PATCH/api/v1/projects/{project}/comments/{comment}/internalTurn a comment into an internal aside, or back again; its files follow. For its author, or somebody who may edit the project.
POST/api/v1/projects/{project}/duplicateDuplicate a project, choosing what comes with it.
GET/api/v1/projects/{project}/exportDownload everything about a project as a zip of CSV files.
DELETE/api/v1/projects/{project}/feedback/{feedback}Remove a piece of feedback.
POST/api/v1/projects/{project}/feedback/{feedback}/replyAnswer a customer's feedback. Once answered, the customer can no longer change what they wrote.
POST/api/v1/projects/{project}/filesUpload files to a project's Files tab.
GET/api/v1/projects/{project}/files/{file}Download one of a project's files, under the name it was uploaded with.
DELETE/api/v1/projects/{project}/files/{file}Delete one of a project's files.
POST/api/v1/projects/{project}/files/{file}/commentsReply on a file's own thread.
PATCH/api/v1/projects/{project}/files/{file}/visibilityShow a file to the customer in the portal, or hide it again.
GET/api/v1/projects/{project}/invoiceWhat an invoice for this project would say right now - its lines and subtotal before tax - before anybody commits to raising it.
POST/api/v1/projects/{project}/invoiceRaise a draft invoice for the project and mark the time it bills as invoiced. Refused (422) when the project has no customer or nothing to bill. Answers with the draft; the invoice endpoints take it from there.
POST/api/v1/projects/{project}/milestonesAdd a milestone to a project.
PUT / PATCH/api/v1/projects/{project}/milestones/{milestone}Change a milestone. Takes the same body as adding one; any field left out keeps its current value.
DELETE/api/v1/projects/{project}/milestones/{milestone}Remove a milestone. Its tasks stay on the project, without a milestone.
GET/api/v1/projects/{project}/previewThe project as one of its customer's contacts sees it in the portal: which tabs they get, every portal switch's final answer, and one tab's records exactly as the portal would list them.
POST/api/v1/projects/{project}/save-as-templateSave a project's milestones, tasks, checklists and members as a new template.
GET/api/v1/projects/{project}/tabs/{tab}The records on one tab of the project page: overview, tasks, board, milestones, gantt, timesheets, files, comments, notes, activity, tickets, contracts, sales or feedback.
GET/api/v1/tasksList the tasks the caller may see, those due soonest first.
POST/api/v1/tasksCreate a task.
POST/api/v1/tasks/add-severalAdd several tasks at once, one per line of `titles`, sharing `task_status_id` (required), `task_priority_id`, `project_id`, `due_date` and `assignee_id`. At most 50. Answers with the new tasks.
GET/api/v1/tasks/lookupsThe choices the task forms offer: statuses, priorities, the projects the caller may see with their milestones, staff, the kinds of record a task can be related to, repeat periods and checklist templates.
GET/api/v1/tasks/timelineThe task timeline: the same tasks the list shows (same filters), as Gantt rows grouped by project, at most 300 of them. `limited` says when there were more than that.
GET/api/v1/tasks/{task}One task with everything its page shows: description, people, checklist, what it waits for and what waits for it, time logged, the caller's running timer, other occurrences of a repeating task, commits that mention it, the whole comment thread (internal comments included) and, for somebody who may read the log, its latest activity.
PUT / PATCH/api/v1/tasks/{task}Change a task. Takes the same body as creating one; any field left out keeps its current value. Refused (422) when it would be marked done while a task it waits for is not.
DELETE/api/v1/tasks/{task}Delete a task.
POST/api/v1/tasks/{task}/checklistAdd a line to a task's checklist.
POST/api/v1/tasks/{task}/checklist/from-templateAdd a checklist template's lines after whatever the task already has.
POST/api/v1/tasks/{task}/checklist/save-templateKeep this task's checklist wording as a new checklist template. Needs the settings permission, as on the task page.
PATCH/api/v1/tasks/{task}/checklist/{item}Tick a checklist line, or untick it. Answers with the line and the checklist's progress in per cent.
DELETE/api/v1/tasks/{task}/checklist/{item}Remove a checklist line.
POST/api/v1/tasks/{task}/commentsComment on a task; the people on it are told. Shared with the customer (when the task and the project allow it) unless `is_internal`.
DELETE/api/v1/tasks/{task}/comments/{comment}Delete a comment. For its author, or somebody who may delete tasks.
PATCH/api/v1/tasks/{task}/comments/{comment}/internalHide a comment from the customer, or share it again; its files follow. A customer's own comment cannot be hidden from them (422).
PATCH/api/v1/tasks/{task}/comments/{comment}/pinPin a comment to the top of the thread, or take the pin off.
DELETE/api/v1/tasks/{task}/coverRemove a task's cover picture.
POST/api/v1/tasks/{task}/dependenciesMake a task wait for another one, which the caller must be able to see. Refused (422) when that would make a loop.
DELETE/api/v1/tasks/{task}/dependencies/{dependency}Stop a task waiting for another one.
POST/api/v1/tasks/{task}/duplicateDuplicate a task.
PATCH/api/v1/tasks/{task}/moveMove a task on the board: a new status, and optionally its position.
POST/api/v1/tasks/{task}/timerStart the caller's timer on a task. Answers with the running entry; stop it with PATCH /timesheets/{timesheet}/stop.
GET/api/v1/timesheetsList the time entries the caller may see, newest first, with the total and the billable-but-not-invoiced total of everything that matches.
POST/api/v1/timesheetsLog time by hand.
GET/api/v1/timesheets/lookupsThe choices the timesheet form and filters offer: the projects, tasks and tickets the caller may log against, the staff they may log for, whether they may log for anybody but themselves, and the tags in use.
GET/api/v1/timesheets/{timesheet}One time entry.
PUT / PATCH/api/v1/timesheets/{timesheet}Change a time entry. Takes the same body as logging one; any field left out keeps its current value.
DELETE/api/v1/timesheets/{timesheet}Remove a time entry. Time already invoiced cannot be removed (422).
PATCH/api/v1/timesheets/{timesheet}/stopStop the caller's own running timer. Answers with the finished entry.

Support: tickets, knowledge base and wiki

MethodAddressWhat it does
GET/api/v1/knowledge-baseList the knowledge-base articles, in the order the screen shows them.
POST/api/v1/knowledge-baseWrite an article.
GET/api/v1/knowledge-base/groupsList the knowledge-base categories with how many articles each holds.
POST/api/v1/knowledge-base/groupsAdd a category.
GET/api/v1/knowledge-base/groups/{group}One category.
PUT / PATCH/api/v1/knowledge-base/groups/{group}Change a category. Takes the same body as POST /knowledge-base/groups; only the fields sent are changed.
DELETE/api/v1/knowledge-base/groups/{group}Remove a category; its articles are kept, uncategorised.
GET/api/v1/knowledge-base/videosList the video gallery, in the order the screen shows it.
POST/api/v1/knowledge-base/videosAdd a video to the gallery.
GET/api/v1/knowledge-base/videos/{video}One video.
PUT / PATCH/api/v1/knowledge-base/videos/{video}Change a video. Takes the same body as POST /knowledge-base/videos; only the fields sent are changed.
DELETE/api/v1/knowledge-base/videos/{video}Remove a video from the gallery.
GET/api/v1/knowledge-base/{article}One article with its full text and custom fields.
PUT / PATCH/api/v1/knowledge-base/{article}Change an article. Takes the same body as POST /knowledge-base; only the fields sent are changed, custom fields one by one.
DELETE/api/v1/knowledge-base/{article}Delete an article.
GET/api/v1/ticketsList the tickets in the queue that the caller may see, longest-waiting first.
POST/api/v1/ticketsOpen a ticket on a customer's behalf; the opening message is recorded as theirs.
GET/api/v1/tickets/optionsWhat the ticket form and the queue's filters offer: statuses, departments, services, priorities, tags, the active staff, and the saved ticket templates.
GET/api/v1/tickets/{ticket}One ticket with its whole conversation, private notes included, its attachments, tags and custom fields.
PUT / PATCH/api/v1/tickets/{ticket}Change a ticket's details.
DELETE/api/v1/tickets/{ticket}Delete a ticket.
PATCH/api/v1/tickets/{ticket}/archiveArchive a ticket, or bring an archived one back to the queue (a toggle).
PATCH/api/v1/tickets/{ticket}/assignAssign a ticket to a member of staff, or to nobody. Body: assigned_to (a staff user id, or null).
POST/api/v1/tickets/{ticket}/link-contactFile a ticket from the public form against the contact who wrote it.
POST/api/v1/tickets/{ticket}/mergeMerge this ticket into another; answers with the ticket merged into.
POST/api/v1/tickets/{ticket}/repliesReply to a ticket, or add a private note, as the caller.
DELETE/api/v1/tickets/{ticket}/replies/{reply}Remove one reply or note from a ticket; the opening message cannot be removed (422).
PATCH/api/v1/tickets/{ticket}/statusSet a ticket's status. Body: ticket_status_id.
GET/api/v1/wikiThe wiki's pages as the sidebar shows them: the top-level pages, each with the pages filed under it.
POST/api/v1/wikiWrite a page.
GET/api/v1/wiki/{page}One page: its text, where it sits, the pages under it, its attachments and its last 20 revisions.
PUT / PATCH/api/v1/wiki/{page}Change a page; what it said until now is kept as a revision.
DELETE/api/v1/wiki/{page}Delete a page; the pages filed under it move up a level.
POST/api/v1/wiki/{page}/revisions/{revision}/restorePut an earlier revision of a page back; the current text is kept as a revision first, so this can be undone.

Staff, roles, teams and HR

MethodAddressWhat it does
GET/api/v1/announcementsList the announcements on the caller's board, newest first.
POST/api/v1/announcementsPost an announcement.
GET/api/v1/announcements/{announcement}One announcement, as the edit form holds it.
PUT / PATCH/api/v1/announcements/{announcement}Change an announcement; everybody who had dismissed it sees it again. Takes the same body as POST /announcements; any field left out keeps its current value.
DELETE/api/v1/announcements/{announcement}Remove an announcement.
POST/api/v1/announcements/{announcement}/dismissClose an announcement's banner for the caller. Needs no permission: it changes only what the caller sees.
GET/api/v1/attendanceList the shifts of one month that the caller may see, latest first.
POST/api/v1/attendanceRecord a shift by hand.
POST/api/v1/attendance/clock-inClock the caller in; answers with the open shift. Body: note.
POST/api/v1/attendance/clock-outClock the caller out; answers with the shift just closed.
GET/api/v1/attendance/summaryThe attendance screen's panel for one month: the caller's open shift, hours and days per person, who is away today, and whether the caller may type a shift in by hand.
GET/api/v1/attendance/{entry}One shift, as the edit form holds it.
PUT / PATCH/api/v1/attendance/{entry}Correct a shift. Takes the same body as POST /attendance; any field left out keeps its current value.
DELETE/api/v1/attendance/{entry}Delete a shift.
GET/api/v1/leaveList the leave requests the caller may see, latest start first.
POST/api/v1/leaveRequest leave, or record it when its type needs no approval.
GET/api/v1/leave/summaryThe caller's leave balances for this leave year, how many requests they may see are waiting for an answer, and who is away today.
GET/api/v1/leave/typesThe leave types a request can be made under.
GET/api/v1/leave/{leave}One leave request - the caller's own, or anybody's within their scope for an approver - as the edit form holds it.
PUT / PATCH/api/v1/leave/{leave}Change a leave request. Takes the same body as POST /leave; any field left out keeps its current value. An answered request can be changed only by an approver who did not make it.
DELETE/api/v1/leave/{leave}Delete a leave request.
PATCH/api/v1/leave/{leave}/cancelWithdraw a leave request - one's own, or as an approver - while it is pending or has not yet ended.
PATCH/api/v1/leave/{leave}/decideApprove or decline a leave request; nobody may answer their own.
GET/api/v1/messagesList the caller's conversations, newest activity first, each with its latest message and how many messages in it are unread.
GET/api/v1/messages/colleaguesThe colleagues the caller may start a conversation with, and whether they may start one at all.
GET/api/v1/messages/customersList the portal threads the caller is in, newest activity first, each with its customer, the other people in it and how many messages are unread.
GET/api/v1/messages/customers/{conversation}One portal thread with all its messages and their attachments; reading it marks it read.
POST/api/v1/messages/customers/{conversation}Answer in a portal thread; answers with the thread.
POST/api/v1/messages/direct/{user}Open the one-to-one conversation with a colleague, starting it if the two have none yet; answers with the conversation.
POST/api/v1/messages/groupStart a group conversation.
POST/api/v1/messages/{conversation}Send a message in a conversation the caller is in. Body: body (required).
DELETE/api/v1/messages/{conversation}/leaveLeave a group conversation (a one-to-one cannot be left: 422). The last person out closes it.
GET/api/v1/messages/{conversation}/pollThe messages of a conversation the caller is in, oldest first, up to 50 at a time; reading them marks the conversation read.
GET/api/v1/rolesList the roles, by name, with how many people hold each.
POST/api/v1/rolesCreate a role.
GET/api/v1/roles/permissionsWhat a role can grant: every permission module with its abilities and scopes, what each scope means, the restrictions a module can be narrowed by and their options, and the read-only preset the role form offers.
GET/api/v1/roles/{role}One role with its permission map.
PUT / PATCH/api/v1/roles/{role}Change a role. Takes the same body as POST /roles; any field left out keeps its current value, and permissions, when sent, replaces the whole map. The administrator role's permissions are not changed, whatever is sent.
DELETE/api/v1/roles/{role}Delete a role; refused for a system role and for one still held by anybody.
POST/api/v1/roles/{role}/cloneCopy a role as a starting point for a similar one: "Copy of ..", never a system or administrator role.
GET/api/v1/staffList the staff the caller may see, by first name.
POST/api/v1/staffAdd a member of staff.
GET/api/v1/staff/{user}One person's profile: their details and teams, the projects and tasks they work on (as far as the caller may see those), their teammates, their recent activity (for a caller who may read the activity log) and the headline figures.
PUT / PATCH/api/v1/staff/{user}Change a member of staff. Takes the same body as POST /staff, the password optional and any field left out kept as it is; what the caller may not change (see may_change_credentials and may_change_role on GET /staff/{user}) is kept as it was.
DELETE/api/v1/staff/{user}Delete a member of staff.
GET/api/v1/staff/{user}/assignThe running projects the caller may give this person work on, each saying whether they are on its team already, and which halves of the assignment the caller may do (tasks.edit hands out tasks, projects.edit adds to a project's team).
POST/api/v1/staff/{user}/assignPut this person on a project's team and/or on some of its open tasks.
GET/api/v1/staff/{user}/assign/tasksThe open tasks of one project that could be given to this person, each saying whether it is theirs already. Filter: project_id (required).
GET/api/v1/staff/{user}/permissionsThis person's role and the permissions changed for them alone on top of it; needs staff.edit and roles.edit.
PUT / PATCH/api/v1/staff/{user}/permissionsReplace this person's permission overrides.
PATCH/api/v1/staff/{user}/toggleDeactivate a member of staff, or reactivate one (a toggle).
GET/api/v1/teamsList the teams, by name, with their members.
POST/api/v1/teamsAdd a team.
GET/api/v1/teams/{team}One team with its members.
PUT / PATCH/api/v1/teams/{team}Change a team. Takes the same body as POST /teams; any field left out keeps its current value. members, when sent, replaces the whole membership; left out, the team keeps its people.
DELETE/api/v1/teams/{team}Remove a team; its people stay, with one team fewer.

Marketing and automations

MethodAddressWhat it does
GET/api/v1/automationsList automation rules, active ones first, with how often each has matched.
POST/api/v1/automationsSave a new rule.
GET/api/v1/automations/createWhat the rule builder offers for a trigger: the triggers themselves, the fields conditions can test, the operators, the actions and their settings, and the workspace's staff, statuses and departments that actions can point at.
GET/api/v1/automations/logList the run log: what each rule did, or why it skipped, newest first.
GET/api/v1/automations/{automation}One rule, together with what the builder offers for its trigger.
PUT / PATCH/api/v1/automations/{automation}Change a rule. Takes the same body as creating one; only the fields sent are changed. conditions[] and actions[], when sent, replace the rule's whole list.
DELETE/api/v1/automations/{automation}Delete a rule.
POST/api/v1/automations/{automation}/resetForget which records a rule has already acted on, so it may act on them again.
POST/api/v1/automations/{automation}/runRun a rule now, for real, against one record - its actions happen.
POST/api/v1/automations/{automation}/run-on/{id}Run a run-by-hand rule on one record, as its button on the record's page does.
POST/api/v1/automations/{automation}/testCheck a rule's conditions against a real record without doing anything to it.
PATCH/api/v1/automations/{automation}/togglePause an active rule, or resume a paused one.
GET/api/v1/campaignsList campaigns, the ones still going out first, each with its figures.
POST/api/v1/campaignsSave a new campaign as a draft; nothing is sent until it is launched.
POST/api/v1/campaigns/aiDraft a campaign's text with the AI writer; nothing is saved or sent.
GET/api/v1/campaigns/audienceCount who a campaign to these lists would reach on this channel.
GET/api/v1/campaigns/createThe options the campaign form offers: the channels with anything that stops each one sending, the merge tags, the text-message footer and whether the AI writer is on.
GET/api/v1/campaigns/{campaign}One campaign with its content, figures, preview, audience and anything standing in the way of sending it.
PUT / PATCH/api/v1/campaigns/{campaign}Change a campaign that has not started sending.
DELETE/api/v1/campaigns/{campaign}Delete a campaign. One that is sending or paused must be cancelled first.
PATCH/api/v1/campaigns/{campaign}/cancelStop a campaign for good; anything not yet sent will not be. Needs campaigns.send.
POST/api/v1/campaigns/{campaign}/duplicateCopy a campaign's content and lists into a new draft, and return the draft.
GET/api/v1/campaigns/{campaign}/exportDownload every message the campaign sent as a CSV file.
POST/api/v1/campaigns/{campaign}/launchSend a draft now, or schedule it for later.
GET/api/v1/campaigns/{campaign}/messagesList the messages a campaign has sent, one per recipient, newest first.
PATCH/api/v1/campaigns/{campaign}/pausePause a campaign that is sending. Needs campaigns.send.
PATCH/api/v1/campaigns/{campaign}/resumeCarry on sending a paused campaign from where it stopped. Needs campaigns.send.
POST/api/v1/campaigns/{campaign}/testSend the campaign to one address, with sample values in the merge tags.
POST/api/v1/campaigns/{campaign}/unscheduleTake a scheduled campaign off the schedule, back to a draft. Needs campaigns.send.
GET/api/v1/message-templatesList message templates by channel and name.
POST/api/v1/message-templatesSave a new message template.
POST/api/v1/message-templates/whatsapp-syncFetch every template on the connected WhatsApp Business Account from Meta.
GET/api/v1/message-templates/{template}One message template, as its edit form shows it.
PUT / PATCH/api/v1/message-templates/{template}Change a message template. Takes the same body as creating one; only the fields sent are changed.
DELETE/api/v1/message-templates/{template}Delete a message template. Campaigns made from it keep their own copy of the content.
GET/api/v1/subscriber-listsList mailing lists by name, with how many people are on each.
POST/api/v1/subscriber-listsCreate a mailing list.
GET/api/v1/subscriber-lists/{list}One mailing list with its settings, sign-up address and how many people are on it in each status.
PUT / PATCH/api/v1/subscriber-lists/{list}Change a mailing list's name, description and sign-up settings. Takes the same body as creating one; only the fields sent are changed.
DELETE/api/v1/subscriber-lists/{list}Delete a mailing list. The people on it stay in All subscribers.
GET/api/v1/subscriber-lists/{list}/exportDownload everybody on the list, with their consent record, as a CSV file.
GET/api/v1/subscriber-lists/{list}/from-crmThe choices for filling a list from the CRM: whether the caller may add leads and customers, and the lead statuses, lead sources, customer groups and tags to filter them by.
POST/api/v1/subscriber-lists/{list}/from-crmAdd the leads or customer contacts matching a filter to the list.
GET/api/v1/subscriber-lists/{list}/subscribersList the people on a mailing list, most recently added first, with the date each joined.
DELETE/api/v1/subscriber-lists/{list}/subscribers/{subscriber}Take one person off a mailing list; they stay subscribed to any others.
GET/api/v1/subscribersList subscribers, newest first.
POST/api/v1/subscribersAdd a subscriber by hand.
GET/api/v1/subscribers/{subscriber}One subscriber with the lists they are on and their consent record.
PUT / PATCH/api/v1/subscribers/{subscriber}Change a subscriber's details and lists.
DELETE/api/v1/subscribers/{subscriber}Delete a subscriber, forgetting who they are. Campaign figures they were part of stay.
PATCH/api/v1/subscribers/{subscriber}/unsubscribeUnsubscribe somebody from everything. Only they can subscribe again.
GET/api/v1/surveysList surveys, newest first, with how many questions and responses each has.
POST/api/v1/surveysCreate a survey; questions are added to it afterwards.
GET/api/v1/surveys/createThe options the survey form offers: statuses, audiences, question types and the workspace's custom fields for surveys.
GET/api/v1/surveys/{survey}One survey with its settings, public address and questions, as the builder shows it.
PUT / PATCH/api/v1/surveys/{survey}Change a survey's settings. Takes the same body as creating one; only the fields sent are changed, custom fields one by one. It cannot be opened with no questions.
DELETE/api/v1/surveys/{survey}Delete a survey together with every answer given to it.
GET/api/v1/surveys/{survey}/exportDownload every response as a CSV file, one row per response and a column per question.
POST/api/v1/surveys/{survey}/questionsAdd a question to the end of a survey.
POST/api/v1/surveys/{survey}/questions/reorderPut a survey's questions in a new order.
PUT / PATCH/api/v1/surveys/{survey}/questions/{question}Change a question. Takes the same body as adding one; only the fields sent are changed.
DELETE/api/v1/surveys/{survey}/questions/{question}Remove a question and the answers given to it.
GET/api/v1/surveys/{survey}/resultsA survey's results: a summary per question, and the responses page by page.

Your workspace: dashboard, account, search, reports and more

MethodAddressWhat it does
GET/api/v1/accountThe caller's own preferences: language and time zone (null means "follow the workspace"), the workspace's defaults, the languages that may be chosen, and the signature they sign documents with.
PUT / PATCH/api/v1/accountSave the caller's language and time zone. Takes locale (one of the enabled languages, or blank to follow the workspace) and timezone (an identifier such as Europe/London, or blank). Either left out keeps its current value; sent blank or null, it follows the workspace again.
PUT / PATCH/api/v1/account/passwordChange the caller's password. Takes current_password, password and password_confirmation. The owner is told by email.
POST/api/v1/account/signatureStore the signature the caller signs documents with. Takes signature: a PNG drawn by the caller, as a data: URI.
DELETE/api/v1/account/signatureRemove the caller's signature.
GET/api/v1/activityList the activity log, newest first. Filters: user (a staff id), type (a record type such as invoice), event (created, updated, deleted..), from and to (dates, inclusive).
POST/api/v1/activity/purgeDelete the workspace's log entries older than a number of months, now. Administrators only. Takes months (1 to 120). The purge itself is logged.
POST/api/v1/ai/actions/{action}/cancelCancel an action the assistant proposed. Nothing is saved.
POST/api/v1/ai/actions/{action}/confirmCarry out an action the assistant proposed, as the caller, through the record's own rules. The only way anything the assistant prepared is ever saved. An action already dealt with, or one that fails, is 422 and stays as it was so it can be corrected or cancelled.
GET/api/v1/ai/assistantWhat the assistant's opening screen offers the caller: whether it is available, the month's allowance, the agents they may talk to and the quick starters. Takes subject_type (lead, customer, ticket or project) to narrow the agents and starters to those for that kind of record.
POST/api/v1/ai/assistantAsk the assistant something, starting a conversation when none is named. Takes question (at most 4000 characters), conversation (the id of one of the caller's conversations to carry on), agent (an agent id, for a new conversation), subject_type and subject_id (a record the question is about, which the caller must be able to open).
GET/api/v1/ai/assistant/historyThe caller's thirty most recent conversations, newest first.
GET/api/v1/ai/assistant/{conversation}One of the caller's conversations with every message in it, and the actions the assistant proposed along the way with their status.
DELETE/api/v1/ai/assistant/{conversation}Delete one of the caller's conversations.
POST/api/v1/ai/composeWrite something from a one-line instruction. Takes instruction (at most 500 characters) and context (an existing draft to work from). Needs ai.use. Answers {"data": {"text": ..}}.
POST/api/v1/ai/runRun one AI feature on one record and get its answer. Takes feature (lead_score, ticket_triage, reply_draft or summary), type (lead, customer, ticket or project), id, and refresh (true to ask again rather than reuse a stored answer). Needs ai.use and the permission to open that record; a record outside the caller's scope answers 404.
GET/api/v1/billingThe workspace's subscription: its status and plan, the plans it may move to, what it uses against its plan's limits, the payments it has made, and the address of the gateway's self-service portal where there is one.
POST/api/v1/billing/checkoutStart paying for a plan. Takes plan (the id of an active, public plan). Answers with checkout_url - the gateway's page to send the person to - or, for a plan that needs no payment, with the plan already applied.
GET/api/v1/billing/completeConfirm a checkout with the gateway and say whether the subscription is now active. Takes session (the gateway's checkout session id). The caller is never believed: the gateway is asked what the session did.
POST/api/v1/bulk/{subject}Apply one action to many records of a list (leads, customers, invoices, estimates, tasks or tickets). Takes action (e.g. status, assign, delete - see config/bulk.php for each list's), ids (an array of record ids) and value where the action sets one. The message says how many changed, and how many were skipped.
GET/api/v1/dashboardThe dashboard that opens first (or the one named by ?dashboard=), with the figures of every panel on it the caller may see.
POST/api/v1/dashboardsCreate a dashboard for the caller. Takes name (at most 56 characters); a name already in use is numbered rather than refused.
GET/api/v1/dashboards/{dashboard}One of the caller's dashboards with every panel they may put on it, in this dashboard's order, each marked hidden or not - what the customise screen arranges.
PUT / PATCH/api/v1/dashboards/{dashboard}Rename a dashboard and save its arrangement. Takes name, and widgets: an object of panel key => {"visible": true|false}, in the order the panels should stand. Panels left out of widgets go to the end; keys the caller may not see are dropped. Either field left out keeps its current value - widgets is replaced whole when sent, never merged.
DELETE/api/v1/dashboards/{dashboard}Delete one of the caller's dashboards. The last one cannot be deleted (403); when the default goes, the next one takes over.
POST/api/v1/dashboards/{dashboard}/defaultMake this the dashboard that opens first.
POST/api/v1/dashboards/{dashboard}/resetPut every panel on this dashboard back in its usual place, all shown.
POST/api/v1/editor/imagesUpload an image for the formatting editor and get its public address back. Takes image (multipart; PNG, JPEG, GIF or WebP, at most 4 MB). Answers {"data": {"url": ..}}.
POST/api/v1/email-builder/imagesUpload an image for the email builder and get its public address back. Needs permission to write campaigns or to edit settings (the email templates). Takes image (multipart; PNG, JPEG, GIF or WebP, at most 2 MB).
DELETE/api/v1/filters/{filter}Delete a saved filter: the caller's own, or a shared one with settings.edit.
POST/api/v1/filters/{filter}/defaultOpen this list with this filter from now on. A shared filter needs settings.edit, and pinning it sets it for everybody.
GET/api/v1/filters/{list}The saved filters the caller may use on one list: their own and the shared ones, each with the query parameters it stands for.
POST/api/v1/filters/{list}Save a filter on one list. Takes name, shared (for everybody - needs settings.edit, otherwise it is saved for the caller alone), is_default, and the list's own filter parameters (e.g. status, q) whose current values make up the filter. At least one filter parameter is required.
POST/api/v1/list-layout/{list}Choose the normal or the compact layout for a list (leads, tasks or tickets). Takes layout: normal or compact.
GET/api/v1/notificationsList the caller's notifications, newest first. Takes unread=1 for the unread ones only.
GET/api/v1/notifications/feedThe latest ten notifications and the unread count, as the bell polls for them. Takes after (a notification id) for only those newer than it.
POST/api/v1/notifications/pusher-authSign a Pusher subscription to the caller's own private channel, for an app that listens for notifications as they happen. Takes socket_id and channel_name; any channel but the caller's own is refused with 403, as is a workspace with no Pusher connection. Answers {"auth": ..}, the shape Pusher's client libraries expect.
POST/api/v1/notifications/read-allMark every one of the caller's notifications read.
POST/api/v1/notifications/{id}/readMark one notification read, and say how many are still unread.
GET/api/v1/pagesList the published staff pages, in the order the menu shows them.
GET/api/v1/pages/{slug}One staff page by its slug, with its content as sanitised HTML.
GET/api/v1/platform-noticesThe platform notices showing to the caller now, most urgent first: the same ones the banner shows, less those the caller dismissed.
POST/api/v1/platform-notices/{announcement}/dismissDismiss a platform notice for the caller alone; colleagues still see it. A notice that cannot be dismissed answers 422.
GET/api/v1/reportsThe overview report: money in and out for the period against the one before, with a line each on leads, delivery and support.
GET/api/v1/reports/deliveryThe delivery report: hours logged by member of staff and by project, projects by member of staff, and open tasks by member of staff.
GET/api/v1/reports/export/{report}Download one report's rows as a CSV (or, with format=xlsx where the server can write one, an Excel workbook) - the file the screens' download buttons give. Needs reports.export. The report is one of invoices, payments, expenses, customers, lead-sources, lead-staff, time-staff, time-projects, projects-staff, tickets-department, tickets-weekday, tickets-staff, articles, income-expenses, year-on-year, year-on-year-expenses, items, credit-notes, payments-summary, customer-groups, invoice-summary, invoice-funnel, estimate-funnel or proposal-funnel.
GET/api/v1/reports/financeThe finance report: income against expenses month by month, the totals, expenses by category, customers, and this year against last.
GET/api/v1/reports/invoicesThe invoice summary: what each customer was invoiced (subtotal, discount, tax, total, received, due), the totals, the invoice funnel and credit notes.
GET/api/v1/reports/leadsThe leads report: new and converted leads, the trend, and leads by source and by member of staff.
GET/api/v1/reports/paymentsThe payments report: money received month by month and by method, and the credit notes issued.
GET/api/v1/reports/salesThe sales report: the money summary, invoice, estimate and proposal funnels, payment methods, the best customers and customer groups, item sales, expenses by category and the pipeline.
GET/api/v1/reports/statement/{customer}One customer's account as a ledger: opening balance, every invoice, payment, credit and refund in the period, and the closing balance, per currency. A customer the caller could not open answers 404.
GET/api/v1/reports/supportThe support report: tickets opened and closed, the trend, tickets by week, weekday, department, priority and member of staff, and how the knowledge base articles are doing.
GET/api/v1/searchSearch every kind of record the caller may see, grouped by kind, as the search page does. Takes q (at least the configured minimum length, two characters by default; shorter answers with no groups).
GET/api/v1/search/previewThe same search with only a few results of each kind, as the dropdown under the search box shows while somebody types. Takes q.
GET/api/v1/starsThe records the caller starred, grouped by kind, newest star first. A record the caller can no longer see drops out.
POST/api/v1/stars/{type}/{id}Star a record, or take its star off again. The type is a record kind such as lead, customer or invoice; a record the caller cannot see answers 404, as one that does not exist does.
GET/api/v1/calendarList everything on the calendar in a range: events, and - where the caller may see them - task deadlines, invoice due dates, contract ends, leave and the connected Google calendar.
POST/api/v1/calendarAdd an event to the calendar, owned by the caller.
GET/api/v1/calendar/{event}Show one event, with its attendees and their answers, what it is about and its custom fields.
PUT / PATCH/api/v1/calendar/{event}Change an event. Only its owner may.
DELETE/api/v1/calendar/{event}Remove an event. Only its owner may.
PATCH/api/v1/calendar/{event}/respondAnswer an invitation to an event.
GET/api/v1/filesList one folder: the folder itself, the trail of folders above it, the folders inside it and its files, with the upload limits and the cloud services that can be copied from.
POST/api/v1/files/foldersMake a folder.
PUT / PATCH/api/v1/files/folders/{folder}Rename a folder. The home folder cannot be renamed.
DELETE/api/v1/files/folders/{folder}Remove an empty folder. One with anything in it is refused with a 422; the home folder cannot be removed.
GET/api/v1/files/folders/{folder}/cloud/{provider}List one folder of a connected Google Drive or Dropbox, folders first, to choose files to copy in.
POST/api/v1/files/folders/{folder}/cloud/{provider}Copy files from a connected Google Drive or Dropbox into a folder.
POST/api/v1/files/folders/{folder}/uploadUpload files into a folder, as multipart form data.
GET/api/v1/files/folders/{folder}/{file}Download a file, under the name it was uploaded with.
DELETE/api/v1/files/folders/{folder}/{file}Remove a file.
PATCH/api/v1/files/folders/{folder}/{file}/visibilityShow or hide a file in the customer's portal, turning it the other way from how it is. Only a file in a customer's folder can be shown.
GET/api/v1/remindersList the signed-in person's reminders, soonest first.
POST/api/v1/remindersSet a reminder against a record.
DELETE/api/v1/reminders/{reminder}Remove a reminder altogether.
PATCH/api/v1/reminders/{reminder}/dismissClear a reminder, moving it to the "done" list.
PATCH/api/v1/reminders/{reminder}/snoozePut a reminder off by a number of hours from now, so it comes due again.
GET/api/v1/timelineList the timeline, pinned posts first and then the newest, each with its author, replies, files and reactions.
POST/api/v1/timelinePost to the timeline, as multipart form data when there are files.
DELETE/api/v1/timeline/{post}Remove a post: your own, or anybody's with the timeline "delete" grant.
POST/api/v1/timeline/{post}/commentsReply to a post.
DELETE/api/v1/timeline/{post}/comments/{comment}Remove a reply: your own, or anybody's with the timeline "delete" grant.
PATCH/api/v1/timeline/{post}/pinPin a post to the top of the timeline, or unpin it if it is pinned.
POST/api/v1/timeline/{post}/reactReact to a post, or take the reaction back if the caller already has.
GET/api/v1/document-pdfsHow many documents a set of filters matches, and how many zips they will come in.
POST/api/v1/document-pdfsDownload one part of the matching documents as PDFs in a zip.
GET/api/v1/exports/{entity}/printEvery matching row of a list, up to the print limit (1,000 by default), as the print page lays it out.
GET/api/v1/exports/{entity}/{format}Download a list as a CSV or Excel file.
GET/api/v1/importsThe kinds of record the caller may import, with the fields each understands.
POST/api/v1/imports/{type}Upload a spreadsheet (.csv or .xlsx, up to 8 MB) to import, and read its headings.
GET/api/v1/imports/{type}/mapAn uploaded file's headings, guessed mapping and first five rows again.
POST/api/v1/imports/{type}/previewWhat an import would do, before it does it: how many rows are new, how many would update an existing record, and which rows repeat one earlier in the file.
POST/api/v1/imports/{type}/runImport an uploaded file.
GET/api/v1/imports/{type}/templateA blank CSV with the right headings for one type, for somebody starting from nothing.
POST/api/v1/pdf/{kind}/bulkSeveral documents of one kind as PDFs in a single zip.
POST/api/v1/pdf/{kind}/emailEmail documents of one kind to their customers' active contacts, each with its PDF attached; a draft that is sent becomes "sent".
GET/api/v1/pdf/{kind}/{id}One document as a PDF, to be shown in a viewer (Content-Disposition: inline).
GET/api/v1/pdf/{kind}/{id}/downloadOne document as a PDF file to save (Content-Disposition: attachment), named after its number.

Settings

MethodAddressWhat it does
GET/api/v1/settings/aiThe AI settings. "mode" says which page this is: "own" (the workspace's provider, model, limits and features, the key reported only as set or not) or "platform" (the features the platform offers, those the workspace has chosen, and the redaction switch). Both carry whether AI is configured, this month's allowance and usage per feature.
PUT / PATCH/api/v1/settings/aiSave the AI settings. On an own connection, body: provider, base_url, model, api_key (blank keeps the saved one), max_tokens, temperature, monthly_token_cap, features (a list), enabled, redact_contacts. On a platform connection, body: features (from those offered) and redact_contacts.
GET/api/v1/settings/ai/agentsThe workspace's agents, with how many conversations each has run, and whether AI is configured at all. Needs "ai.manage".
POST/api/v1/settings/ai/agentsWrite an agent. Body: name, description, instructions, knowledge, starters (up to six questions), context_types (lead, customer, ticket, project), model, temperature, max_tokens, icon, sort_order, is_active. Needs "ai.manage".
GET/api/v1/settings/ai/agents/{agent}One agent with its instructions and knowledge. Needs "ai.manage".
PUT / PATCH/api/v1/settings/ai/agents/{agent}Change an agent; the same fields as writing one. Its slug never changes, and a field left out keeps its value (the screen would read a missing is_active as "off" and a missing list as empty). Needs "ai.manage".
DELETE/api/v1/settings/ai/agents/{agent}Remove an agent. The conversations it ran are kept. Needs "ai.manage".
POST/api/v1/settings/ai/disconnectRemove the key, switch AI off and clear every stored answer.
POST/api/v1/settings/ai/testAsk the provider for one short answer, to prove the key works. A refusal answers 422 with the provider's reason.
GET/api/v1/settings/apiThe workspace's staff tokens (never their secrets), its webhook endpoints, the events an endpoint can listen for, and the abilities the caller may put on a new token.
POST/api/v1/settings/api/tokensCreate a token for the caller and return it with its secret, which is shown this once and never again. Body: name, abilities (a list of "module.ability"; empty for everything the maker may do), expires_at.
DELETE/api/v1/settings/api/tokens/{token}Revoke a token. Anything using it stops working at once.
POST/api/v1/settings/api/webhooksAdd a webhook endpoint and return it with its signing secret, which is shown this once. Body: name, url (https, not a private address), events (a list from GET /api/v1/settings/api), is_active.
PUT / PATCH/api/v1/settings/api/webhooks/{webhook}Change a webhook endpoint. Takes the same fields as creating one, and starts its failure count again. A field left out keeps its value: the screen reads a missing is_active as "on", which would quietly switch a paused endpoint back on, so the rest is filled in from the endpoint as it stands. An events list sent replaces the old one whole.
DELETE/api/v1/settings/api/webhooks/{webhook}Remove a webhook endpoint.
POST/api/v1/settings/api/webhooks/{webhook}/testSend a sample "ticket.created" delivery to an endpoint. Answers 422 with the reason when the endpoint does not accept it.
GET/api/v1/settings/appearance/appThe installable app: whether it is offered, its names and colours, the icons in use, and whether this server can resize an uploaded icon.
PUT / PATCH/api/v1/settings/appearance/appSave the installable app. Body: enabled, name, short_name, theme_colour, background_colour (#rrggbb), and icon (a square png of at least 512 pixels) to replace the icon. A field left out keeps its value, rather than the screen's reading of a missing switch as "off" and a missing name or colour as cleared.
DELETE/api/v1/settings/appearance/app/iconGo back to the bundled app icon.
GET/api/v1/settings/appearance/codeThe custom CSS and JavaScript for the staff area and the portal, and whether this server runs custom JavaScript at all. Administrators only.
PUT / PATCH/api/v1/settings/appearance/codeSave the custom code. Body: staff_css, portal_css, staff_js, portal_js. Script is refused (422) on a server that does not run it. Administrators only. A field left out keeps its code; send it empty to clear it.
GET/api/v1/settings/appearance/sign-inThe sign-in page: its welcome words, whether the public pages show their top bar, and the background, logos and favicon in use.
PUT / PATCH/api/v1/settings/appearance/sign-inSave the sign-in page. Body: welcome, public_menu (a switch), and background (a png, jpg or webp upload) to replace the picture. A field left out keeps its value, rather than the screen's reading of a missing switch as "off".
DELETE/api/v1/settings/appearance/sign-in/backgroundRemove the sign-in page's background picture.
GET/api/v1/settings/emailHow mail is sent: the email settings (without their secrets), which secrets are set, the mail drivers on offer, whether a Google or Microsoft 365 mailbox is connected and as whom, the address to register with the provider, and how many messages are queued and failed.
PUT / PATCH/api/v1/settings/emailSave how mail is sent. Body: from_name, from_email, bcc_all, signature, mailer (a driver key), smtp_host, smtp_port, smtp_encryption, smtp_username, smtp_password, sendmail_path, oauth_client_id, oauth_client_secret, oauth_tenant, per_hour, log_keep_days, and the switches queue_enabled, queue_exclude_attachments. A secret left blank or out is kept, and so is every other field left out - the screen would read a missing mailer as "none" (and forget a connected mailbox) and a missing switch as "off", so they are filled in from the current settings first.
GET/api/v1/settings/email-logEvery message this workspace sent or queued, newest first, with the count per status, how many went in the last hour and the hourly limit in meta. Filters: status, kind, q (recipient or subject).
POST/api/v1/settings/email-log/retry-failedPut every failed message that still has its body back in the queue.
GET/api/v1/settings/email-log/{id}One message, with its body while the log still holds it.
DELETE/api/v1/settings/email-log/{id}Take a message out of the queue before it is sent. Refused (422) for one already sent.
POST/api/v1/settings/email-log/{id}/retryPut one failed message back in the queue. Refused (422) for a message that has not failed or no longer has its body.
GET/api/v1/settings/email-templatesEvery email template (without its body), grouped as on the screen, the groups switched off, and the signature added to every message.
PATCH/api/v1/settings/email-templates/groupsSwitch a whole group of templates off or on. Body: group, enabled.
GET/api/v1/settings/email-templates/{emailTemplate}One template with its subject, body, design (the builder's blocks, or null for a plain template) and the merge fields it may use.
PUT / PATCH/api/v1/settings/email-templates/{emailTemplate}Change a template. Body: name, subject, body, design (the builder's blocks as JSON, or empty for plain text), from_name, from_email, bcc, is_active. A field left out keeps its value: a template made in the builder stays in the builder unless "design" is sent empty.
POST/api/v1/settings/email/oauth/disconnectDisconnect the Google or Microsoft 365 mailbox. Mail goes through the server's own settings again.
POST/api/v1/settings/email/testSend a test message to "to" and answer with the conversation with the mail server (passwords blanked out) in data.debug. A refused message answers 422 with the reason and the same transcript.
GET/api/v1/settings/integrationsThe integration settings (without their secrets), which secrets are set, the forms reCAPTCHA can protect, whether Google Drive, Dropbox and the calendar are connected, and the addresses to register with each provider (OAuth callbacks and the GitHub and Bitbucket webhooks).
PUT / PATCH/api/v1/settings/integrationsSave the integration settings. Body: google_api_key, google_calendar_id, google_client_id, google_client_secret, recaptcha_site_key, recaptcha_secret, recaptcha_version ("v2" or "v3"), recaptcha_min_score, recaptcha_forms (a list), dropbox_app_key, dropbox_app_secret, github_secret, bitbucket_secret, facebook_app_id, facebook_app_secret, and the switches social_google, social_facebook, rich_text_editor, customer_map. A secret left blank or out is kept; a changed Google client or Dropbox app forgets the connection made through the old one. Every other field left out keeps its value too - the screen would read a missing switch as "off", a missing recaptcha_forms as none and a missing Google client as a changed one - so the rest is filled in from the current settings first.
POST/api/v1/settings/integrations/calendar-testRead this month from the Google calendar, to prove the key and the calendar id work together. A refusal answers 422 with Google's reason.
POST/api/v1/settings/integrations/dropbox/disconnectDisconnect Google Drive or Dropbox (the route says which). Files already copied in stay where they are.
POST/api/v1/settings/integrations/google/disconnectDisconnect Google Drive or Dropbox (the route says which). Files already copied in stay where they are.
GET/api/v1/settings/mailboxesEvery mailbox, the last fifty decisions the checker made (what became a lead or a ticket, and what was skipped and why), the encryptions on offer, and whether this server can open an encrypted connection.
POST/api/v1/settings/mailboxesAdd a mailbox. Body: name, purpose ("leads" or "tickets"), host, port, encryption, username, password, folder, check_every (minutes, 5 to 1440), for leads lead_status_id, lead_source_id, assigned_to, task_for_existing_customers, for tickets ticket_department_id, ticket_service_id, ticket_priority, mark_public, and blocked_senders, blocked_subjects, is_active, validate_certificate, unread_only, delete_after_import.
PUT / PATCH/api/v1/settings/mailboxes/{mailbox}Change a mailbox; the same fields as adding one. A password left out or blank keeps the saved one, and so does every other field left out: the screen posts the whole form and reads a missing switch as "off" and a missing box as cleared, so the rest is filled in from the mailbox as it stands.
DELETE/api/v1/settings/mailboxes/{mailbox}Remove a mailbox.
POST/api/v1/settings/mailboxes/{mailbox}/runRead the mailbox now rather than waiting for the scheduler. Answers with how many leads or tickets were made, or 422 with the reason it could not be read.
POST/api/v1/settings/mailboxes/{mailbox}/testConnect, sign in and list the mailbox's folders, with how many messages wait in its folder. A refused connection answers 422 with the server's reason.
GET/api/v1/settings/marketingThe marketing settings (without their secrets), which secrets are set, the SMS providers on offer, whether SMS is ready, what (if anything) stops WhatsApp sending, the addresses to give Twilio and Meta for delivery reports, the WhatsApp verify token, and any warning about sending campaign email.
PUT / PATCH/api/v1/settings/marketingSave the marketing settings. Body: email_per_minute, sms_per_minute, whatsapp_per_minute, default_country_code, email_footer, sms_footer, sms_driver and the chosen provider's fields (twilio_sid, twilio_token, twilio_from; clickatell_api_key; msg91_auth_key, msg91_sender; http_url, http_method, http_to_param, http_message_param, http_params, http_header, http_keep_plus), and whatsapp_phone_number_id, whatsapp_business_id, whatsapp_token, whatsapp_app_secret. A secret left blank or out is kept, and so is every other field left out: the screen posts the whole form, so the rest is filled in from the current settings first rather than cleared (and http_keep_plus switched off).
POST/api/v1/settings/marketing/sms/disconnectDisconnect the SMS provider and delete its details.
POST/api/v1/settings/marketing/sms/testCheck the SMS provider's credentials, or with "to" send one test text to that number. A refusal answers 422 with the provider's reason.
POST/api/v1/settings/marketing/whatsapp/disconnectDisconnect WhatsApp and delete its token.
POST/api/v1/settings/marketing/whatsapp/verifyAsk Meta who the WhatsApp number is, and record the answer. A refusal answers 422 with Meta's reason.
GET/api/v1/settings/menuThe three menus as their editors show them - every entry with its shipped label and icon, the workspace's own label and icon if it set one, and whether it is hidden - plus the Bootstrap Icons names an entry may use.
PUT / PATCH/api/v1/settings/menu/portalSave the portal's menu. Body: items, keyed by entry key, each with label, icon and visible, in the order wanted; personal, whether each contact may arrange it for themselves (left out, it keeps its value).
PUT / PATCH/api/v1/settings/menu/setupSave the Settings menu. Body: entries, keyed by entry key, each with visible, in the order wanted.
PUT / PATCH/api/v1/settings/menu/sidebarSave the staff sidebar. Body: sections, keyed by section key, each with label and items (keyed by item key, each with label, icon, visible and children), in the order wanted.
POST/api/v1/settings/menu/{menu}/resetPut one menu (sidebar, portal or setup) back as it shipped.
GET/api/v1/settings/notificationsThe notification settings (without their secrets), which secrets are set, whether SMS, Pusher and Slack are ready, and the events Slack can be told about.
PUT / PATCH/api/v1/settings/notificationsSave the notification settings. Body: desktop_dismiss_seconds, pusher_app_id, pusher_key, pusher_secret, pusher_cluster, bitly_token, slack_webhook_url, slack_events (a list), and the switches desktop, sms_invoice_due, sms_invoice_overdue, sms_payment_recorded, sms_staff_reminders. A secret left blank or out is kept, and so is every other field left out - the screen reads a missing switch as "off" and a missing slack_events as none, so the rest is filled in from the current settings first. slack_events, when sent, replaces the list whole.
POST/api/v1/settings/notifications/pusher-testSend a test notice through Pusher to the caller. A refusal answers 422.
POST/api/v1/settings/notifications/slack-testPost a test message to the Slack webhook. A refusal answers 422.
GET/api/v1/settings/portalEvery card's current values: access, registration_fields, profile_tabs, projects (default permissions, tab order, feedback), dashboard (panels, welcome message, whether contacts may rearrange it), tickets (the statuses a customer may set), messages and estimate_requests.
PUT / PATCH/api/v1/settings/portal/accessThe "Access" card. Body: verify_hours, and the switches sign_in, registration, verify_email, approval.
PUT / PATCH/api/v1/settings/portal/assistantThe "AI assistant" card. Body: enabled - whether the portal has an Ask AI button of its own, working on the customer's own account. Left out, it stays as it is.
PUT / PATCH/api/v1/settings/portal/dashboardThe "Overview page" card. Body: widgets (panel key => {"visible": bool}, in the order wanted), welcome (formatted text), personal (whether each contact may rearrange it). widgets is replaced whole when sent, and left out keeps the panels as they stand.
POST/api/v1/settings/portal/dashboard/resetPut the overview panels back as they shipped. The welcome message and the "personal" switch are left alone.
PUT / PATCH/api/v1/settings/portal/estimate-requestsThe "Estimate requests" card. Body: portal, public_form (switches) and assign_to (a staff id, or null).
PUT / PATCH/api/v1/settings/portal/messagesThe "Messages" card. Body: staff, colleagues (switches), staff_audience ("assigned" or "available") and available_staff (staff ids).
PUT / PATCH/api/v1/settings/portal/profileThe "My account" card. Body: tabs, the optional tabs contacts see (password, company, contacts, privacy). Left out, they stay as they are.
PUT / PATCH/api/v1/settings/portal/projectsThe "Projects" card. Body: permissions (permission key => true/false, the defaults every project follows), tabs (every tab key, in order), shown_tabs (tab key => true for the tabs shown), feedback, feedback_finished_only. A permission left out of "permissions" keeps its value; shown_tabs is replaced whole when sent (a tab left out of it is hidden).
PUT / PATCH/api/v1/settings/portal/registrationThe "Sign-up form" card. Body: fields, an object of field key => "hidden", "optional" or "required". The object is replaced whole: a field left out of it is not asked. Left out altogether, the form stays as it is.
PUT / PATCH/api/v1/settings/portal/ticketsThe "Tickets" card. Body: customer_statuses, the ticket status ids a customer may move their own ticket to. Left out, it stays as it is.
GET/api/v1/settings/privacyThe privacy settings, the pages a policy or terms link may point at, the consent purposes (with how many answers each has) and how many removal requests are waiting.
PUT / PATCH/api/v1/settings/privacySave the privacy settings. Body: policy_page_id or policy_url, terms_page_id or terms_url, export_link_hours, and the switches enabled, portal_consents, portal_export, portal_removal, signup_terms_required. A field left out keeps its value: the screen posts the whole form and reads a missing switch as "off" and a missing link as none, so the rest is filled in from the settings as they stand.
POST/api/v1/settings/privacy/purposesAdd a consent purpose. Body: name, description, sort_order, is_active.
PUT / PATCH/api/v1/settings/privacy/purposes/{purpose}Change a consent purpose; the same fields as adding one. A field left out keeps its value - the screen reads a missing is_active as "off", which would retire the purpose - so the rest is filled in from the purpose as it stands.
DELETE/api/v1/settings/privacy/purposes/{purpose}Remove a consent purpose nobody has answered yet. One somebody has answered is part of their consent history and is refused (422): retire it with is_active false instead.
GET/api/v1/settings/site-menuThe public website's menu and footer: its links (each a label and either a url or a page_id), the footer text, the social links, the public pages a link may point at, and the networks a social link may be for.
PUT / PATCH/api/v1/settings/site-menuSave the website's menu and footer. Body: menu_links and footer_links (lists of {label, type: "url"|"page", url | page_id}), footer_text, social_links (network => address), show_kb_link, show_support_link.
GET/api/v1/settings/supportThe desk's behaviour switches, the knowledge base's public settings, and every list on the screen: departments (with their member ids), statuses, priorities, services, canned replies and ticket templates.
PUT / PATCH/api/v1/settings/support/behaviourSave how the desk behaves. Body: status_after_staff_reply (a status id, 0 for "leave it"), auto_close_after_hours, pipe_default_priority (a priority slug), kb_heading, and the switches assign_to_first_responder, auto_response, public_form_enabled, pipe_strip_quoted, pipe_replies_only, pipe_registered_only, kb_public, kb_voting. A field left out keeps its value: the screen posts the whole form and reads a missing switch as "off", so the rest is filled in from the settings as they stand.
POST/api/v1/settings/support/canned-repliesAdd a canned reply. Body: name, content, ticket_department_id (null for every department), sort_order.
PUT / PATCH/api/v1/settings/support/canned-replies/{reply}Change a canned reply; the same fields as adding one. A field left out keeps its value rather than being cleared (the department) or reset (the sort order).
DELETE/api/v1/settings/support/canned-replies/{reply}Remove a canned reply.
POST/api/v1/settings/support/departmentsAdd a department. Body: name, email (the address its mail arrives at), sort_order, notify_members, is_default, members (staff ids).
PUT / PATCH/api/v1/settings/support/departments/{department}Change a department; the same fields as adding one. A field left out keeps its value - the screen posts the whole form, reading a missing switch as "off" and missing members as none - so the rest is filled in from the department as it stands. Members, when sent, replace the old list whole.
DELETE/api/v1/settings/support/departments/{department}Remove a department. Its tickets are kept, with no department.
GET/api/v1/settings/support/pipe-logThe messages the mail pipe received and what it did with each, newest first. Filter: status.
POST/api/v1/settings/support/prioritiesAdd a priority. Body: name, colour (#rrggbb), sort_order, is_default, is_high. Its slug is made from the name once and never changes.
PUT / PATCH/api/v1/settings/support/priorities/{priority}Change a priority; the same fields as adding one. A field left out keeps its value - the screen posts the whole form, reading a missing switch as "off" - so the rest is filled in from the record as it stands.
DELETE/api/v1/settings/support/priorities/{priority}Remove a priority; its tickets move to the first remaining one. Refused (422) for the last priority.
POST/api/v1/settings/support/servicesAdd a service. Body: name, sort_order.
PUT / PATCH/api/v1/settings/support/services/{service}Change a service; the same fields as adding one. A field left out keeps its value rather than resetting (the sort order to 0).
DELETE/api/v1/settings/support/services/{service}Remove a service.
POST/api/v1/settings/support/statusesAdd a ticket status. Body: name, colour (#rrggbb), sort_order, and the switches is_closed, is_default, reopen_on_customer_reply.
PUT / PATCH/api/v1/settings/support/statuses/{status}Change a ticket status; the same fields as adding one. A field left out keeps its value - the screen posts the whole form, reading a missing switch as "off" - so the rest is filled in from the record as it stands.
DELETE/api/v1/settings/support/statuses/{status}Remove a ticket status. Refused (422) for the last open one.
POST/api/v1/settings/support/templatesAdd a ticket template. Body: name, subject, message, ticket_department_id, ticket_service_id, priority (a slug), sort_order, is_active.
PUT / PATCH/api/v1/settings/support/templates/{template}Change a ticket template; the same fields as adding one. A field left out keeps its value - the screen posts the whole form, reading a missing switch as "off" - so the rest is filled in from the record as it stands.
DELETE/api/v1/settings/support/templates/{template}Remove a ticket template.
GET/api/v1/settings/themeThe accent, the default mode, the workspace's colours (only those changed from stock, per mode), the editor's rows with their stock values, every named theme and the one in use.
PUT / PATCH/api/v1/settings/themeSave the theme. Body: accent (#rrggbb), mode ("light" or "dark"), colours ({"light": {key: "#rrggbb"}, "dark": {..}}; a colour left out goes back to stock). The accent or mode left out keeps its value, and colours left out altogether stay as they are.
POST/api/v1/settings/theme/namedKeep the colours as they are now under a name. Body: name.
PUT / PATCH/api/v1/settings/theme/named/{id}Rename one of the workspace's own themes. Body: name.
DELETE/api/v1/settings/theme/named/{id}Delete one of the workspace's own themes. The colours in use stay.
POST/api/v1/settings/theme/named/{id}/applyMake a named theme's colours the workspace's colours.
GET/api/v1/settings/website-contentThe page's settings (published, header button, sign-in link, posts), the kinds of section with the fields each takes, every section in order, and the blog posts (without their bodies), newest first.
POST/api/v1/settings/website-content/postsWrite a blog post. Body: title, slug (made from the title when left out), excerpt, body (formatted text), meta_description, published_at (left out for a draft), image (png, jpg or webp upload).
GET/api/v1/settings/website-content/posts/{post}One blog post with its body, addressed by its slug.
PUT / PATCH/api/v1/settings/website-content/posts/{post}Change a blog post; the same fields as writing one. A field left out keeps its value - the screen would read a missing published_at as "a draft" and a missing body as empty - so the rest is filled in from the post as it stands. Send published_at as null to take a post back to a draft.
DELETE/api/v1/settings/website-content/posts/{post}Remove a blog post.
POST/api/v1/settings/website-content/sectionsAdd a section at the bottom of the page. Body: type (one of the types GET /api/v1/settings/website-content lists), heading, subheading, body (formatted text), button_label, button_url, items (rows of the fields the type takes), options (the style options the type takes), image (png, jpg or webp upload), is_active.
PUT / PATCH/api/v1/settings/website-content/sections/orderPut the sections in a new order. Body: order, every section id in the order wanted.
GET/api/v1/settings/website-content/sections/{section}One section, as it is edited.
PUT / PATCH/api/v1/settings/website-content/sections/{section}Change a section; the same fields as adding one, plus remove_image. A field left out keeps its value - the screen reads a missing is_active as "hidden" and missing items as none - so the rest is filled in from the section as it stands. items, when sent, replaces the rows whole; options are filled per option. The image stays unless a new one is uploaded or remove_image is sent.
DELETE/api/v1/settings/website-content/sections/{section}Remove a section.
POST/api/v1/settings/website-content/sections/{section}/duplicateCopy a section. The copy is hidden and placed straight after the original; it is what this answers with.
POST/api/v1/settings/website-content/sections/{section}/toggleShow a hidden section, or hide a shown one.
PUT / PATCH/api/v1/settings/website-content/settingsSave the page's own settings. Body: published, header_button_label, header_button_url (https://, / or #), show_sign_in, show_posts. A field left out keeps its value: the screen reads a missing switch as "off" - which would take the site down - so the rest is filled in from the settings as they stand.
POST/api/v1/settings/website-content/starterAdd the ready-made page. Onto an empty page only, unless replace is true, which deletes every existing section first. Answers with the sections as they now are.
GET/api/v1/settingsRead the company profile - the Settings landing page.
GET/api/v1/settings/backupList the backups on the server, newest first, with the automatic schedule.
POST/api/v1/settings/backupTake a backup now.
PUT / PATCH/api/v1/settings/backup-scheduleSave the automatic backup schedule.
GET/api/v1/settings/backup/{name}Download a backup as a .zip file.
DELETE/api/v1/settings/backup/{name}Delete a backup from the server.
GET/api/v1/settings/checklist-templatesList the checklist templates, by name, each with its items.
POST/api/v1/settings/checklist-templatesAdd a checklist template.
GET/api/v1/settings/checklist-templates/{template}Show one checklist template with its items.
PUT / PATCH/api/v1/settings/checklist-templates/{template}Change a checklist template.
DELETE/api/v1/settings/checklist-templates/{template}Remove a checklist template. Tasks it was applied to are not touched.
GET/api/v1/settings/commentsRead the comment settings: formatting and voice notes.
PUT / PATCH/api/v1/settings/commentsSave the comment settings.
GET/api/v1/settings/companiesList the further companies, by name, with how many documents each has issued.
POST/api/v1/settings/companiesAdd a company.
GET/api/v1/settings/companies/{company}Show one company.
PUT / PATCH/api/v1/settings/companies/{company}Change a company.
DELETE/api/v1/settings/companies/{company}Remove a company.
GET/api/v1/settings/contract-typesList the contract types, in their display order, with how many contracts each holds.
POST/api/v1/settings/contract-typesAdd a contract type.
GET/api/v1/settings/contract-types/{type}Show one contract type.
PUT / PATCH/api/v1/settings/contract-types/{type}Change a contract type.
DELETE/api/v1/settings/contract-types/{type}Remove a contract type.
GET/api/v1/settings/contractsRead the contract settings: the statement anybody signing has to agree to, who signs by default, and the contract types.
PUT / PATCH/api/v1/settings/contracts/signingSave the signing settings.
GET/api/v1/settings/currenciesList the workspace's currencies, the base currency first.
POST/api/v1/settings/currenciesAdd a currency.
GET/api/v1/settings/currencies/{currency}Show one currency.
PUT / PATCH/api/v1/settings/currencies/{currency}Change a currency.
DELETE/api/v1/settings/currencies/{currency}Remove a currency.
GET/api/v1/settings/custom-fieldsList the custom field definitions, by record type and display order.
POST/api/v1/settings/custom-fieldsAdd a custom field.
GET/api/v1/settings/custom-fields/{custom_field}Show one custom field definition.
PUT / PATCH/api/v1/settings/custom-fields/{custom_field}Change a custom field.
DELETE/api/v1/settings/custom-fields/{custom_field}Remove a custom field, and every answer stored against it.
GET/api/v1/settings/data-exportRead who sees the Export button on the lists.
PUT / PATCH/api/v1/settings/data-exportSave who sees the Export button on the lists.
GET/api/v1/settings/documentsRead how invoices, estimates, proposals and credit notes are numbered and what a new one starts with.
PUT / PATCH/api/v1/settings/documentsSave document numbering and defaults.
GET/api/v1/settings/expense-categoriesList the expense categories, by name, with how many expenses and recurring expenses each holds.
POST/api/v1/settings/expense-categoriesAdd an expense category.
GET/api/v1/settings/expense-categories/{category}Show one expense category.
PUT / PATCH/api/v1/settings/expense-categories/{category}Change an expense category.
DELETE/api/v1/settings/expense-categories/{category}Remove an expense category.
GET/api/v1/settings/item-groupsList the item groups, by name, with how many items each holds.
POST/api/v1/settings/item-groupsAdd an item group.
GET/api/v1/settings/item-groups/{itemGroup}Show one item group.
PUT / PATCH/api/v1/settings/item-groups/{itemGroup}Rename an item group.
DELETE/api/v1/settings/item-groups/{itemGroup}Remove an item group.
GET/api/v1/settings/leave-typesList the leave types, in their display order, with how many requests each holds.
POST/api/v1/settings/leave-typesAdd a leave type.
GET/api/v1/settings/leave-types/{type}Show one leave type.
PUT / PATCH/api/v1/settings/leave-types/{type}Change a leave type.
DELETE/api/v1/settings/leave-types/{type}Remove a leave type.
GET/api/v1/settings/login-historyList sign-in attempts, newest first.
PUT / PATCH/api/v1/settings/login-historySet how long sign-in attempts are kept.
GET/api/v1/settings/modulesRead which modules are on.
PUT / PATCH/api/v1/settings/modulesSwitch modules on or off.
GET/api/v1/settings/pagesList the pages, in their menu order.
POST/api/v1/settings/pagesAdd a page.
GET/api/v1/settings/pages/{page}Show one page, with its content.
PUT / PATCH/api/v1/settings/pages/{page}Change a page.
DELETE/api/v1/settings/pages/{page}Delete a page. Needs "settings.edit".
GET/api/v1/settings/payment-methodsList the payment methods, in their display order.
POST/api/v1/settings/payment-methodsAdd a payment method.
GET/api/v1/settings/payment-methods/{payment_method}Show one payment method.
PUT / PATCH/api/v1/settings/payment-methods/{payment_method}Change a payment method.
DELETE/api/v1/settings/payment-methods/{payment_method}Remove a payment method.
GET/api/v1/settings/pluginsList the plugins installed on the server.
POST/api/v1/settings/pluginsInstall a plugin, or upgrade one, from its .zip.
DELETE/api/v1/settings/plugins/{slug}Delete a plugin's files. Any tables it made are left in the database.
POST/api/v1/settings/plugins/{slug}/activateActivate a plugin, running its database changes.
POST/api/v1/settings/plugins/{slug}/deactivateDeactivate a plugin. Its settings and data are kept.
GET/api/v1/settings/project-categoriesList the project categories, in their display order, with how many projects each holds.
POST/api/v1/settings/project-categoriesAdd a project category.
GET/api/v1/settings/project-categories/{category}Show one project category.
PUT / PATCH/api/v1/settings/project-categories/{category}Change a project category.
DELETE/api/v1/settings/project-categories/{category}Remove a project category.
GET/api/v1/settings/sales-documentsRead the estimate and proposal settings: who may open one, and what an acceptance sets off.
PUT / PATCH/api/v1/settings/sales-documentsSave the estimate and proposal settings.
GET/api/v1/settings/schedulerRead whether the scheduler is running, and what it runs.
GET/api/v1/settings/searchRead how many results of each kind the search box shows.
PUT / PATCH/api/v1/settings/searchSave how many results of each kind the search box shows.
GET/api/v1/settings/securityRead the IP allow list.
PUT / PATCH/api/v1/settings/securitySave the IP allow list.
GET/api/v1/settings/system-logRead the latest entries of the error log, newest first.
DELETE/api/v1/settings/system-logEmpty the error log.
GET/api/v1/settings/task-prioritiesList the task priorities, in their display order, with how many tasks each holds.
POST/api/v1/settings/task-prioritiesAdd a task priority.
GET/api/v1/settings/task-priorities/{priority}Show one task priority.
PUT / PATCH/api/v1/settings/task-priorities/{priority}Change a task priority.
DELETE/api/v1/settings/task-priorities/{priority}Remove a task priority, moving its tasks to another first.
GET/api/v1/settings/taxesList the workspace's tax rates, the default first.
POST/api/v1/settings/taxesAdd a tax rate.
GET/api/v1/settings/taxes/{tax}Show one tax rate.
PUT / PATCH/api/v1/settings/taxes/{tax}Change a tax rate.
DELETE/api/v1/settings/taxes/{tax}Remove a tax rate.
GET/api/v1/settings/timeRead the time tracking settings.
PUT / PATCH/api/v1/settings/timeSave the time tracking settings.
GET/api/v1/settings/updatesRead the installed version, the release waiting to be installed if any, and the last few updates.
POST/api/v1/settings/updatesUpload a release's .zip and check it. Installs nothing.
POST/api/v1/settings/updates/onlineTake the site out of maintenance mode, after an update that stopped with it down has been put right.
DELETE/api/v1/settings/updates/pendingRemove the uploaded release without installing it.
POST/api/v1/settings/updates/runInstall the release waiting from the last upload.
GET/api/v1/settings/uploadsRead which files may be uploaded, and how large.
PUT / PATCH/api/v1/settings/uploadsSave which files may be uploaded, and how large.
GET/api/v1/settings/{group}Read one settings page's current values.
PUT / PATCH/api/v1/settings/{group}Save one settings page.

The options forms pick from

MethodAddressWhat it does
GET/api/v1/lookupsThe options every form picks from, in one call: currencies, taxes, payment methods, item groups, expense, project and contract categories, leave types and task and ticket priorities.

The API itself

MethodAddressWhat it does
POST/api/v1/auth/tokenExchange a staff member's email and password for a token.
DELETE/api/v1/auth/tokenSign out: revoke the token this request was made with.
GET/api/v1/pingCheck a token: whose it is, which workspace it opens and what it may do.
GET/api/v1/webhook-eventsThe events a webhook can subscribe to.