ZE extensions · Documentation

CRM Toolbox API

Obtain a session in Deluge, send it on each connector call, and read the response. This reference is public.

Authentication

Every call goes to https://connector.zepartner.net. Create a session from a Deluge script inside Zoho CRM, then send data.session.sessionId as the x-zep-session-id header. Pass an empty string to zelogger.generate_zep_session. The session lasts 24 hours. Cache it until data.session.exp, which is a unix epoch value in milliseconds. The examples on this page assume sessionId is already set.

Deluge · session
sessionResult = zelogger.generate_zep_session("");
sessionId = sessionResult.get("data").get("session").get("sessionId");
Session response
{
  "success": true,
  "data": {
    "session": {
      "crmOrgId": "orgXXXXXXXXXX",
      "extensionName": "ZE CRM Toolbox",
      "userId": "0000000000000000000",
      "userName": "Example User",
      "userEmail": "user@example.com",
      "createdAt": 1790618117000,
      "exp": 1790704517000,
      "sessionId": "<session-id>"
    }
  },
  "error": null
}

The organisation variable zelogger__ZE_API_BASE_URL is https://connector.zepartner.net/protected-api. The same paths work under that prefix, which is what the extension workflows call. A request to https://connector.zepartner.net/protected-api/ze-crm-toolbox/credits is the same call as GET /ze-crm-toolbox/credits below.

Request header
x-zep-session-id: <session-id>

With detailed: true, read the HTTP status and the JSON body from the invokeurl map.

Deluge · read the response
responseCode = response.get("responseCode");
body = response.get("responseText").toMap();

A valid session is required on every call. Record automation, the CRM catalogue, and the screenshot call also require the session to belong to ZE CRM Toolbox. A session for another extension returns HTTP 403. Screenshot capture also needs the CRM user on the session, and an active subscription.

Address lookup, email validation, email verification, and phone validation each use 1 credit when the check succeeds. Record automation uses 1 credit for each non-empty field it checks. Reading credits and reading or refreshing the catalogue do not use a credit. A screenshot reserves 1 monthly allowance before the capture.

An invalid or expired session is HTTP 401: { "success": false, "data": null, "error": "Session expired" }. The error text can also be Invalid sessionId, Invalid session claims, Session organization mismatch, or Invalid session. A request with no credentials returns { "ERROR": "Unauthorized" }. On HTTP 401, create a new session and retry once.

Credits

Remaining credits

Read the organisation’s remaining allowances. This call does not deduct a credit.

GET /ze-crm-toolbox/credits

Next_Reset_Time is a unix timestamp in seconds. The four check counters refill at that time, which is the next UTC midnight.

remainingScreenshots is how many page captures are left this month. screenshotAllowance is the plan’s monthly cap. The row can include other stored columns.

Deluge
headers = Map();
headers.put("x-zep-session-id", sessionId);
requestUrl = "https://connector.zepartner.net/ze-crm-toolbox/credits";
response = invokeurl
[
	url :requestUrl
	type :GET
	headers:headers
	detailed:true
];
info response;
Response
{
  "success": true,
  "data": {
    "CRM_Org_ID": "orgXXXXXXXXXX",
    "Current_Plan_Code": "ze_helper_bronze",
    "Current_Plan_Cost": 29,
    "Next_Reset_Time": 1790707200,
    "Address_Lookup_Remaining": 50,
    "Validate_Email_Remaining": 200,
    "Verify_Email_Remaining": 10,
    "Validate_Phone_Remaining": 200,
    "remainingScreenshots": 100,
    "screenshotAllowance": 100
  }
}

Checks

Address lookup

Geocode a postal address. A successful call uses 1 address-lookup credit.

POST /ze-crm-toolbox/api/addressLookup

Parameters

InputBody
The address to look up. Required.
countryCodeBody
Two-letter country code, for example GB. Required.

data.locations is the list to map onto a CRM record. The upstream body can include further fields. Daily_Credits_Remaining is the balance after this call.

