Introduction
Welcome to the Jetpack CRM API v2.0. The API can be used to talk to Jetpack CRM from another application.
All endpoints live under your CRM site's API root:
https://{your-site}/zbs_api/{endpoint}
Requirements
- Jetpack CRM v6.0+
- WordPress v6.0+
- PHP 7.4+
- Pretty permalinks enabled in Settings → Permalinks. Default permalinks will not work because the API uses custom rewrite endpoints.
Errors
The Jetpack CRM API returns the following error codes:
| Error Code | Meaning |
|---|---|
| 400 | Bad Request. Your request is invalid or the endpoint is unknown. |
| 401 | Unauthorized. Your API key or secret is wrong. |
| 403 | Forbidden. You do not have permission to access this resource. |
| 405 | Method Not Allowed. You used an HTTP method the endpoint doesn't accept. |
| 418 | I'm a teapot. You tried the BREW method. |
Parameters
Every request must include your API credentials as query parameters (see Authentication).
Pagination
List endpoints accept:
page: page number, starting at1(default:1)perpage: results per page (default:10)order: sort direction,ASCorDESC(default:DESC)
Ownership / Assignment
Jetpack CRM has an ownership and assignment model: results can be restricted to records owned by, or assigned to, a specific CRM team member. Endpoints that support this accept the assign, owned, or owner parameters (see each endpoint for details).
Other
zbs_query: search phrase for endpoints that support filteringreplace_hyphens_with_underscores_in_json_keys: set to1to rewrite hyphens to underscores in JSON keys (useful for integrations like Zapier that reject hyphenated keys)external_api_name: string identifier for the calling integration, surfaced in logs/webhooks
Authentication
The API key and secret are passed as query parameters on every request:
/zbs_api/{endpoint}?api_key={your_api_key}&api_secret={your_api_secret}
Jetpack CRM uses an API key + secret pair to authenticate requests. Generate yours from the CRM admin (see How to Generate API Keys).
- Publishable key:
jpcrm_pk_... - Secret key:
jpcrm_sk_...
The credentials grant both read and write access to your CRM, so treat the secret like a password.
Status
Get Status
A lightweight health-check endpoint. Use it to verify your API credentials and check the running CRM version before making any other calls.
HTTP Request
GET /status
Optional query parameters:
full: if present (any value), the response also includes installed core modules and active pro extensions.
JSON response example:
{
"success": true,
"data": {
"status": "Successful Connection",
"message": "Your API Connection with Jetpack CRM is functioning correctly.",
"crm_version": "6.7.2",
"db_version": "4.3"
}
}
With
?full=1:
{
"success": true,
"data": {
"status": "Successful Connection",
"message": "Your API Connection with Jetpack CRM is functioning correctly.",
"crm_version": "6.7.2",
"db_version": "4.3",
"modules": {
"mail-campaigns": true,
"client-portal": true
},
"extensions": {
"stripe": { "name": "Stripe Sync", "version": "2.4.0" }
}
}
}
Customers
Create Customer
Creates or updates a customer. The unique key is the email address; if a matching contact exists it is updated, otherwise a new one is created. Pass id to update a specific contact regardless of email. On success the response echoes the data you sent plus the new id (if created).
HTTP Request
POST /create_customer
Send a JSON body. Common fields:
email(string): customer email. Unique key for create-or-update.id(int): existing contact ID. If set, updates that record.status(string): one ofLead,Customer,Refused. Other custom statuses are also accepted.prefix,fname,lname(string): name fields.addr1,addr2,city,county,postcode,country(string): main address.secaddr1,secaddr2,seccity,seccounty,secpostcode,seccountry(string): second address.hometel,worktel,mobtel(string): phone numbers.assign(int): WordPress user ID of the team member to own this contact.tags(array): list of tag strings to attach.{custom-field-slug}(mixed): any custom field by its slug.
<?php
$data = array(
'status' => 'Lead',
'prefix' => 'Mr',
'fname' => 'John',
'lname' => 'Doe',
'email' => 'someone@somewhere.com',
'hometel' => '1234 567 89',
'worktel' => '1234 567 89',
'mobtel' => '1234 567 89',
'addr1' => 'Sample House',
'addr2' => 'Sample Road',
'city' => 'Sample City',
'county' => 'Sample State',
'postcode' => 'P0ST C0D3',
'country' => 'UK',
'secaddr1' => 'Sample House 2',
'secaddr2' => 'Sample Road 2',
'seccity' => 'Sample City 2',
'seccounty' => 'Sample State 2',
'secpostcode' => 'P1ST C1D3',
'seccountry' => 'USA',
'tags' => array( 'newsletter', 'vip' ),
'assign' => 1,
'custom-field' => 'bacon',
);
?>
JSON response example:
{
"fname": "John",
"lname": "Doe",
"email": "johndoe@example.com",
"status": "Lead",
"prefix": "Mr",
"addr1": "1 Sample Road",
"city": "Sampleton",
"postcode": "SAM PL4",
"id": 135
}
View Customers
Returns a paginated list of customers. Each entry includes core fields plus any custom fields keyed by slug. Optionally include related invoices, quotes, transactions, and tags.
HTTP Request
POST /customers
Send a JSON body. All fields optional:
page(int): page number, default1.perpage(int): results per page, default10.search(string): filter by name/email substring.owned(int): WP user ID; only return contacts owned by this user.company(int): only return contacts attached to this company ID.tags(bool): include tags in each customer object. Default:false.invoices,quotes,transactions(bool): include related records in each customer object. Default:false.
<?php
$data = array(
'perpage' => 20,
'page' => 1,
'search' => 'doe',
'transactions' => true,
'invoices' => true,
'quotes' => true,
'tags' => true,
'owned' => 1,
'company' => 42,
);
?>
JSON response example:
[
{
"id": 20267,
"owner": 1,
"status": "Customer",
"email": "john@example.com",
"prefix": "Mr",
"fname": "John",
"lname": "Doe",
"addr1": "1 Sample Road",
"addr2": "",
"city": "Sampleton",
"county": "",
"country": "UK",
"postcode": "SAM PL4",
"hometel": "123 455",
"worktel": "",
"mobtel": "555 135",
"tw": "",
"li": "",
"fb": "",
"created": "2024-04-25 03:33:38",
"createduts": 1713994418,
"lastupdated": 1713994418,
"fullname": "John Doe",
"name": "John Doe",
"cf1": "Custom Field 1"
}
]
Search Customers
Search customers by free-text query against the deep meta (name, address, custom fields, etc.), or look up a single customer directly by email.
HTTP Request
GET /customer_search
Query parameters:
zbs_query(string): search phrase. Returns matching customers.email(string): exact email lookup. Returns one customer with related invoices, transactions, and tags attached.page,perpage,order: standard pagination.replace_hyphens_with_underscores_in_json_keys(int): set to1to rewrite hyphenated JSON keys to underscores (useful for Zapier, etc.).
<?php
// Free-text search:
// GET /zbs_api/customer_search?api_key=...&api_secret=...&zbs_query=doe
// Direct email lookup (includes financial data):
// GET /zbs_api/customer_search?api_key=...&api_secret=...&email=john@doe.com
?>
JSON response example (
zbs_querysearch returns an array):
[
{
"id": 20267,
"owner": 1,
"status": "Customer",
"email": "john@example.com",
"fname": "John",
"lname": "Doe",
"fullname": "John Doe",
"name": "John Doe",
"created": "2024-04-25 03:33:38"
}
]
JSON response example (
{
"id": 20267,
"owner": 1,
"status": "Customer",
"email": "john@example.com",
"fname": "John",
"lname": "Doe",
"fullname": "John Doe",
"created": "2024-04-25 03:33:38",
"invoices": [],
"transactions": [],
"tags": []
}
Companies
Create Company
Creates or updates a company. The unique key is the email address; if a matching company exists it is updated, otherwise a new one is created. Pass id to update a specific company regardless of email. On success the response echoes the data you sent plus the new id (if created).
HTTP Request
POST /create_company
Send a JSON body. Common fields:
name(string): company name.email(string): company email. Unique key for create-or-update.id(int): existing company ID. If set, updates that record.status(string): company status. If omitted, the CRM's default status is used.addr1,addr2,city,county,postcode,country(string): main address.secaddr1,secaddr2,seccity,seccounty,secpostcode,seccountry(string): second address.maintel,sectel(string): phone numbers.tw,li,fb(string): Twitter/LinkedIn/Facebook URLs.assign(int): WordPress user ID of the team member to own this company.tags(array): list of tag strings to attach.{custom-field-slug}(mixed): any custom field by its slug.
<?php
$data = array(
'name' => 'Acme Inc.',
'email' => 'hello@acme.com',
'status' => 'Customer',
'maintel' => '1234 567 89',
'sectel' => '1234 567 90',
'addr1' => 'Sample House',
'addr2' => 'Sample Road',
'city' => 'Sample City',
'county' => 'Sample State',
'postcode' => 'P0ST C0D3',
'country' => 'UK',
'secaddr1' => 'Sample House 2',
'secaddr2' => 'Sample Road 2',
'seccity' => 'Sample City 2',
'seccounty' => 'Sample State 2',
'secpostcode' => 'P1ST C1D3',
'seccountry' => 'USA',
'tags' => array( 'partner', 'priority' ),
'assign' => 1,
'custom-field' => 'bacon',
);
?>
JSON response example:
{
"name": "Acme Inc.",
"email": "hello@acme.com",
"status": "Customer",
"addr1": "Sample House",
"city": "Sample City",
"country": "UK",
"id": 442
}
View Companies
Returns a paginated list of companies.
HTTP Request
POST /companies
Send a JSON body. All fields optional:
page(int): page number, default1.perpage(int): results per page, default10.search(string): filter by name/email substring.owned(int): WP user ID; only return companies owned by this user.invoices,quotes,transactions(bool): include related records and totals for each company. Default:false.
<?php
$data = array(
'perpage' => 20,
'page' => 1,
'search' => 'acme',
'invoices' => true,
'transactions' => true,
'owned' => 1,
);
?>
JSON response example:
[
{
"id": 442,
"owner": 1,
"status": "Customer",
"name": "Acme Inc.",
"email": "hello@acme.com",
"addr1": "Sample House",
"addr2": "Sample Road",
"city": "Sample City",
"county": "Sample State",
"country": "UK",
"postcode": "P0ST C0D3",
"maintel": "1234 567 89",
"sectel": "",
"tw": "",
"li": "",
"fb": "",
"created": 1713994418,
"created_date": "2024-04-25",
"lastupdated": 1713994418,
"invoices_total": "1500.00",
"invoices_count": 3,
"transactions_total": "1500.00",
"transactions_paid_total": "1500.00",
"total_value": "1500.00"
}
]
Quotes
View Quotes
Returns a paginated list of quotes.
HTTP Request
GET /quotes
Query parameters: standard pagination (page, perpage, order).
JSON response example:
[
{
"id": 20069,
"owner": 1,
"id_override": "",
"title": "New Website",
"currency": "USD",
"value": "500.00",
"date": 1492185770,
"date_date": "2024-04-14",
"template": 3,
"content": "<p>Quote body HTML...</p>",
"notes": "",
"send_attachments": false,
"hash": "abcd1234",
"lastviewed": 0,
"lastviewed_date": false,
"viewed_count": 0,
"accepted": 0,
"accepted_date": false,
"created": 1492185770,
"created_date": "2024-04-14",
"lastupdated": 1492185770,
"lastupdated_date": "2024-04-14",
"status": -2
}
]
The status field is computed from other fields:
-1: draft (no template applied)-2: published, not yet accepted1: accepted
Invoices
View Invoices
Returns a paginated list of invoices.
HTTP Request
GET /invoices
Query parameters: standard pagination (page, perpage, order).
JSON response example:
[
{
"id": 20069,
"owner": 1,
"id_override": "INV-0042",
"parent": 0,
"status": "Unpaid",
"status_label": "Unpaid",
"hash": "abcd1234",
"currency": "USD",
"addressed_from": "Acme Inc.",
"addressed_to": "John Doe",
"address_to_objtype": 1,
"allow_partial": false,
"allow_tip": false,
"date": 1713994418,
"date_date": "2024-04-24",
"due_date": 1716586418,
"due_date_date": "2024-05-24",
"paid_date": 0,
"net": "500.00",
"discount": "0.00",
"discount_type": "percent",
"shipping": "0.00",
"tax": "0.00",
"total": "500.00",
"hash_viewed_count": 0,
"portal_viewed_count": 0,
"created": 1713994418,
"created_date": "2024-04-24 12:00:00",
"lastupdated": 1713994418
}
]
Transactions
Create Transaction
Creates or updates a transaction. If email matches an existing customer the transaction is attached to them; otherwise a new customer is created using the email and optional fname. Existing transactions with the same orderid are updated rather than duplicated.
HTTP Request
POST /create_transaction
Send a JSON body. Required:
orderid(string): unique reference. Stored asrefon the transaction.status(string): e.g.Completed,Refunded,Failed. Allowed values come from CRM settings (Transactions tab).total(string|number): grand total.
Optional:
email(string): customer email. Used to find or create the linked contact.fname(string): first name, used only when auto-creating a contact.date(int): Unix timestamp of the transaction. Auto-set if omitted.type(string): e.g.Sale,Refund.title,desc(string).currency(string): ISO code, e.g.USD.net,fee,discount,tax,shipping,shipping_tax(string|number).{custom-field-slug}(mixed): any custom field by its slug.
<?php
$data = array(
'orderid' => 'ORDER-0042',
'email' => 'john@example.com',
'fname' => 'John',
'status' => 'Completed',
'total' => '79.99',
'net' => '59.99',
'tax' => '0.00',
'fee' => '10.00',
'discount' => '10.00',
'currency' => 'USD',
'title' => 'Your Item Name',
);
?>
JSON response example (request body echoed back with new
id):
{
"orderid": "ORDER-0042",
"email": "john@example.com",
"fname": "John",
"status": "Completed",
"total": "79.99",
"net": "59.99",
"tax": "0.00",
"fee": "10.00",
"discount": "10.00",
"currency": "USD",
"title": "Your Item Name",
"id": 20286
}
View Transactions
Returns a paginated list of transactions.
HTTP Request
GET /transactions
Query parameters: standard pagination (page, perpage, order).
JSON response example:
[
{
"id": 20286,
"owner": 1,
"status": "Completed",
"type": "Sale",
"status_bool": 1,
"type_accounting": "credit",
"ref": "ORDER-0042",
"origin": "api",
"parent": 0,
"title": "My Awesome Order",
"desc": "",
"date": 1714237915,
"date_date": "2024-04-27 16:51:55",
"currency": "USD",
"net": "59.99",
"fee": "10.00",
"discount": "10.00",
"tax": "0.00",
"shipping": "0.00",
"total": "79.99",
"date_paid": 1714237915,
"date_paid_date": "2024-04-27 16:51:55",
"created": 1714237915,
"created_date": "2024-04-27 16:51:55",
"lastupdated": 1714237915
}
]
Notes:
status_boolis1if the status is configured to count as a successful transaction,-1otherwise. Configure which statuses count under Settings → Transactions in the CRM.type_accountingis a derived classification (credit/debit/ etc.) based on thetypevalue.
Events
Create Event
Creates or updates an event. Pass id to update an existing event.
HTTP Request
POST /create_event
Send a JSON body. All fields optional:
title(string): event title.customer(int): contact ID this event is attached to.notes(string): event description. Stored asdescon the record.from(string): start datetime, formatm/d/Y H:00:00.to(string): end datetime, same format.notify(int): set to24to schedule a reminder 24 hours beforefrom. Any other value disables notifications.complete(int):1to mark complete,0for incomplete.owner(int): WordPress user ID owning the event.-1for no owner.id(int): existing event ID to update.
<?php
$data = array(
'title' => 'Follow-up call',
'customer' => 44149,
'notes' => 'Discuss renewal options',
'from' => '02/01/2024 14:00:00',
'to' => '02/01/2024 15:00:00',
'notify' => 24,
'complete' => 0,
'owner' => 1,
);
?>
JSON response example (request body echoed back with new
id):
{
"title": "Follow-up call",
"customer": 44149,
"notes": "Discuss renewal options",
"to": "02/01/2024 15:00:00",
"from": "02/01/2024 14:00:00",
"notify": 24,
"complete": 0,
"owner": 1,
"id": 44155
}
View Events
Returns a paginated list of events.
HTTP Request
GET /events
Query parameters: standard pagination (page, perpage, order), plus:
owner(int): filter to events owned by this WordPress user ID.
JSON response example:
[
{
"id": 44155,
"owner": 1,
"title": "Follow-up call",
"desc": "Discuss renewal options",
"start": 1706799600,
"start_date": "2024-02-01 14:00:00",
"end": 1706803200,
"end_date": "2024-02-01 15:00:00",
"complete": 0,
"show_on_portal": 0,
"show_on_cal": 1,
"created": 1706796000,
"created_date": "2024-02-01 13:00:00",
"lastupdated": 1706796000
}
]
Notes:
- On read,
notesbecomesdesc, andfrom/tobecomestart/end(as Unix timestamps), plus formattedstart_date/end_date.