Perfex CRM MCP server
Your CRM's clients, invoices and tickets in front of an assistant -- without the outbound email surprises.
- Tools
- 67
- Read-only
- 37
- Write
- 30
- Off by default
- Destructive
- 11
- Flagged distinctly
Perfex CRM through an assistant
Point a connection at your own Perfex install and an assistant can look up clients and contacts, pull invoices and estimates, work leads through the pipeline, and read projects, tasks and support tickets. Reads work as soon as you connect. Writes are opt-in, and the three operations that email your CLIENTS -- sending an invoice, replying to a ticket, and creating a contact with its welcome email -- are held to a stricter standard than everything else: off by default, individually enabled, and each requiring an explicit confirmation, because that mail reaches a real person outside your company and cannot be recalled.
- Clients and contacts, with search across company, VAT and phone
- Invoices and estimates, including status and payment state
- Leads through the sales pipeline, with their custom fields
- Projects, milestones and tasks, with comments and checklists
- Support tickets and their conversation history
- The product and service catalogue used for line items
- Payment modes, tax rates and expense categories for correct data entry
- Create and update clients, leads, tasks and tickets (opt-in)
- Record a payment against an invoice (opt-in, confirmation required)
- Email an invoice or reply to a ticket (opt-in, confirmation required)
What people actually ask
Real questions, answered from live Perfex CRM data.
“Which invoices are overdue, and who do I chase?”
perfex_list_invoicesperfex_list_customer_contacts“What's the story on this client -- open tickets, unpaid invoices, live projects?”
perfex_search_customersperfex_list_tickets“Summarise the leads that came in this week and what stage each is at.”
perfex_list_leadsperfex_get_lead67 Perfex CRM tools
Grouped by what they touch. Every tool is individually toggleable — you expose only what you want.
Tasks
11 tools5 read-only · 6 writeShowing 10 of 10 tools
- perfex_add_task_checklist_itemWrite
Adds one checklist item to a task. Use this for a step within an existing task; a genuinely separate piece of work belongs in perfex_create_task instead, because checklist items carry no dates, no time tracking and no billing -- only a description, an optional assignee and a done flag. Assigning an item points a real colleague at it through the CRM's notification settings. Add items one call at a time; the route takes a single item and there is no batch form worth using.
- perfex_add_task_commentWrite
Posts a comment on a task. Before enabling this, understand whose name it goes out under: Perfex attributes the comment to THE STAFF MEMBER THE API TOKEN BELONGS TO. It appears in the CRM under that real person's name, with nothing marking it as machine-written, and everyone following the task is notified as though that colleague wrote it. Anyone reading the thread later -- including in a dispute about what was agreed -- will attribute it to them. The comment is internal to staff and not visible to the customer, so this is not the tool for replying to a client; that is a ticket reply. There is no de-duplication on this route as this connector calls it, so a retry posts a second identical comment, and this connector ships no way to edit or delete one -- removing a comment means going into the Perfex UI.
- perfex_create_taskWrite
Creates a task. name, startDate and relType are mandatory. relType is what the task hangs off -- `project` with relId set to a project id from perfex_list_projects is the documented pairing; other values exist in Perfex but the API does not enumerate them, so mirror an existing task from perfex_get_task rather than guessing. Assigning the task notifies those staff members through the CRM's own notification settings, so an assignee id is a message to a real colleague, not just a field. priority is a numeric id whose labels the API does not document -- copy it from a comparable task. Custom fields need their write keys from perfex_list_custom_fields, since read payloads carry only labels.
- perfex_delete_taskWriteDestructive
Permanently deletes a task and everything attached to it -- its comments, its checklist items, its attachments and its logged time entries, including billable hours that have not been invoiced yet. That last part is the one that costs money: deleting a task with unbilled time destroys the record the invoice would have been built from, and the API has no restore. If the task is finished, obsolete or a duplicate, setting its status with perfex_update_task keeps the time and the discussion intact and is nearly always what was actually wanted. Requires confirm: true.
- perfex_get_taskRead-only
One task in full, by id, including its custom fields. Use it when you need a specific task's current state -- particularly its numeric status and priority, which the API documents as ranges without labels, so an existing task in the state you want is the only reliable place to read the right number from before calling perfex_update_task. Comments and checklist items are not included; they have their own tools.
- perfex_list_task_checklistRead-only
The checklist items on one task -- each item's description, whether it is finished, who it is assigned to and its display order. This is the sub-task breakdown inside a single Perfex task, not a list of tasks: for those use perfex_list_tasks. Checklist items are not part of perfex_get_task's response. The item id on each row is what perfex_update_task_checklist_item takes.
- perfex_list_task_commentsRead-only
The comment thread on one task, oldest first -- who said what, and when. These are internal staff comments, not anything the customer sees; the client-facing equivalent is a support ticket thread. Read this before adding to it: the thread is the decision record on a task, and the last comment usually says whether the work is actually blocked. Comments are not included in perfex_get_task, which is why this tool exists.
- perfex_list_tasksRead-only
Every task with its name, status, priority, dates, billable flag, assignees and what it is attached to (rel_type plus rel_id -- a project, an invoice, a customer, a ticket). The id on each row is what the comment and checklist tools in this connector take. Note what is NOT here: a task's comments and checklist items are separate sub-resources, fetched with perfex_list_task_comments and perfex_list_task_checklist. Use perfex_search_tasks to find a task by name, perfex_get_task once you have an id.
- perfex_search_tasksRead-only
Keyword search across tasks -- how you turn a task name into an id. The keyword goes in the URL path rather than a query parameter. Which columns Perfex matches for tasks is undocumented, so a miss is inconclusive rather than proof the task does not exist; try a shorter fragment. Results are not paged -- this route takes no page/per_page. To find every task on a project, list tasks and filter on rel_type/rel_id rather than searching for the project's name.
- perfex_update_taskWrite
Changes fields on an existing task. Everything is optional here, including the fields that were required on create. This is also the only way to complete or reopen a task -- there is no separate complete endpoint; you set status, which the API documents as 0 to 5 without saying what any of them mean, so read the number off a task already in the state you want (perfex_get_task) rather than assuming an ordering. Two traps: Perfex ignores unrecognised field names on update instead of rejecting them, so a mistyped field silently no-ops while the call reports success; and assignees REPLACES the assignment list, so sending one id unassigns everyone else.
+ 1 more tasks tool — see the full catalogue
Contacts
7 tools3 read-only · 4 writeShowing 7 of 7 tools
- perfex_create_contactWrite
Create a person under a customer WITHOUT emailing them. This is the tool to use for contacts in general, and the only safe one for a bulk import. Perfex sends a welcome email to a newly created contact BY DEFAULT. That default is inverted here: this tool always sends `donotsendwelcomeemail` and has no way to email anyone, so a run that creates fifty contacts sends zero messages. If the person genuinely should be told they have portal access, use perfex_create_contact_with_welcome_email instead -- and only when the user has actually asked for that. The contact is created without a password, so they cannot log into the portal until someone sets one in the Perfex UI. `portalPermissions` still decides what they would see if they did -- read that field's description before setting it, because each id is a category of the customer's commercial data this individual can read. The email notification flags subscribe a real person to future mail from Perfex; `invoiceEmails` in particular is the prerequisite for the customer ever being able to receive an invoice by email. Custom fields need their `fieldName` keys from perfex_get_custom_field_definitions first -- contact reads give you {label, value} with no id, so there is no other way to get the write key.
- perfex_create_contact_with_welcome_emailWriteDestructive
Create a person under a customer AND let Perfex send them its welcome email. The mail goes to that individual's real inbox, from the CRM owner's mail server, the moment this succeeds -- it cannot be recalled, previewed or dry-run, and there is no way to see the wording it will use from here. Use perfex_create_contact instead in every other case. Reach for this one only when the user has explicitly said this person should be emailed. Never use it for a bulk import: creating a list of contacts through this tool mails every one of them. `sendSetPasswordEmail` adds a SECOND message, one that lets the recipient set a password and sign into the client portal, so between the two this call can hand a third party working access to the customer's invoices, contracts and projects -- whatever `portalPermissions` allows. Set that field deliberately. Everything else behaves as perfex_create_contact. Requires confirm: true.
- perfex_delete_contactWriteDestructive
PERMANENTLY delete a contact. This removes a person from the customer and destroys their client-portal login along with any custom field values on the record -- Perfex deletes custom field data silently whenever it deletes a record. There is no undo and no soft delete. Smaller in blast radius than deleting a customer, but not harmless. If this was the customer's only contact flagged for invoice emails, the customer can no longer be sent an invoice at all, and the failure shows up later as a 500 from the send endpoint rather than as anything traceable to this deletion. Check perfex_list_customer_contacts first. Consider whether the person should simply be left in place instead -- an ex-employee at a client is usually a record worth keeping. Takes the contact id alone, and the endpoint is /api/delete/contacts/{id}, not the RESTful path.
- perfex_get_contactRead-only
One contact's full record, including the `customfields` array Perfex embeds in every GET. Needs BOTH the customer id and the contact id -- this route is two-segment and there is no way to look a contact up by its id alone, which is unique to contacts in this API and catches people out. If you have only a contact id, find its customer with perfex_search_contacts first. Worth reading before perfex_update_contact: the module does not document whether an update preserves the fields you leave out, so this is the only record of what you are about to overwrite.
- perfex_list_customer_contactsRead-only
Every contact under one customer -- name, email, job title, phone, whether each is the primary contact, and their last portal login. Contacts are the PEOPLE at a customer company and, where they have portal access, its logins; the customer record itself is the company. Check here before anything that emails a client: Perfex refuses to email an invoice to a customer that has no contact flagged for invoice emails, and ticket creation needs a specific contact id alongside the customer id. Requires the customer id -- there is no route that lists contacts across all customers, so use perfex_search_contacts to find a person whose company you do not know.
- perfex_search_contactsRead-only
Free-text search across contacts -- the way to find a person, and by extension their customer, when you know a name or an email address but not the company. The customer id on each result is what perfex_get_contact and every customer-scoped tool needs next. The keyword goes in the URL path rather than a query string and is encoded here. Exactly which columns the module matches on for contacts is not documented, so treat a miss as inconclusive rather than proof the person is absent; perfex_search_customers matches company, VAT and phone instead. Not paginated by the module.
- perfex_update_contactWrite
Update an existing contact by contact id. Takes the contact id alone -- unlike reading one, which needs the customer id too. `customer_id` cannot be changed: a contact cannot be moved to another customer through this API. Read the contact with perfex_get_contact first. The module does not document whether fields you omit are preserved or blanked, and it explicitly IGNORES field names it does not recognise instead of rejecting them, so a misspelt field does nothing and still reports success. THE PERMISSIONS FIELD CHANGES WHAT A CLIENT CAN SEE. `portalPermissions` controls this person's access to the customer's invoices, estimates, contracts, proposals, support tickets and projects in the client portal. Widening it hands a third party more of the customer's commercial data, takes effect at their next login, and produces no notification, log entry or other signal anywhere -- which is exactly why it is gated here behind confirm: true. Leave it out entirely and this tool will not touch portal access at all. The email notification flags can only be switched ON through this API; passing false omits them rather than clearing them, because the module's checkbox handling would likely read a `false` as "on". Unsubscribe someone in the Perfex UI. This tool never sends email itself.
Customers
6 tools3 read-only · 3 writeShowing 6 of 6 tools
- perfex_create_customerWrite
Create a customer (a company record) in Perfex. Only `company` is required; everything else is optional, but billing address fields are worth setting because invoice creation requires a billing street of its own later. This creates the COMPANY, not a person and not a portal login. Nobody is emailed. To give the customer a person you can contact, or portal access, create a contact under it afterwards with perfex_create_contact -- and note that creating a contact is the step that can email a real human being. To set custom fields, call perfex_get_custom_field_definitions FIRST and pass the `fieldName` strings it returns verbatim: reads give you custom fields as {label, value} with no id, so there is no other way to get the write key. Perfex does not deduplicate -- creating the same company twice gives you two customers and two sets of invoices, so search before you create.
- perfex_delete_customerWriteDestructive
PERMANENTLY delete a customer. This is the single most destructive call in the Perfex API and the module documents none of its consequences. A Perfex customer is the parent record for its contacts (and their portal logins), invoices, estimates, credit notes, proposals, contracts, projects, tasks under those projects, support tickets and subscriptions. The module's own documentation gives only `{"status": true}` as the response and says nothing whatsoever about what happens to any of that. It may cascade-delete the lot or it may orphan it; there is a `deleted_customer_name` field on the invoice payload which hints that invoices survive as orphans, but that is inference and is unconfirmed. Either outcome is bad: cascading destroys issued financial records that most jurisdictions require you to retain, and orphaning leaves invoices and tickets pointing at a customer that no longer exists. Custom-field data attached to any deleted record is silently destroyed regardless. There is no undo, no soft delete and no export. Before running this, list what hangs off the customer -- at minimum perfex_list_customer_contacts -- and be certain the business genuinely wants the history gone rather than the customer marked inactive in the Perfex UI. Note the endpoint is /api/delete/customers/{id}, not the RESTful path.
- perfex_get_customerRead-only
One customer's full record by id, including the `customfields` array Perfex embeds automatically in every GET. Prefer perfex_list_customers or perfex_search_customers to find a customer; use this when you need everything about one, or when you are about to update one -- the module does not document whether a PUT preserves or blanks fields you leave out, so reading first is the only way to be sure what you are overwriting. Note that the embedded custom fields come back as {label, value} with no id: to write one back you need perfex_get_custom_field_definitions.
- perfex_list_customersRead-only
Customers on this Perfex install -- company name, VAT number, phone, website, address and creation date. The module does not document a default ordering, so pass `sort` (e.g. "-datecreated") if the order matters. Start here: the id on each row is the customer id every other tool wants, including perfex_list_customer_contacts, invoice creation (`clientid`) and ticket creation (`userid`). Use perfex_search_customers instead when you already know the company name, and perfex_get_customer when you need one customer's full record including its custom fields. Paginated -- `page` and `perPage` are always sent, so a large CRM comes back in pages of at most 100 with a meta block telling you whether there are more.
- perfex_search_customersRead-only
Free-text customer search. Perfex matches the keyword against company name, VAT number and phone number -- it does NOT search contact names or email addresses, so use perfex_search_contacts to find a customer by the person you deal with there. The keyword goes in the URL path rather than a query string, so it is URL-encoded here; punctuation and spaces are fine. Search results are not paginated by the module, so a very broad keyword returns whatever it returns.
- perfex_update_customerWrite
Update an existing customer by id. Two things make this sharper than it looks. First, `company` is required by Perfex on every update, even one that only changes a phone number -- so you must pass the current company name back, unchanged, or you will rename the customer. Read it with perfex_get_customer first. Second, the module does not document whether fields you omit are left alone or blanked, and it explicitly IGNORES field names it does not recognise rather than rejecting them -- so a misspelt field silently does nothing and the call still reports success. Read the customer before and after anything important. Does not touch contacts, invoices or anything else under the customer, and emails nobody. `partnership_type` cannot be set here -- it is create-only. Custom fields need their `fieldName` keys from perfex_get_custom_field_definitions.
Leads
6 tools3 read-only · 3 writeShowing 6 of 6 tools
- perfex_create_leadWrite
Adds a lead to the sales pipeline. source, status and assigned are numeric ids from THIS install's own configuration, and the API publishes no lookup for any of them -- copy them off an existing lead (perfex_list_leads) or read them from Setup -> Leads in the CRM. A wrong status id files the lead at the wrong pipeline stage, where it silently skips whatever automation that stage drives, so check rather than guess. To set custom fields, call perfex_list_custom_fields first and pass its field_name values verbatim -- read payloads carry labels, never the ids writes need. Creating a lead sends no email to anyone; only contact creation and the invoice/ticket send routes do that.
- perfex_delete_leadWriteDestructive
Permanently deletes a lead. This is not the same as removing it from a view: the lead's whole activity history goes with it -- its notes, reminders, attachments, the log of who contacted it and when, and the trail recording what it converted into. Pipeline and conversion-rate reporting for past periods changes as a result, because the lead stops having existed. There is no undo and no restore endpoint. Nearly always the right move instead is perfex_update_lead to a lost or junk status, which keeps the history and takes it out of the active pipeline. Requires confirm: true.
- perfex_get_leadRead-only
One lead in full, by id -- everything perfex_list_leads shows for that row plus its custom fields. Use this when you already have the id; use perfex_search_leads to find it from a name, company or email. A lead that has been converted to a customer still exists here, and the conversion link is part of what perfex_delete_lead destroys.
- perfex_list_leadsRead-only
The sales pipeline: every lead with its status, source, assigned staff member, contact details, company, dates and whatever custom fields this install defines. Custom field values come back embedded as {label, value} pairs with no id -- readable, but not enough to write one back, which is what perfex_list_custom_fields is for. Reach for perfex_search_leads instead when you have a name or company and no id, and perfex_get_lead when you already have one. Filter by created_after / created_before rather than pulling every page and filtering here.
- perfex_search_leadsRead-only
Keyword search across leads -- the usual way to turn a name, company or email into a lead id. The keyword travels in the URL path rather than as a query parameter, and Perfex does not document which columns it matches on for leads (for customers it is company, VAT and phone number), so a miss is inconclusive: it is not proof the lead does not exist. Results are NOT paged -- this route takes no page/per_page -- so a broad keyword returns whatever the module decides to return. Narrow the keyword rather than paging.
- perfex_update_leadWrite
Changes fields on an existing lead. Send only what should change. Two traps: Perfex IGNORES field names it does not recognise on update rather than rejecting them, so a mistyped field silently no-ops and the call still reports success -- read the lead back with perfex_get_lead if the change matters. And the last-contact field is named differently here than on create: `lastContact` on update, `customContactDate`/`contactedToday` on create. Moving a lead to a lost or junk status with this tool is almost always the right alternative to perfex_delete_lead, which destroys the history. Custom fields need their write keys from perfex_list_custom_fields.
Projects
6 tools3 read-only · 3 writeShowing 6 of 6 tools
- perfex_create_projectWrite
Creates a project for a customer. Six fields are mandatory: name, relType, clientId, billingType, startDate and status. Three of those are install-specific ids whose value sets the API does not publish -- billingType, status and relType -- so read them off a comparable existing project with perfex_get_project instead of guessing; the wrong billingType silently changes how the project's time turns into money later. clientId is a customer id (perfex_list_customers). Custom fields need their write keys from perfex_list_custom_fields, because read payloads only carry labels. Creating a project emails nobody, but staff added as projectMembers may be notified by the CRM's own settings.
- perfex_delete_projectWriteDestructive
Permanently deletes a project AND everything hanging off it. The cascade is the point: its milestones, its tasks, and each of those tasks' comments, checklist items and time entries go too, along with the project's own notes, discussions and files. Time that was logged against those tasks but never invoiced is destroyed with them, so unbilled work becomes unbillable and unrecoverable. The API documents no restore and no soft delete. To take a project out of active use without losing any of that, set its status to a finished or cancelled value with perfex_update_project instead. Requires confirm: true.
- perfex_get_projectRead-only
One project in full, by id, including its custom fields. Reach for this when you are answering a question about a specific project -- its billing setup, its deadline, who is on it -- rather than scanning perfex_list_projects. It is also the cheapest way to see the exact numeric billing_type, status and rel_type values a working project uses before you create another one with perfex_create_project. Its tasks are not part of this response; list those with perfex_list_tasks.
- perfex_list_projectsRead-only
Every project with its customer, status, billing type, rate, start date, deadline and progress. This is the lookup that feeds the rest of the delivery side: the id on each row is what perfex_create_task takes as rel_id when rel_type is `project`, and what milestone tools take as project_id. It is also where to read this install's own billing_type and status ids from, since the API documents no lookup for either. Use perfex_search_projects to go from a project name to an id, and perfex_get_project for one project's full record.
- perfex_search_projectsRead-only
Keyword search across projects -- the usual way to turn a project name into an id. The keyword goes in the URL path, not a query parameter. Perfex does not document which columns it matches for projects, so a miss means only that this keyword found nothing, not that the project is absent; try a shorter or differently-spelled fragment before concluding anything. Results are not paged -- this route takes no page/per_page.
- perfex_update_projectWrite
Changes fields on an existing project. Send only what should change. Two things to know. Perfex ignores field names it does not recognise on update rather than rejecting them, so a mistyped field quietly does nothing while the call still reports success -- read the project back with perfex_get_project when the change matters. And projectMembers REPLACES the member list rather than adding to it, so send the full set: passing one id removes everyone else from the project. Changing billingType or the rate on a project that already has logged time changes what that time is worth when it is invoiced.
Tickets
6 tools3 read-only · 3 writeShowing 6 of 6 tools
- perfex_create_ticketWrite
Open a new support ticket against a client contact. All four of subject, departmentId, contactId and customerId are required by the API: get the last two from perfex_list_customer_contacts and perfex_list_customers, and note that the API calls the customer id `userid` even though it is not a staff id. The opening message is optional but a ticket with no message is rarely useful. What mail this generates is NOT documented -- the endpoint accepts a cc list, which only makes sense if the install emails somebody, so assume opening a ticket may notify the contact and do not use this to park internal notes. Only perfex_reply_to_ticket is documented as client-facing, and that one is gated.
- perfex_get_ticketRead-only
One ticket in full, by id. Use this before perfex_update_ticket -- that update requires subject, department, contactid, userid and priority on every call, so you need the current values here first or you will overwrite them with guesses. Also worth calling before perfex_reply_to_ticket, to read what the client actually asked before anything is emailed back to them. Returns the record as Perfex stores it, including any custom field values as {label, value} pairs.
- perfex_list_ticketsRead-only
Support tickets on this Perfex install, newest page first. Start here when you need a ticket's id, its department, or an overview of the open queue -- the id on each row is what perfex_get_ticket, perfex_update_ticket and perfex_reply_to_ticket take. Note this endpoint pages 20 rows at a time, not the 25 the rest of this API uses. Any custom fields configured on tickets come back embedded on each row as a customfields array of {label, value} pairs; the label-to-id mapping needed to WRITE one is not in that payload. There is no documented status/department/priority filter on this route -- filter the returned rows yourself, or use perfex_search_tickets for a keyword.
- perfex_reply_to_ticketWriteDestructive
Post a reply to a support ticket. Read this before calling it. The reply is NOT an internal note: it is published on the ticket where the client can see it and it emails the ticket's contact, going out under the company's name to someone the business has a real commercial relationship with. It cannot be recalled, and the API documents no way to edit or delete a reply once posted. Draft the wording with the person who owns that relationship and get their explicit approval of the exact text before calling this -- an AI-authored support reply going out unreviewed is precisely what this gate exists to stop. It also CHANGES THE TICKET'S STATUS as a side effect, which is easy to miss: the module applies a default status to every reply (documented as 1 for a reply from the customer, 3 for one from staff) even when you pass no status at all, so replying silently moves the ticket in the queue. Pass statusId if you care where it lands -- the API documents neither what the numeric statuses mean nor any endpoint that lists them, so take the id from the Perfex admin or from an existing ticket. The cc field fans the same unrecallable mail out to further addresses. This tool cannot attach files: the API accepts one file here as multipart/form-data, which this connector's HTTP client cannot send and for which the API offers no base64 alternative, so attachments are simply not available rather than silently dropped. Finally, this call carries no idempotency key, so a timeout may have sent the mail anyway -- check the ticket with perfex_get_ticket before retrying rather than replying twice.
- perfex_search_ticketsRead-only
Keyword search across tickets -- the fastest way from a subject line, a client's name or a reference someone quoted in chat to a ticket id. Which columns are matched is not documented and varies by install, so treat a miss as inconclusive rather than proof the ticket does not exist, and fall back to paging perfex_list_tickets. The search route documents no paging parameters, so it returns whatever the install returns in one go.
- perfex_update_ticketWrite
Change a ticket's subject, department, contact, customer or priority. This is not a partial update in practice: the API requires ALL FIVE of subject, departmentId, contactId, customerId and priorityId on every call, so read the ticket with perfex_get_ticket first and pass its current values for everything you are not deliberately changing -- omitting one is a rejected call, and passing a guessed one silently rewrites it. Two limits worth knowing. Ticket STATUS is not among the documented update fields, so the only documented way to move a ticket's status is to post a reply -- which emails the client (perfex_reply_to_ticket). And this API ignores unknown fields on an update instead of rejecting them, so a field name it does not recognise fails silently as a no-op rather than telling you.
Invoices
6 tools3 read-only · 3 writeShowing 6 of 6 tools
- perfex_delete_invoiceWriteDestructive
Permanently deletes an invoice. This destroys an issued financial record -- in most jurisdictions the business is legally required to retain it, and its tax figures may already have been reported. The correct way to cancel or reverse an invoice a client has seen is a credit note, not a delete. There is no undo through this API: the invoice, its line items and its custom-field data all go, and any payments recorded against it lose their parent. Deleting is only reasonable for an invoice that was created in error and never sent. Note that this uses the plain /invoices/{id} route -- unlike customers, contacts, leads, tasks and tickets, which delete through Perfex's odd /delete/{resource}/{id} path.
- perfex_get_invoiceRead-only
One invoice in full -- its line items (each with their own custom fields), the embedded client record, every payment recorded against it, attachments, scheduled email, custom fields, and `total_left_to_pay`. This is the tool to reach for before changing anything: perfex_update_invoice demands the full set of create fields back, so read them here first. Two parsing traps in the payload: `allowed_payment_modes` comes back PHP-serialized (a:2:{i:0;s:1:"1";...}) rather than as JSON, so treat it as opaque and get real payment-mode ids from the payment-modes lookup; and multi-value custom fields are JSON encoded inside a string.
- perfex_list_invoicesRead-only
Invoices on this Perfex install, newest-first by default, with the pagination metadata (total, total_pages, has_more) needed to page through them. Rows come back as Perfex returns them; use `fields` to narrow the columns, since a full invoice row carries billing and shipping addresses, notes and terms. Start here to find an invoice id -- perfex_get_invoice, perfex_update_invoice and perfex_send_invoice_email all take that id. Use perfex_search_invoices instead when you have a number or a client name and no id. Note that invoice `status` is derived from the payments recorded against the invoice, not stored as an editable field.
- perfex_search_invoicesRead-only
Keyword search across invoices -- use it when you have an invoice number, a client name or a reference and need the id. The keyword goes in the URL path, so it is URL-encoded for you. Which columns Perfex matches is not documented and varies by install, so treat a miss as inconclusive rather than proof the invoice does not exist, and fall back to paging perfex_list_invoices with `created_after`/`created_before`. This endpoint takes no pagination parameters and returns a plain array.
- perfex_send_invoice_emailWriteDestructive
Emails the invoice, with its PDF attached, to the customer's client. This leaves the building and cannot be recalled. It goes to the client contacts flagged to receive invoice emails, plus anyone in `cc`. It flips the invoice's `sent` flag and stamps `datesend`, which is what stops it appearing as unsent and what starts the overdue-reminder clock. Never run this in a loop. An agent acting on "send all the unsent invoices" would bill the customer's entire client base in one pass, and there is no dry run, no preview and no recall. Send one invoice, on an explicit instruction naming that invoice. Re-sending an invoice that has already been sent emails the client a second copy; the response reports whether it had been sent before. Perfex honours an Idempotency-Key header here, and this connector always sends one -- but unless YOU pass `idempotencyKey`, a fresh key is generated per call, and a fresh key defeats the protection completely: the second call is a second email. So if a call times out and you mean to retry it, retry with the SAME `idempotencyKey` you sent the first time. Regenerating it, or omitting it, turns the retry into a duplicate send. Better still, check `sent`/`datesend` with perfex_get_invoice before retrying at all. A 500 from this call usually means the install has no SMTP configured, or the customer has no contact flagged for invoice emails -- not that the invoice is broken.
- perfex_update_invoiceWrite
Changes an existing invoice's header -- client, number, date, due date, currency, totals, billing address, notes and terms. Read this before using it. It can silently rewrite the money on an invoice that has ALREADY been sent to the client. `subtotal` and `total` are supplied by the caller, not computed by Perfex from the line items, so nothing stops an update leaving an invoice whose stated total disagrees with the items printed on it. Version 3 of the module claims server-side invoice math, but the totals are still required in the request body and which one wins is UNCONFIRMED -- so pass totals that are actually correct rather than relying on either behaviour, and re-read the invoice afterwards to see what Perfex stored. It does NOT touch line items. The API's `newitems[]`/`items[]`/`removed_items[]` arrays have no documented element schema, so this connector will not guess at them -- edit line items in the Perfex UI. Shipping fields and the recurring-billing fields (recurring, cycles, repeat_*) are not exposed either. Perfex requires the entire create field set on an update, which makes this closer to a replace than a patch: values you do not send may be cleared. Always run perfex_get_invoice first and pass back everything you want kept. Because `newitems[]` is documented as required even on update, an install may reject an update that carries no items at all -- a 400 here means exactly that. There is no status field: an invoice becomes paid by having a payment recorded against it, not by being updated.
Catalog
5 tools3 read-only · 2 writeShowing 5 of 5 tools
- perfex_create_itemWrite
Add a product or service to the catalogue so it can be dropped onto future invoices, estimates and proposals. Only description and rate are required. This changes nothing about existing documents and sends no email -- it is reference data. Check perfex_search_items first: nothing here prevents a duplicate item, and two near-identical entries at different rates is how the wrong price ends up on an invoice later. The rate is a bare number in the install's own currency; the endpoint takes no currency parameter, so it inherits whatever the install is configured for.
- perfex_get_itemRead-only
One catalogue item in full, by id. Use it to read an item's exact current wording, rate, tax settings and unit before quoting it to someone or before perfex_update_item -- an update sends only the fields you pass, so this is how you see what you are about to leave alone. Prefer perfex_list_items when you are still looking for the right item.
- perfex_list_itemsRead-only
The saved product and service catalogue -- the reusable items that get pulled onto invoice, estimate and proposal line items, with their descriptions, rates, tax settings, unit and group. Reach for this before building any document with line items: it is where the correct wording and the current rate live, and it is the only way to find an item's id. Any custom fields configured on items come back embedded as a customfields array of {label, value} pairs; note that the label-to-id mapping needed to WRITE a custom field is not in that payload. Use perfex_search_items instead when you already know roughly what the item is called.
- perfex_search_itemsRead-only
Keyword search over the item catalogue -- the quickest route from a product or service name someone mentioned to the item id and its current rate. Which columns are matched is not documented and varies by install, so treat a miss as inconclusive rather than proof the item does not exist, and fall back to paging perfex_list_items. The search route documents no paging parameters, so it returns whatever the install returns in one go.
- perfex_update_itemWrite
Change a catalogue item's wording, rate, tax, group or unit. Every field is optional and only what you pass is sent, so this is a genuine partial update -- but the API IGNORES unknown fields rather than rejecting them, so anything it does not recognise fails silently as a no-op instead of telling you. Read the item first with perfex_get_item so you know what you are changing. What this does to invoices, estimates and proposals that ALREADY reference the item is not documented: do not assume issued paperwork stays frozen at the old rate, and do not assume it follows the new one -- check on this install before repricing anything that has already gone out. Editing the rate on a live item is the quiet way to change what future quotes bill.
Estimates
5 tools3 read-only · 2 writeShowing 5 of 5 tools
- perfex_delete_estimateWriteDestructive
Permanently deletes an estimate, along with its line items and custom-field data. There is no undo through this API. An estimate is a quote rather than an issued financial record, so deleting one is less serious than deleting an invoice -- but if it has already been sent to a client, or has been converted to an invoice, the client's copy and the resulting invoice both outlive it and the paper trail between them breaks. Prefer changing its status to declined or expired over deleting it. Uses the plain /estimates/{id} route, not the /delete/{resource}/{id} form other resources use.
- perfex_get_estimateRead-only
One estimate in full, including its line items and client details. Read this before perfex_update_estimate: the update demands the whole create field set back -- client, number, date, currency, subtotal, total, status and billing street -- and anything you cannot supply from here you would be inventing. Multi-value custom fields come back JSON-encoded inside a string.
- perfex_list_estimatesRead-only
Estimates (quotes) on this Perfex install, with pagination metadata. An estimate is the pre-sale document: it becomes an invoice only when someone converts it, so an accepted estimate is not money owed and will not appear in any invoice or payment total. Start here to find an estimate id -- perfex_get_estimate, perfex_update_estimate and perfex_delete_estimate all take it. Use perfex_search_estimates when you have a number or client name instead of an id.
- perfex_search_estimatesRead-only
Keyword search across estimates -- use it when you have a number, client name or reference and need the id. The keyword travels in the URL path and is encoded for you. Which columns Perfex matches is undocumented and varies by install, so a miss is inconclusive: fall back to paging perfex_list_estimates with date bounds. Takes no pagination parameters and returns a plain array.
- perfex_update_estimateWrite
Changes an existing estimate's header -- client, number, date, expiry, currency, totals, status, billing address, notes and terms. It does NOT touch line items. The API's `newitems[]`/`items[]`/`removed_items[]` arrays have no documented element schema, so this connector will not guess at them -- edit line items in the Perfex UI. Because `newitems[]` is documented as required even on update, an install may reject an update that carries no items at all; a 400 here means exactly that. `subtotal` and `total` are supplied by you, not computed by Perfex from the items, so an update can leave an estimate whose stated total disagrees with what is printed on it. Pass totals that are actually correct. Perfex requires the whole create field set on update, which makes this closer to a replace than a patch -- values you do not send may be cleared. Run perfex_get_estimate first and pass back what you want kept. Note also that the update body uses different field names from the create body for the same data (`expirydate` not `duedate`, `reference_no` not `Reference`); this tool speaks the update spelling, and since Perfex silently ignores unknown fields on PUT rather than rejecting them, a wrong name would quietly do nothing. Changing `status` is a business event, not bookkeeping: marking an estimate accepted or declined is how the pipeline reads it.
Lookups
5 tools5 read-only · 0 writeShowing 5 of 5 tools
- perfex_get_custom_field_definitionsRead-only
The custom-field definitions for one Perfex record type -- for each field, its `fieldName` (the exact key a write must use), its id, its label, its data type, whether it is required, and the option list for select/radio/checkbox types. This is a HARD PREREQUISITE for any tool that sets a custom field, because Perfex custom fields are read/write asymmetric. Reads embed values as `customfields: [{label, value}]` with no id anywhere; writes need the bracket key `custom_fields[<group>][<id>]`. The label-to-id mapping exists only here, so you cannot read a record, change one custom field and write it back without calling this first. perfex_create_customer, perfex_update_customer, perfex_create_contact and perfex_update_contact all take the `fieldName` strings this returns, verbatim -- do not reconstruct them by hand. `fieldBelongsTo` is Perfex's internal group name for the record type, e.g. `invoice` (the one value the module's own write example demonstrates). The full set of accepted group names is per-install and is not documented by the module, so if a group returns nothing, that is more likely a wrong group name than an install with no custom fields. Two parsing traps in the values that come back elsewhere: multiselect and checkbox values arrive as JSON-encoded STRINGS ("[\"A\",\"B\"]"), and link fields arrive as raw HTML anchors.
- perfex_list_expense_categoriesRead-only
The expense categories configured on this install -- id, name and description. Needed to file an expense against the right category, and useful for interpreting expense records that come back carrying only a category id. Purely a lookup: it reports what categories exist, not what has been spent in them.
- perfex_list_payment_modesRead-only
The payment methods configured on this Perfex install -- id, name, whether each is offered on invoices only or expenses only, whether it is selected by default, and whether it is still active. Reach for this before any invoice write: `allowed_payment_modes` is a required field on invoice creation and takes these numeric ids, which appear nowhere else in the API. Also the only way to resolve the `paymentmode` id a payment record needs. Note that an inactive mode still has an id and will still be accepted by a write -- check `active` before offering one to a client.
- perfex_list_tax_ratesRead-only
Every tax rate configured on this install -- id, display name and the percentage. These ids are what invoice, estimate and credit-note line items reference; the rate is not something you can pass as a raw percentage, so a document that needs 20% VAT needs the id of the row whose taxrate is 20. Returns configuration, not tax that has been charged -- for amounts actually billed, read the invoice.
- perfex_list_webhook_eventsRead-only
The authoritative catalogue of webhook events this install can emit -- roughly 124 events across 22 resource groups, fetched live. Use it to answer what can be subscribed to, or to check what an existing webhook's event list actually means. Never hardcode an event name from memory: the module's own docs disagree with themselves about the naming scheme (`customer.created` in one place, `customer_created` in another), and only this endpoint is generated from the running code. This connector does not create, edit or delete webhooks -- a webhook is a standing export of CRM data to an arbitrary URL, which is not something to configure through an agent. Set them up in Perfex under Setup -> API. Also note webhooks are a v3.0+ module feature and their delivery queue is drained by Perfex's cron, so on an install with cron misconfigured they queue silently and never fire. A 403 here usually means the token predates the Webhooks permission rows and an admin needs to re-save it, not that the token is invalid.
Payments
4 tools3 read-only · 1 writeShowing 4 of 4 tools
- perfex_get_paymentRead-only
One payment by id, returned raw plus a `normalized` block that repairs the payload's duplicate `invoiceid` key -- the API emits that key twice, as the invoice id and as the payment-mode name, and the second overwrites the first when the JSON is parsed. So `normalized.invoiceId` is null whenever the mode name won, and `normalized.paymentModeName` holds what was actually there. If you need to know which invoice a payment belongs to and this returns null, go the other way: perfex_get_invoice embeds a reliable `payments[]` array. Note there is no documented way to edit or delete a payment through this API.
- perfex_list_paymentsRead-only
Payments recorded against invoices, with pagination metadata. Each row is returned raw alongside a `normalized` block, because the payment payload has a genuine defect: it carries the key `invoiceid` twice -- once as the invoice id and once as the payment-mode name -- and JSON parsing keeps only the last, so the raw `invoiceid` usually holds a string like "Stripe" rather than an invoice number. Read `normalized.invoiceId` (null when the collision ate it) and `normalized.paymentModeName`, and use `normalized.paymentId` rather than trusting the raw row. To see the payments for one specific invoice, read the invoice with perfex_get_invoice instead -- its payload embeds a reliable `payments[]` array.
- perfex_record_paymentWriteDestructive
Records that money was received against an invoice. Read all of this before using it. This fabricates a financial record. It does not take money, verify that any money arrived, or talk to a payment processor -- it writes a row asserting that the client paid, and Perfex believes it. The invoice's derived status moves toward paid, `total_left_to_pay` drops, and the automatic overdue reminders that would have chased the client stop. Recording a payment that did not happen makes a debt disappear from the books. There is no documented way to undo it. The module's guide lists exactly three payment operations and none of them is an update or a delete, so a payment recorded in error most likely cannot be corrected through this API at all -- it needs someone in the Perfex UI or the database. Treat this as a one-way door and get the invoice id and the amount right the first time. This is also the ONLY way to make an invoice paid through this API: there is no invoice status endpoint, and status is derived from payments. Retries are only safe if you make them safe. Perfex honours an Idempotency-Key header on POST and this connector always sends one, but unless YOU pass `idempotencyKey` a fresh key is generated per call -- and a fresh key means the second call books a second payment. If a call times out and you mean to retry, retry with the SAME `idempotencyKey`. Otherwise check perfex_get_invoice's `payments[]` first. `paymentmode` is the mode id -- get real ids from the payment-modes lookup rather than guessing. `paymentmethod` is a separate optional field the docs name but do not describe; leave it out unless you know the install expects it. Payment custom fields are not supported here, since writing one needs the custom-field definitions endpoint to map label to id. Nor is a payment DATE: the documented parameters are invoiceid, amount, paymentmode, paymentmethod, note and transactionid only, so the payment is dated by Perfex -- backdating one is a UI job.
- perfex_search_paymentsRead-only
Keyword search across payments -- reach for it with a transaction id, a reference or an amount when you do not have the payment id. The keyword goes in the URL path and is encoded for you. Which columns Perfex matches is undocumented, so a miss is inconclusive rather than proof the payment does not exist. Results carry the same `normalized` repair as perfex_list_payments, because the duplicate `invoiceid` key is in this payload too. Takes no pagination parameters and returns a plain array.
Every tool name and description, machine-readable: /llms-full.txt
You decide what it can touch
The same model applies to every connector, and it defaults closed.
Your own credential
You supply your own Perfex CRM key, scoped however you like on their side. It is encrypted with AES-256-GCM and never returned by any API response or tool call.
Writes off by default
A new connection switches on a read-oriented default set only. Every write tool must be enabled deliberately before any client can call it.
Roles enforced server-side
READ, WRITE and ADMIN gate tool invocation on the server, not just in the UI. A READ member's token is refused any write tool.
Connect Perfex CRM in minutes
No infrastructure to run. Copy one URL and one token into your client.
- 1Create a free workspace and connect Perfex CRM.
- 2Choose which tools to expose — writes stay off until you enable them.
- 3Copy your MCP endpoint URL and bearer token.
- 4Paste them into Claude, Cursor, or any MCP client.
{
"mcpServers": {
"serve-mcp": {
"url": "https://servemcp.com/api/mcp/your-workspace",
"transport": "http",
"headers": {
"Authorization": "Bearer smcp_..."
}
}
}
}More in Customer Support
Put Perfex CRM in front of your assistant
Free plan, no card required. Connect in minutes.