A missing Input, a missing organisation, an unknown action, a used-up allowance, or an upstream failure returns HTTP 500 with { "ERROR": "<message>" }. The credit is deducted only after the lookup succeeds.

Deluge
payload = Map();
payload.put("Input", "10 Downing Street, London");
payload.put("countryCode", "GB");
headers = Map();
headers.put("Content-Type", "application/json");
headers.put("x-zep-session-id", sessionId);
requestUrl = "https://connector.zepartner.net/ze-crm-toolbox/api/addressLookup";
response = invokeurl
[
	url :requestUrl
	type :POST
	parameters:payload.toString()
	headers:headers
	detailed:true
];
info response;
Response
{
  "success": true,
  "message": "addressLookup completed successfully.",
  "data": {
    "found": 1,
    "locations": [
      {
        "address": "10 Downing Street, London, SW1A 2AA, United Kingdom",
        "latitude": 51.5034,
        "longitude": -0.1276,
        "address-components": {
          "house-number": "10",
          "road": "Downing Street",
          "city": "London",
          "postal-code": "SW1A 2AA",
          "country": "United Kingdom"
        }
      }
    ],
    "action": "addressLookup",
    "CRM_Org_ID": "orgXXXXXXXXXX",
    "Daily_Credits_Remaining": { "Address_Lookup_Remaining": 49, "Validate_Phone_Remaining": 199, "Validate_Email_Remaining": 199, "Verify_Email_Remaining": 9 },
    "Last_Checked_At": "2026-11-13T17:00:00.000Z"
  }
}
Validate an email address

Check that an email address is syntactically usable and report disposable, freemail, and personal flags. This does not confirm the mailbox exists. A successful call uses 1 validate-email credit.

POST /ze-crm-toolbox/api/validateEmail

Parameters

InputBody
The email address. Required.
fixTyposBody
Optional. When true, the upstream service may correct a common typo and return the corrected address in data.email. Defaults to true. Suggest_Typo is accepted as the same flag.

Read data.valid, data.email, data.is-disposable, data.is-freemail, and data.is-personal. verified is not set on this call. Use verify email when the mailbox itself must be checked.

A failure returns HTTP 500 with { "ERROR": "<message>" }. The credit is deducted only after the check succeeds.

Deluge
payload = Map();
payload.put("Input", "person@example.com");
headers = Map();
headers.put("Content-Type", "application/json");
headers.put("x-zep-session-id", sessionId);
requestUrl = "https://connector.zepartner.net/ze-crm-toolbox/api/validateEmail";
response = invokeurl
[
	url :requestUrl
	type :POST
	parameters:payload.toString()
	headers:headers
	detailed:true
];
info response;
Response
{
  "success": true,
  "message": "validateEmail completed successfully.",
  "data": {
    "valid": true,
    "email": "person@example.com",
    "is-disposable": false,
    "is-freemail": false,
    "is-personal": true,
    "action": "validateEmail",
    "CRM_Org_ID": "orgXXXXXXXXXX",
    "Daily_Credits_Remaining": { "Address_Lookup_Remaining": 49, "Validate_Phone_Remaining": 199, "Validate_Email_Remaining": 199, "Verify_Email_Remaining": 9 },
    "Last_Checked_At": "2026-11-13T17:00:00.000Z"
  }
}
Verify an email address

Check that the mailbox accepts mail, and return the same disposable, freemail, and personal flags. A successful call uses 1 verify-email credit.

POST /ze-crm-toolbox/api/verifyEmail

Parameters

InputBody
The email address. Required.
fixTyposBody
Optional. When true, a common typo may be corrected and returned in data.email. Defaults to true. Suggest_Typo is accepted as the same flag.

Read data.verified as well as data.valid. data.email is the address to store when a typo was corrected.

A failure returns HTTP 500 with { "ERROR": "<message>" }. The credit is deducted only after the check succeeds.

Deluge
payload = Map();
payload.put("Input", "person@example.com");
headers = Map();
headers.put("Content-Type", "application/json");
headers.put("x-zep-session-id", sessionId);
requestUrl = "https://connector.zepartner.net/ze-crm-toolbox/api/verifyEmail";
response = invokeurl
[
	url :requestUrl
	type :POST
	parameters:payload.toString()
	headers:headers
	detailed:true
];
info response;
Response
{
  "success": true,
  "message": "verifyEmail completed successfully.",
  "data": {
    "valid": true,
    "verified": true,
    "email": "person@example.com",
    "is-disposable": false,
    "is-freemail": false,
    "is-personal": true,
    "action": "verifyEmail",
    "CRM_Org_ID": "orgXXXXXXXXXX",
    "Daily_Credits_Remaining": { "Address_Lookup_Remaining": 49, "Validate_Phone_Remaining": 199, "Validate_Email_Remaining": 199, "Verify_Email_Remaining": 9 },
    "Last_Checked_At": "2026-11-13T17:00:00.000Z"
  }
}
Validate a phone number

Check a phone number and return its international form. A successful call uses 1 validate-phone credit.

POST /ze-crm-toolbox/api/validatePhone

Parameters

InputBody
The phone number. Required.
countryCodeBody
Optional two-letter country code, for example GB. When it is omitted, the connector uses the caller IP to choose a country.

Read data.valid, data.international-number, data.international-calling-code, data.is-mobile, and data.type. Store data.international-number when it differs from the value you sent.

A failure returns HTTP 500 with { "ERROR": "<message>" }. The credit is deducted only after the check succeeds.

Deluge
payload = Map();
payload.put("Input", "020 7946 0958");
payload.put("countryCode", "GB");
headers = Map();
headers.put("Content-Type", "application/json");
headers.put("x-zep-session-id", sessionId);
requestUrl = "https://connector.zepartner.net/ze-crm-toolbox/api/validatePhone";
response = invokeurl
[
	url :requestUrl
	type :POST
	parameters:payload.toString()
	headers:headers
	detailed:true
];
info response;
Response
{
  "success": true,
  "message": "validatePhone completed successfully.",
  "data": {
    "valid": true,
    "international-calling-code": "+44",
    "international-number": "+442079460958",
    "is-mobile": false,
    "type": "landline",
    "action": "validatePhone",
    "CRM_Org_ID": "orgXXXXXXXXXX",
    "Daily_Credits_Remaining": { "Address_Lookup_Remaining": 49, "Validate_Phone_Remaining": 199, "Validate_Email_Remaining": 199, "Verify_Email_Remaining": 9 },
    "Last_Checked_At": "2026-11-13T17:00:00.000Z"
  }
}

Record automation

Check a record after it changes

Run the email or phone check configured for a module, write the result back to the record, and store a history row. This is the call the extension’s on-edit workflows make. Use it from a custom module the same way.

POST /ze-crm-toolbox/automation/on-record-change

Parameters

moduleApiNameBody
CRM module API name, for example Contacts or a custom module. Required.
recordIdBody
CRM record id. Required.
triggerBody
email or phone. Any other value returns HTTP 400.

An inactive subscription returns HTTP 402 { "error": "Subscription is not active" }. A missing field returns HTTP 400. A session for another extension returns HTTP 403 { "error": "Unauthorised" }.

Every other outcome is HTTP 200. skipped true with reason settings_not_ready means extension settings have not been saved yet. module_off means that module has no matching automation: email must be autoValidateEmails or autoVerifyEmails, and phone must be autoValidatePhone. no_fields means the module has no email or phone fields in the catalogue. empty_values means those fields are blank.

failed true includes urgency and message. Typical messages are that Zoho is not connected, the record could not be read or updated, credits could not be read, the allowance is used up, or the check failed.

A completed call returns skipped false, checked (how many non-empty fields were checked), and invalid. One credit is used for each field that was checked. Phone numbers that return a different international form are written back. The invalid flag on the record is updated when it changes.

Deluge
payload = Map();
payload.put("moduleApiName", "Contacts");
payload.put("recordId", "0000000000000000000");
payload.put("trigger", "email");
headers = Map();
headers.put("Content-Type", "application/json");
headers.put("x-zep-session-id", sessionId);
requestUrl = "https://connector.zepartner.net/ze-crm-toolbox/automation/on-record-change";
response = invokeurl
[
	url :requestUrl
	type :POST
	parameters:payload.toString()
	headers:headers
	detailed:true
];
info response;
Response
{
  "skipped": false,
  "checked": 1,
  "invalid": false
}

CRM catalogue

List modules

Read the cached CRM module catalogue for this organisation. This call does not use a credit. Custom modules are included so a function can resolve a module API name.

GET /ze-crm-toolbox/meta/modules

Each module entry uses p for the plural label, a for the API name, m for the module name, and c set to 1 when the module is custom.

orgVariable is the same catalogue as a JSON string, kept under 3000 characters, with custom modules first. It is the value stored in the CRM org variable.

Zoho not connected returns HTTP 409 { "error": "Zoho OAuth is not connected" }. A session for another extension returns HTTP 403. A Zoho read failure returns HTTP 502.

Deluge
headers = Map();
headers.put("x-zep-session-id", sessionId);
requestUrl = "https://connector.zepartner.net/ze-crm-toolbox/meta/modules";
response = invokeurl
[
	url :requestUrl
	type :GET
	headers:headers
	detailed:true
];
info response;
Response
{
  "cachedAt": 1790618117000,
  "modules": {
    "Contacts": { "p": "Contacts", "a": "Contacts", "m": "Contacts", "c": 0 },
    "CustomModule1": { "p": "Matters", "a": "CustomModule1", "m": "CustomModule1", "c": 1 }
  },
  "orgVariable": "{\"cachedAt\":1790618117000,\"modules\":{\"CustomModule1\":{\"p\":\"Matters\",\"a\":\"CustomModule1\",\"m\":\"CustomModule1\",\"c\":1}}}"
}
List fields for one module

Read the cached fields for one module. This call does not use a credit. Email and phone automation uses data_type email and phone from this list.

GET /ze-crm-toolbox/meta/fields/:moduleApiName

Parameters

moduleApiNamePath
CRM module API name, for example Contacts or CustomModule1.

Each field has api_name, field_label, and data_type. Zoho not connected returns HTTP 409. A Zoho read failure returns HTTP 502.

Deluge
headers = Map();
headers.put("x-zep-session-id", sessionId);
requestUrl = "https://connector.zepartner.net/ze-crm-toolbox/meta/fields/Contacts";
response = invokeurl
[
	url :requestUrl
	type :GET
	headers:headers
	detailed:true
];
info response;
Response
{
  "cachedAt": 1790618117000,
  "moduleApiName": "Contacts",
  "fields": [
    { "api_name": "Email", "field_label": "Email", "data_type": "email" },
    { "api_name": "Phone", "field_label": "Phone", "data_type": "phone" }
  ]
}
List fields for every module

Read the module catalogue and the cached fields for every module in it. This call does not use a credit.

GET /ze-crm-toolbox/meta/fields

modules matches GET /meta/modules. fields is one entry per module, in the same shape as GET /meta/fields/:moduleApiName.

Deluge
headers = Map();
headers.put("x-zep-session-id", sessionId);
requestUrl = "https://connector.zepartner.net/ze-crm-toolbox/meta/fields";
response = invokeurl
[
	url :requestUrl
	type :GET
	headers:headers
	detailed:true
];
info response;
Response
{
  "modules": {
    "cachedAt": 1790618117000,
    "modules": {
      "Contacts": { "p": "Contacts", "a": "Contacts", "m": "Contacts", "c": 0 }
    },
    "orgVariable": "{\"cachedAt\":1790618117000,\"modules\":{}}"
  },
  "fields": [
    {
      "cachedAt": 1790618117000,
      "moduleApiName": "Contacts",
      "fields": [
        { "api_name": "Email", "field_label": "Email", "data_type": "email" }
      ]
    }
  ]
}
Refresh the catalogue

Drop the cached modules and fields, read them again from Zoho, and return the full catalogue. This call does not use a credit. The body can be empty.

POST /ze-crm-toolbox/meta/refresh

The response matches GET /meta/fields. Zoho not connected returns HTTP 409.

Deluge
payload = Map();
headers = Map();
headers.put("Content-Type", "application/json");
headers.put("x-zep-session-id", sessionId);
requestUrl = "https://connector.zepartner.net/ze-crm-toolbox/meta/refresh";
response = invokeurl
[
	url :requestUrl
	type :POST
	parameters:payload.toString()
	headers:headers
	detailed:true
];
info response;
Response
{
  "modules": {
    "cachedAt": 1790618117000,
    "modules": {
      "Contacts": { "p": "Contacts", "a": "Contacts", "m": "Contacts", "c": 0 }
    },
    "orgVariable": "{\"cachedAt\":1790618117000,\"modules\":{}}"
  },
  "fields": [
    {
      "cachedAt": 1790618117000,
      "moduleApiName": "Contacts",
      "fields": [
        { "api_name": "Email", "field_label": "Email", "data_type": "email" }
      ]
    }
  ]
}

Screenshot

Capture a page and attach it

Capture a public page and attach the image to a CRM record. The session must include the CRM user. One screenshot allowance is reserved before the capture. A failed capture keeps that charge. An empty allowance does not capture.

POST /ze-crm-toolbox/custom-actions/take-screenshot

Parameters

moduleApiNameBody
CRM module API name. Letters, digits, and underscores. Required.
recordIdBody
CRM record id. Required.
backgroundBody
When true, the capture continues after HTTP 202 and the function can return. The extension custom action sends true.
urlModeBody
fixed uses url. record_field uses resolvedUrl, which your function reads from the record first. Any other value is treated as fixed.
urlBody
Page address when urlMode is fixed.
resolvedUrlBody
Page address already read from the record when urlMode is record_field.
urlFieldApiNameBody
The CRM field your function read. The connector uses resolvedUrl, not this name, to fetch the page.
fileNameBody
Attachment name. Unsafe characters are replaced. The file is stored as .webp.
replaceExistingBody
yes deletes an existing attachment with the same file name before the new one is added. Any other value leaves existing files in place.

background true returns HTTP 202 { "success": true, "code": "ACCEPTED", "recordId": "<id>" }. A finished foreground call returns HTTP 200 { "success": true, "code": "SUCCESS", "fileName": "<name>.webp" }.

An inactive subscription is HTTP 402 code INACTIVE_SUBSCRIPTION. A used-up allowance is HTTP 402 code ALLOWANCE_EXHAUSTED. A missing module or record is HTTP 400 code INVALID_PAYLOAD. A missing page address is HTTP 422 code MISSING_URL. Zoho not connected for this user is HTTP 409 code OAUTH_NOT_CONNECTED. A session for another extension is HTTP 403 code WRONG_EXTENSION. A capture or attach failure is HTTP 502.

Deluge
payload = Map();
payload.put("background", true);
payload.put("moduleApiName", "Accounts");
payload.put("recordId", "0000000000000000000");
payload.put("urlMode", "fixed");
payload.put("url", "https://example.com");
payload.put("fileName", "Website");
payload.put("replaceExisting", "yes");
headers = Map();
headers.put("Content-Type", "application/json");
headers.put("x-zep-session-id", sessionId);
requestUrl = "https://connector.zepartner.net/ze-crm-toolbox/custom-actions/take-screenshot";
response = invokeurl
[
	url :requestUrl
	type :POST
	parameters:payload.toString()
	headers:headers
	detailed:true
];
info response;
Response · HTTP 202
{
  "success": true,
  "code": "ACCEPTED",
  "recordId": "0000000000000000000"
}
Start a conversation

What could work better in your business?

Tell Gregory where the friction is. You do not need to know the service or technology before getting in touch.

Work with Gregory Or email help@zepartner.net