Build on Crossing Edge
Read and change everything in a workspace from your own systems. Every call runs with the access of the member who made the key, and every change shows in the record’s history.
Introduction
The Crossing Edge API reads and changes everything in a workspace from your own systems: contacts, companies, deals and any object you added, tasks and calls, email, Telegram, webhooks, reports and settings.
It is a JSON API over HTTPS. Every operation runs with the access of the member who made the key, through the same checks as the app: automations run, duplicates are caught, and every change shows in the record’s history, marked via the API.
https://api.crossingedge.com/v1There are two ways to call it. REST routes cover the records most integrations need. Actions (POST /actions/{name}) reach every other operation, the same set the Crossing Edge MCP server offers. Both share keys, limits and errors.
curl https://api.crossingedge.com/v1/me \
-H "Authorization: Bearer $CROSSING_EDGE_KEY"const res = await fetch("https://api.crossingedge.com/v1/me", {
headers: { Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}` },
});
console.log(await res.json());import os, requests
res = requests.get("https://api.crossingedge.com/v1/me",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}"})
print(res.json())Authentication
Send a workspace API key as a bearer token on every request:
Authorization: Bearer ce_live_…
Make keys in Crossing Edge under Settings › Integrations › API. Each key is shown once: store it in a secret manager or an environment variable. Crossing Edge keeps only a hash.
- Read only keys run reading operations. Anything that changes data answers
403 insufficient_scope. - Read and write keys run everything their maker can do, and nothing more.
- A key can expire after 30, 90 or 365 days, and can be revoked at any time.
- A key stops working if the member who made it leaves the workspace or loses the “Make API keys” access.
Requests and responses
Send bodies as JSON with Content-Type: application/json, up to 1 MB. Unknown fields are refused rather than ignored, so a typo never silently does nothing.
Every success answers { "data": …, "request_id": "req_…" }, with 201 for a created record. Every response carries an X-Request-Id header; quote it when asking for help.
Records take field values by key or label. Call GET /schema for every object, field and the choices a field allows. Owners are given as a member’s email.
Lists answer up to limit records (at most 100) with the total that match. Narrow them with query, owner or a status; for every record of an object at once, use the export_records action.
Errors
Errors use HTTP status codes and one shape:
{
"error": {
"type": "invalid_request",
"code": "invalid_parameter",
"message": "firstName is required",
"field": "firstName",
"request_id": "req_7c1f0e2a9b4d"
}
}
| Status | Type | Means |
|---|---|---|
| 400 | invalid_request | A missing or wrong field, or bad JSON. field names it. |
| 401 | authentication_error | No key, or one that is unknown, revoked or expired. |
| 403 | permission_error | The key may not do this: read only, its maker lacks the access, or it is suspended. |
| 404 | not_found | The record or the operation is not there. |
| 409 | conflict | It clashes with what exists, like a duplicate email. |
| 422 | invalid_request | An Idempotency-Key reused for a different request. |
| 429 | rate_limited | Over a limit. Wait Retry-After seconds. |
| 5xx | server_error | Our side failed. Retry with backoff. |
Rate limits
Each key may make 120 requests a minute and 25,000 a day (UTC). Every response says where you stand:
| Header | Value |
|---|---|
X-RateLimit-Limit | Requests a minute |
X-RateLimit-Remaining | Left this minute |
X-RateLimit-Reset | Seconds until the minute resets |
X-Daily-Limit | Requests a day |
X-Daily-Remaining | Left today |
Retry-After | On a 429: seconds to wait |
On a 429, wait for Retry-After, then retry. For other failures, retry with exponential backoff and jitter, and only writes that carry an Idempotency-Key.
Idempotency
Networks fail mid-request. Send an Idempotency-Key header (any unique string, like a UUID) with every write, and retry with the same key: for 24 hours, a retry returns the first answer, marked Idempotent-Replayed: true, instead of creating a second record.
Reusing a key for a different request answers 422 idempotency_conflict.
Versioning and changes
The version is in the path: /v1. Within v1 we only add: new operations, new optional fields, new fields in answers. Write clients that ignore fields they do not know. Anything that would break a client comes as a new version, announced ahead.
The full description is OpenAPI 3.1: import it into Postman or Insomnia, or generate a client from it.
MCP
Connecting an AI assistant, IDE or agent rather than writing code? The same operations are an MCP server at https://app.crossingedge.com/mcp. It signs in through the browser or takes a key in a header. See Settings › Integrations › MCP.
Security
- HTTPS only, with HSTS. Keys are stored as SHA-256 hashes and shown once.
- Use a read-only key wherever writing is not needed, and one key per system, so one can be revoked alone.
- Every request is logged for 30 days (method, path, status, time; never bodies) and visible to the workspace in Settings › Integrations › API.
- Revoke a key that may have leaked straight away, then make a new one.
Getting started
Check a key.
/meThe key in use
Which key this is, its scope, the workspace it works in, and the member it acts as. A cheap way to check a key works.
curl -X GET "https://api.crossingedge.com/v1/me" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY"const res = await fetch("https://api.crossingedge.com/v1/me", {
method: "GET",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
},
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.get(
"https://api.crossingedge.com/v1/me",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}"},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}Contacts
REST routes for contacts.
/contactsList or search contacts
Finds contacts by name, email, phone, job title or company, optionally narrowed by status or owner. Returns compact rows with ids; use get_contact for everything about one.
Query parameters
querystringWords to match in the name, email, phone, job title or company names
statusstringOnly this lifecycle status
ownerstringOnly contacts this member owns, by email or name
companyIdnumberOnly contacts at this company
limitnumberHow many to return, default 20, at most 100
curl -X GET "https://api.crossingedge.com/v1/contacts" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY"const res = await fetch("https://api.crossingedge.com/v1/contacts", {
method: "GET",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
},
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.get(
"https://api.crossingedge.com/v1/contacts",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}"},
)
data = res.json()["data"]{
"data": {
"total": 1,
"…": [
{
"id": 101,
"…": "…"
}
]
},
"request_id": "req_7c1f0e2a9b4d"
}/contactsCreate a contact
Adds a contact. Needs a first name and an email or phone. Runs the workspace’s automations and duplicate check like a contact made in the app.
Body
firstNamestringrequiredFirst name
lastNamestringLast name
emailstringEmail. A contact needs an email or a phone
phonestringPhone, with country code
jobTitlestringJob title
statusstringLifecycle status, one of the choices get_schema lists for contacts.status
sourcestringWhere they came from, one of the choices get_schema lists for contacts.source
linkedinstringLinkedIn profile URL
telegramstringTelegram username, like @priya
countrystringCountry they are based in, by name or two-letter code (India, IN)
statestringTheir state, province or region
citystringTheir city
ownerstringOwner, by member email or name
companyIdsarray of numberCompanies they work with, by id (replaces the current set)
companyNamestringA company to link by exact name; made if the workspace has none by that name
customobjectCustom field values by field key (keys from get_schema)
curl -X POST "https://api.crossingedge.com/v1/contacts" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"firstName": "Priya"
}'const res = await fetch("https://api.crossingedge.com/v1/contacts", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
"firstName": "Priya"
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/contacts",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}", "Idempotency-Key": str(uuid.uuid4())},
json={
"firstName": "Priya"
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/contacts/{id}Get a contact
Everything about one contact: their fields, companies, owner, and their latest activities and open tasks.
Path parameters
idstringrequiredThe record id
curl -X GET "https://api.crossingedge.com/v1/contacts/101" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY"const res = await fetch("https://api.crossingedge.com/v1/contacts/101", {
method: "GET",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
},
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.get(
"https://api.crossingedge.com/v1/contacts/101",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}"},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/contacts/{id}Update a contact
Changes a contact. Only the fields passed change; companyName adds a company link, companyIds replaces the set.
Path parameters
idstringrequiredThe record id
Body
firstNamestringFirst name
lastNamestringLast name
emailstringEmail. A contact needs an email or a phone
phonestringPhone, with country code
jobTitlestringJob title
statusstringLifecycle status, one of the choices get_schema lists for contacts.status
sourcestringWhere they came from, one of the choices get_schema lists for contacts.source
linkedinstringLinkedIn profile URL
telegramstringTelegram username, like @priya
countrystringCountry they are based in, by name or two-letter code (India, IN)
statestringTheir state, province or region
citystringTheir city
ownerstringOwner, by member email or name
companyIdsarray of numberCompanies they work with, by id (replaces the current set)
companyNamestringA company to link by exact name; made if the workspace has none by that name
customobjectCustom field values by field key (keys from get_schema)
curl -X PATCH "https://api.crossingedge.com/v1/contacts/101" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"firstName": "Priya",
"lastName": "Nair"
}'const res = await fetch("https://api.crossingedge.com/v1/contacts/101", {
method: "PATCH",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
"firstName": "Priya",
"lastName": "Nair"
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.patch(
"https://api.crossingedge.com/v1/contacts/101",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}", "Idempotency-Key": str(uuid.uuid4())},
json={
"firstName": "Priya",
"lastName": "Nair"
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/contacts/{id}Delete a contact
Deletes a contact for good, with their notes and history. Ask the person first, then call with confirm: true. Deleting is permanent.
Path parameters
idstringrequiredThe record id
curl -X DELETE "https://api.crossingedge.com/v1/contacts/101" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY"const res = await fetch("https://api.crossingedge.com/v1/contacts/101", {
method: "DELETE",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
},
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.delete(
"https://api.crossingedge.com/v1/contacts/101",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}"},
)
data = res.json()["data"]{
"data": {
"deleted": true
},
"request_id": "req_7c1f0e2a9b4d"
}Companies
REST routes for companies.
/companiesList or search companies
Finds records of any object (companies, deals, contacts or a workspace object) by words in their name and fields, optionally narrowed by owner. Compact rows with ids; get_record has everything about one.
Query parameters
querystringWords to match
ownerstringOnly records this member owns, by email or name
limitnumberHow many, default 20, at most 100
curl -X GET "https://api.crossingedge.com/v1/companies" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY"const res = await fetch("https://api.crossingedge.com/v1/companies", {
method: "GET",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
},
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.get(
"https://api.crossingedge.com/v1/companies",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}"},
)
data = res.json()["data"]{
"data": {
"total": 1,
"…": [
{
"id": 101,
"…": "…"
}
]
},
"request_id": "req_7c1f0e2a9b4d"
}/companiesCreate a company
Adds a record of any object: a company, a deal (lands in the default pipeline unless pipeline or stage is given), a contact, or a workspace object. Runs automations and duplicate checks like the app.
Body
Field values by key or label: name, domain, amount, owner (member email), and custom fields by their label. /schema lists every field and its choices.
curl -X POST "https://api.crossingedge.com/v1/companies" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"name": "Acme",
"domain": "acme.com"
}'const res = await fetch("https://api.crossingedge.com/v1/companies", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
"name": "Acme",
"domain": "acme.com"
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/companies",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}", "Idempotency-Key": str(uuid.uuid4())},
json={
"name": "Acme",
"domain": "acme.com"
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/companies/{id}Get a company
Everything about one record of any object: its fields, what it is linked to (companies, people, deals, parents and subsidiaries, workspace relationships), and its latest activity and notes.
Path parameters
idstringrequiredThe record id
curl -X GET "https://api.crossingedge.com/v1/companies/101" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY"const res = await fetch("https://api.crossingedge.com/v1/companies/101", {
method: "GET",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
},
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.get(
"https://api.crossingedge.com/v1/companies/101",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}"},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/companies/{id}Update a company
Changes a record of any object. Only the fields passed change; a deal moves stage by passing stage (and pipeline if it is in several). companyIds and contactIds replace the set; link_records adds or removes one.
Path parameters
idstringrequiredThe record id
Body
Field values by key or label: name, domain, amount, owner (member email), and custom fields by their label. /schema lists every field and its choices.
curl -X PATCH "https://api.crossingedge.com/v1/companies/101" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"name": "Acme",
"domain": "acme.com"
}'const res = await fetch("https://api.crossingedge.com/v1/companies/101", {
method: "PATCH",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
"name": "Acme",
"domain": "acme.com"
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.patch(
"https://api.crossingedge.com/v1/companies/101",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}", "Idempotency-Key": str(uuid.uuid4())},
json={
"name": "Acme",
"domain": "acme.com"
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/companies/{id}Delete a company
Deletes a record of any object for good, with its notes and history. Ask the person first, then call with confirm: true. Deleting is permanent.
Path parameters
idstringrequiredThe record id
curl -X DELETE "https://api.crossingedge.com/v1/companies/101" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY"const res = await fetch("https://api.crossingedge.com/v1/companies/101", {
method: "DELETE",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
},
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.delete(
"https://api.crossingedge.com/v1/companies/101",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}"},
)
data = res.json()["data"]{
"data": {
"deleted": true
},
"request_id": "req_7c1f0e2a9b4d"
}Deals
REST routes for deals.
/dealsList or search deals
Finds records of any object (companies, deals, contacts or a workspace object) by words in their name and fields, optionally narrowed by owner. Compact rows with ids; get_record has everything about one.
Query parameters
querystringWords to match
ownerstringOnly records this member owns, by email or name
limitnumberHow many, default 20, at most 100
curl -X GET "https://api.crossingedge.com/v1/deals" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY"const res = await fetch("https://api.crossingedge.com/v1/deals", {
method: "GET",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
},
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.get(
"https://api.crossingedge.com/v1/deals",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}"},
)
data = res.json()["data"]{
"data": {
"total": 1,
"…": [
{
"id": 101,
"…": "…"
}
]
},
"request_id": "req_7c1f0e2a9b4d"
}/dealsCreate a deal
Adds a record of any object: a company, a deal (lands in the default pipeline unless pipeline or stage is given), a contact, or a workspace object. Runs automations and duplicate checks like the app.
Body
Field values by key or label: name, domain, amount, owner (member email), and custom fields by their label. /schema lists every field and its choices.
curl -X POST "https://api.crossingedge.com/v1/deals" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"name": "Acme renewal",
"amount": 12000,
"stage": "Proposal"
}'const res = await fetch("https://api.crossingedge.com/v1/deals", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
"name": "Acme renewal",
"amount": 12000,
"stage": "Proposal"
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/deals",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}", "Idempotency-Key": str(uuid.uuid4())},
json={
"name": "Acme renewal",
"amount": 12000,
"stage": "Proposal"
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/deals/{id}Get a deal
Everything about one record of any object: its fields, what it is linked to (companies, people, deals, parents and subsidiaries, workspace relationships), and its latest activity and notes.
Path parameters
idstringrequiredThe record id
curl -X GET "https://api.crossingedge.com/v1/deals/101" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY"const res = await fetch("https://api.crossingedge.com/v1/deals/101", {
method: "GET",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
},
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.get(
"https://api.crossingedge.com/v1/deals/101",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}"},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/deals/{id}Update a deal
Changes a record of any object. Only the fields passed change; a deal moves stage by passing stage (and pipeline if it is in several). companyIds and contactIds replace the set; link_records adds or removes one.
Path parameters
idstringrequiredThe record id
Body
Field values by key or label: name, domain, amount, owner (member email), and custom fields by their label. /schema lists every field and its choices.
curl -X PATCH "https://api.crossingedge.com/v1/deals/101" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"name": "Acme renewal",
"amount": 12000,
"stage": "Proposal"
}'const res = await fetch("https://api.crossingedge.com/v1/deals/101", {
method: "PATCH",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
"name": "Acme renewal",
"amount": 12000,
"stage": "Proposal"
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.patch(
"https://api.crossingedge.com/v1/deals/101",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}", "Idempotency-Key": str(uuid.uuid4())},
json={
"name": "Acme renewal",
"amount": 12000,
"stage": "Proposal"
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/deals/{id}Delete a deal
Deletes a record of any object for good, with its notes and history. Ask the person first, then call with confirm: true. Deleting is permanent.
Path parameters
idstringrequiredThe record id
curl -X DELETE "https://api.crossingedge.com/v1/deals/101" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY"const res = await fetch("https://api.crossingedge.com/v1/deals/101", {
method: "DELETE",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
},
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.delete(
"https://api.crossingedge.com/v1/deals/101",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}"},
)
data = res.json()["data"]{
"data": {
"deleted": true
},
"request_id": "req_7c1f0e2a9b4d"
}Any object
REST routes for any object.
/objects/{object}/recordsList or search records of any object
Finds records of any object (companies, deals, contacts or a workspace object) by words in their name and fields, optionally narrowed by owner. Compact rows with ids; get_record has everything about one.
Path parameters
objectstringrequiredThe object: companies, deals, contacts, or a workspace object’s id (obj_…, from /schema)
Query parameters
querystringWords to match
ownerstringOnly records this member owns, by email or name
limitnumberHow many, default 20, at most 100
curl -X GET "https://api.crossingedge.com/v1/objects/deals/records" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY"const res = await fetch("https://api.crossingedge.com/v1/objects/deals/records", {
method: "GET",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
},
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.get(
"https://api.crossingedge.com/v1/objects/deals/records",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}"},
)
data = res.json()["data"]{
"data": {
"total": 1,
"…": [
{
"id": 101,
"…": "…"
}
]
},
"request_id": "req_7c1f0e2a9b4d"
}/objects/{object}/recordsCreate a record
Adds a record of any object: a company, a deal (lands in the default pipeline unless pipeline or stage is given), a contact, or a workspace object. Runs automations and duplicate checks like the app.
Path parameters
objectstringrequiredThe object: companies, deals, contacts, or a workspace object’s id (obj_…, from /schema)
Body
Field values by key or label: name, domain, amount, owner (member email), and custom fields by their label. /schema lists every field and its choices.
curl -X POST "https://api.crossingedge.com/v1/objects/deals/records" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"name": "Example"
}'const res = await fetch("https://api.crossingedge.com/v1/objects/deals/records", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
"name": "Example"
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/objects/deals/records",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}", "Idempotency-Key": str(uuid.uuid4())},
json={
"name": "Example"
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/objects/{object}/records/{id}Get a record
Everything about one record of any object: its fields, what it is linked to (companies, people, deals, parents and subsidiaries, workspace relationships), and its latest activity and notes.
Path parameters
objectstringrequiredThe object: companies, deals, contacts, or a workspace object’s id (obj_…, from /schema)
idstringrequiredThe record id
curl -X GET "https://api.crossingedge.com/v1/objects/deals/records/101" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY"const res = await fetch("https://api.crossingedge.com/v1/objects/deals/records/101", {
method: "GET",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
},
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.get(
"https://api.crossingedge.com/v1/objects/deals/records/101",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}"},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/objects/{object}/records/{id}Update a record
Changes a record of any object. Only the fields passed change; a deal moves stage by passing stage (and pipeline if it is in several). companyIds and contactIds replace the set; link_records adds or removes one.
Path parameters
objectstringrequiredThe object: companies, deals, contacts, or a workspace object’s id (obj_…, from /schema)
idstringrequiredThe record id
Body
Field values by key or label: name, domain, amount, owner (member email), and custom fields by their label. /schema lists every field and its choices.
curl -X PATCH "https://api.crossingedge.com/v1/objects/deals/records/101" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"name": "Example"
}'const res = await fetch("https://api.crossingedge.com/v1/objects/deals/records/101", {
method: "PATCH",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
"name": "Example"
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.patch(
"https://api.crossingedge.com/v1/objects/deals/records/101",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}", "Idempotency-Key": str(uuid.uuid4())},
json={
"name": "Example"
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/objects/{object}/records/{id}Delete a record
Deletes a record of any object for good, with its notes and history. Ask the person first, then call with confirm: true. Deleting is permanent.
Path parameters
objectstringrequiredThe object: companies, deals, contacts, or a workspace object’s id (obj_…, from /schema)
idstringrequiredThe record id
curl -X DELETE "https://api.crossingedge.com/v1/objects/deals/records/101" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY"const res = await fetch("https://api.crossingedge.com/v1/objects/deals/records/101", {
method: "DELETE",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
},
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.delete(
"https://api.crossingedge.com/v1/objects/deals/records/101",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}"},
)
data = res.json()["data"]{
"data": {
"deleted": true
},
"request_id": "req_7c1f0e2a9b4d"
}Tasks
REST routes for tasks.
/tasksList tasks and activities
Tasks, open ones by default: yours, everyone’s you can see, or those on one record. Also lists other activity types with type.
Query parameters
scopestringTasks you created or are on (default), or all you can see
statusstringDefault open
typestringDefault task
overduebooleanOnly those past due
dueBeforestringOnly those due before this ISO date
contactIdnumberThe contact it is about
companyIdnumberThe company it is about
dealIdnumberThe deal it is about
limitnumberDefault 25, at most 100
curl -X GET "https://api.crossingedge.com/v1/tasks" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY"const res = await fetch("https://api.crossingedge.com/v1/tasks", {
method: "GET",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
},
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.get(
"https://api.crossingedge.com/v1/tasks",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}"},
)
data = res.json()["data"]{
"data": {
"total": 1,
"…": [
{
"id": 101,
"…": "…"
}
]
},
"request_id": "req_7c1f0e2a9b4d"
}/tasksCreate a task
Plans a task: what, when it is due, how urgent, who owns it (you by default), and the records it is about. Pass parentTaskId to make it a sub-task.
Body
subjectstringrequiredWhat needs doing
duestringrequiredDue date and time, ISO 8601, e.g. 2026-10-01T17:00:00+05:30
prioritystringDefault Medium
One of Low Medium High
assigneestringWho owns it, by member email or name. Default: you
bodystringDetails
parentTaskIdstringMake it a sub-task inside this task; it then takes that task’s records
notifyarray of stringPeople to keep informed, by member email or name
contactIdnumberThe contact it is about
companyIdnumberThe company it is about
dealIdnumberThe deal it is about
recordsarray of objectOther records it is about, as { object, id } (custom objects too)
curl -X POST "https://api.crossingedge.com/v1/tasks" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"subject": "Call Priya about the renewal",
"due": "2026-11-02T10:00:00Z"
}'const res = await fetch("https://api.crossingedge.com/v1/tasks", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
"subject": "Call Priya about the renewal",
"due": "2026-11-02T10:00:00Z"
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/tasks",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}", "Idempotency-Key": str(uuid.uuid4())},
json={
"subject": "Call Priya about the renewal",
"due": "2026-11-02T10:00:00Z"
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/tasks/{id}Get a task
One task (or any activity) with everything logged inside it: its calls, meetings, emails, messages, notes and sub-tasks.
Path parameters
idstringrequiredThe record id
curl -X GET "https://api.crossingedge.com/v1/tasks/101" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY"const res = await fetch("https://api.crossingedge.com/v1/tasks/101", {
method: "GET",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
},
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.get(
"https://api.crossingedge.com/v1/tasks/101",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}"},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/tasks/{id}Update a task
Changes a task or activity. Only what is passed changes. status: planned | in_progress | done | cancelled.
Path parameters
idstringrequiredThe record id
Body
subjectstringNew subject
bodystringNew details
duestringNew due date, ISO 8601 (tasks), or when it happened (other types)
prioritystringOne of Low Medium High
statusstringOne of planned in_progress done cancelled
assigneestringNew owner, by member email or name
notifyarray of stringThe full new list of people to keep informed, by email or name
detailsobjectType fields to change
moveIntoTaskstringMove it inside this task; it then takes that task’s records
moveOutOfTaskbooleanTake it out of the task it is in, keeping its records
contactIdnumberThe contact it is about. Passing any record replaces what it is linked to
companyIdnumberThe company it is about. Passing any record replaces what it is linked to
dealIdnumberThe deal it is about. Passing any record replaces what it is linked to
recordsarray of objectOther records it is about, as { object, id } (custom objects too). Passing any record replaces what it is linked to
curl -X PATCH "https://api.crossingedge.com/v1/tasks/101" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"subject": "Call Priya about the renewal",
"body": "…"
}'const res = await fetch("https://api.crossingedge.com/v1/tasks/101", {
method: "PATCH",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
"subject": "Call Priya about the renewal",
"body": "…"
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.patch(
"https://api.crossingedge.com/v1/tasks/101",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}", "Idempotency-Key": str(uuid.uuid4())},
json={
"subject": "Call Priya about the renewal",
"body": "…"
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/tasks/{id}Delete a task
Deletes a task or activity for good; a task takes everything logged inside it. Ask the person first, then call with confirm: true. Deleting is permanent.
Path parameters
idstringrequiredThe record id
curl -X DELETE "https://api.crossingedge.com/v1/tasks/101" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY"const res = await fetch("https://api.crossingedge.com/v1/tasks/101", {
method: "DELETE",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
},
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.delete(
"https://api.crossingedge.com/v1/tasks/101",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}"},
)
data = res.json()["data"]{
"data": {
"deleted": true
},
"request_id": "req_7c1f0e2a9b4d"
}/tasks/{id}/completeComplete a task
Marks a task done.
Path parameters
idstringrequiredThe record id
curl -X POST "https://api.crossingedge.com/v1/tasks/101/complete" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{}'const res = await fetch("https://api.crossingedge.com/v1/tasks/101/complete", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/tasks/101/complete",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}", "Idempotency-Key": str(uuid.uuid4())},
json={},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}Schema
REST routes for schema.
/schemaGet the workspace schema: objects, fields and their choices
The workspace data model: every object and field (with types and choices), pipelines and stages, members, currency and today’s date.
curl -X GET "https://api.crossingedge.com/v1/schema" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY"const res = await fetch("https://api.crossingedge.com/v1/schema", {
method: "GET",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
},
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.get(
"https://api.crossingedge.com/v1/schema",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}"},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}Contacts and tasks
ActionsContacts, tasks, calls, meetings and notes.
/actions/search_contactsSearch contacts
Finds contacts by name, email, phone, job title or company, optionally narrowed by status or owner. Returns compact rows with ids; use get_contact for everything about one.
Body
querystringWords to match in the name, email, phone, job title or company names
statusstringOnly this lifecycle status
ownerstringOnly contacts this member owns, by email or name
companyIdnumberOnly contacts at this company
limitnumberHow many to return, default 20, at most 100
curl -X POST "https://api.crossingedge.com/v1/actions/search_contacts" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-d '{
"query": "acme",
"status": "…"
}'const res = await fetch("https://api.crossingedge.com/v1/actions/search_contacts", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"query": "acme",
"status": "…"
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/search_contacts",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}"},
json={
"query": "acme",
"status": "…"
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/actions/get_contactGet contact
Everything about one contact: their fields, companies, owner, and their latest activities and open tasks.
Body
idnumberrequiredContact id
curl -X POST "https://api.crossingedge.com/v1/actions/get_contact" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-d '{
"id": 101
}'const res = await fetch("https://api.crossingedge.com/v1/actions/get_contact", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"id": 101
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/get_contact",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}"},
json={
"id": 101
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/actions/create_contactCreate contact
Adds a contact. Needs a first name and an email or phone. Runs the workspace’s automations and duplicate check like a contact made in the app.
Body
firstNamestringrequiredFirst name
lastNamestringLast name
emailstringEmail. A contact needs an email or a phone
phonestringPhone, with country code
jobTitlestringJob title
statusstringLifecycle status, one of the choices get_schema lists for contacts.status
sourcestringWhere they came from, one of the choices get_schema lists for contacts.source
linkedinstringLinkedIn profile URL
telegramstringTelegram username, like @priya
countrystringCountry they are based in, by name or two-letter code (India, IN)
statestringTheir state, province or region
citystringTheir city
ownerstringOwner, by member email or name
companyIdsarray of numberCompanies they work with, by id (replaces the current set)
companyNamestringA company to link by exact name; made if the workspace has none by that name
customobjectCustom field values by field key (keys from get_schema)
curl -X POST "https://api.crossingedge.com/v1/actions/create_contact" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"firstName": "Priya"
}'const res = await fetch("https://api.crossingedge.com/v1/actions/create_contact", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
"firstName": "Priya"
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/create_contact",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}", "Idempotency-Key": str(uuid.uuid4())},
json={
"firstName": "Priya"
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/actions/update_contactUpdate contact
Changes a contact. Only the fields passed change; companyName adds a company link, companyIds replaces the set.
Body
idnumberrequiredContact id
firstNamestringFirst name
lastNamestringLast name
emailstringEmail. A contact needs an email or a phone
phonestringPhone, with country code
jobTitlestringJob title
statusstringLifecycle status, one of the choices get_schema lists for contacts.status
sourcestringWhere they came from, one of the choices get_schema lists for contacts.source
linkedinstringLinkedIn profile URL
telegramstringTelegram username, like @priya
countrystringCountry they are based in, by name or two-letter code (India, IN)
statestringTheir state, province or region
citystringTheir city
ownerstringOwner, by member email or name
companyIdsarray of numberCompanies they work with, by id (replaces the current set)
companyNamestringA company to link by exact name; made if the workspace has none by that name
customobjectCustom field values by field key (keys from get_schema)
curl -X POST "https://api.crossingedge.com/v1/actions/update_contact" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"id": 101
}'const res = await fetch("https://api.crossingedge.com/v1/actions/update_contact", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
"id": 101
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/update_contact",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}", "Idempotency-Key": str(uuid.uuid4())},
json={
"id": 101
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/actions/delete_contactDelete contact
Deletes a contact for good, with their notes and history. Ask the person first, then call with confirm: true.
Body
idnumberrequiredContact id
confirmbooleanrequiredTrue once the person has confirmed the delete
curl -X POST "https://api.crossingedge.com/v1/actions/delete_contact" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"id": 101,
"confirm": true
}'const res = await fetch("https://api.crossingedge.com/v1/actions/delete_contact", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
"id": 101,
"confirm": true
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/delete_contact",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}", "Idempotency-Key": str(uuid.uuid4())},
json={
"id": 101,
"confirm": True
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/actions/list_tasksList tasks
Tasks, open ones by default: yours, everyone’s you can see, or those on one record. Also lists other activity types with type.
Body
scopestringTasks you created or are on (default), or all you can see
One of mine all
statusstringDefault open
One of open done all
typestringDefault task
One of task call meeting email message note any
overduebooleanOnly those past due
dueBeforestringOnly those due before this ISO date
contactIdnumberThe contact it is about
companyIdnumberThe company it is about
dealIdnumberThe deal it is about
recordsarray of objectOther records it is about, as { object, id } (custom objects too)
limitnumberDefault 25, at most 100
curl -X POST "https://api.crossingedge.com/v1/actions/list_tasks" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-d '{
"scope": "mine",
"status": "open"
}'const res = await fetch("https://api.crossingedge.com/v1/actions/list_tasks", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"scope": "mine",
"status": "open"
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/list_tasks",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}"},
json={
"scope": "mine",
"status": "open"
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/actions/get_taskGet task
One task (or any activity) with everything logged inside it: its calls, meetings, emails, messages, notes and sub-tasks.
Body
idstringrequiredTask id, like act_…
curl -X POST "https://api.crossingedge.com/v1/actions/get_task" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-d '{
"id": "101"
}'const res = await fetch("https://api.crossingedge.com/v1/actions/get_task", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"id": "101"
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/get_task",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}"},
json={
"id": "101"
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/actions/create_taskCreate task
Plans a task: what, when it is due, how urgent, who owns it (you by default), and the records it is about. Pass parentTaskId to make it a sub-task.
Body
subjectstringrequiredWhat needs doing
duestringrequiredDue date and time, ISO 8601, e.g. 2026-10-01T17:00:00+05:30
prioritystringDefault Medium
One of Low Medium High
assigneestringWho owns it, by member email or name. Default: you
bodystringDetails
parentTaskIdstringMake it a sub-task inside this task; it then takes that task’s records
notifyarray of stringPeople to keep informed, by member email or name
contactIdnumberThe contact it is about
companyIdnumberThe company it is about
dealIdnumberThe deal it is about
recordsarray of objectOther records it is about, as { object, id } (custom objects too)
curl -X POST "https://api.crossingedge.com/v1/actions/create_task" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"subject": "Call Priya about the renewal",
"due": "2026-11-02T10:00:00Z"
}'const res = await fetch("https://api.crossingedge.com/v1/actions/create_task", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
"subject": "Call Priya about the renewal",
"due": "2026-11-02T10:00:00Z"
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/create_task",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}", "Idempotency-Key": str(uuid.uuid4())},
json={
"subject": "Call Priya about the renewal",
"due": "2026-11-02T10:00:00Z"
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/actions/log_activityLog activity
Logs a call, meeting, email, message or note on records, or inside a task (taskId). Fields by type: call: direction (Incoming | Outgoing), outcome (Connected | No answer | Left voicemail | Wrong number | Busy); meeting: locationOrLink, agenda, outcome; email: direction (Incoming | Outgoing), subject; message: channel (SMS | WhatsApp | LinkedIn | Telegram), direction (Incoming | Outgoing); note: none. Required choices left out are filled with sensible defaults (calls and emails: Outgoing).
Body
typestringrequiredOne of call meeting email message note
subjectstringShort title
bodystringWhat happened; required for a note
atstringWhen, ISO 8601. Default now. A future time plans a meeting, call, email or message
durationMinutesnumberHow long, for calls and meetings
detailsobjectThis type’s own fields (see the description)
taskIdstringLog it inside this task; it then takes the task’s records
notifyarray of stringPeople to keep informed, by member email or name
privatebooleanNotes on a record only: visible to you alone
contactIdnumberThe contact it is about
companyIdnumberThe company it is about
dealIdnumberThe deal it is about
recordsarray of objectOther records it is about, as { object, id } (custom objects too)
curl -X POST "https://api.crossingedge.com/v1/actions/log_activity" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"type": "call"
}'const res = await fetch("https://api.crossingedge.com/v1/actions/log_activity", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
"type": "call"
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/log_activity",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}", "Idempotency-Key": str(uuid.uuid4())},
json={
"type": "call"
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/actions/update_taskUpdate task
Changes a task or activity. Only what is passed changes. status: planned | in_progress | done | cancelled.
Body
idstringrequiredTask or activity id
subjectstringNew subject
bodystringNew details
duestringNew due date, ISO 8601 (tasks), or when it happened (other types)
prioritystringOne of Low Medium High
statusstringOne of planned in_progress done cancelled
assigneestringNew owner, by member email or name
notifyarray of stringThe full new list of people to keep informed, by email or name
detailsobjectType fields to change
moveIntoTaskstringMove it inside this task; it then takes that task’s records
moveOutOfTaskbooleanTake it out of the task it is in, keeping its records
contactIdnumberThe contact it is about. Passing any record replaces what it is linked to
companyIdnumberThe company it is about. Passing any record replaces what it is linked to
dealIdnumberThe deal it is about. Passing any record replaces what it is linked to
recordsarray of objectOther records it is about, as { object, id } (custom objects too). Passing any record replaces what it is linked to
curl -X POST "https://api.crossingedge.com/v1/actions/update_task" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"id": "101"
}'const res = await fetch("https://api.crossingedge.com/v1/actions/update_task", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
"id": "101"
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/update_task",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}", "Idempotency-Key": str(uuid.uuid4())},
json={
"id": "101"
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/actions/update_noteUpdate note
Changes a note on a record (ids like note_…, from get_contact). Only its author can.
Body
idstringrequiredNote id
bodystringThe new text
privatebooleanVisible to you alone
curl -X POST "https://api.crossingedge.com/v1/actions/update_note" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"id": "101"
}'const res = await fetch("https://api.crossingedge.com/v1/actions/update_note", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
"id": "101"
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/update_note",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}", "Idempotency-Key": str(uuid.uuid4())},
json={
"id": "101"
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/actions/delete_noteDelete note
Deletes a note on a record for good. Ask the person first, then call with confirm: true.
Body
idstringrequiredNote id
confirmbooleanrequiredTrue once the person has confirmed the delete
curl -X POST "https://api.crossingedge.com/v1/actions/delete_note" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"id": "101",
"confirm": true
}'const res = await fetch("https://api.crossingedge.com/v1/actions/delete_note", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
"id": "101",
"confirm": true
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/delete_note",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}", "Idempotency-Key": str(uuid.uuid4())},
json={
"id": "101",
"confirm": True
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/actions/complete_taskComplete task
Marks a task done.
Body
idstringrequiredTask id
curl -X POST "https://api.crossingedge.com/v1/actions/complete_task" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"id": "101"
}'const res = await fetch("https://api.crossingedge.com/v1/actions/complete_task", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
"id": "101"
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/complete_task",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}", "Idempotency-Key": str(uuid.uuid4())},
json={
"id": "101"
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/actions/delete_taskDelete task
Deletes a task or activity for good; a task takes everything logged inside it. Ask the person first, then call with confirm: true.
Body
idstringrequiredTask or activity id
confirmbooleanrequiredTrue once the person has confirmed the delete
curl -X POST "https://api.crossingedge.com/v1/actions/delete_task" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"id": "101",
"confirm": true
}'const res = await fetch("https://api.crossingedge.com/v1/actions/delete_task", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
"id": "101",
"confirm": true
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/delete_task",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}", "Idempotency-Key": str(uuid.uuid4())},
json={
"id": "101",
"confirm": True
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}Records
ActionsAny record: companies, deals, contacts and the objects a workspace adds itself. Links between them, and deal splits.
/actions/search_recordsSearch records
Finds records of any object (companies, deals, contacts or a workspace object) by words in their name and fields, optionally narrowed by owner. Compact rows with ids; get_record has everything about one.
Body
objectstringrequiredcontacts, companies, deals, or a workspace object by id, name or plural (get_schema lists them)
querystringWords to match
ownerstringOnly records this member owns, by email or name
limitnumberHow many, default 20, at most 100
curl -X POST "https://api.crossingedge.com/v1/actions/search_records" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-d '{
"object": "deals"
}'const res = await fetch("https://api.crossingedge.com/v1/actions/search_records", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"object": "deals"
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/search_records",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}"},
json={
"object": "deals"
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/actions/get_recordGet record
Everything about one record of any object: its fields, what it is linked to (companies, people, deals, parents and subsidiaries, workspace relationships), and its latest activity and notes.
Body
objectstringrequiredcontacts, companies, deals, or a workspace object by id, name or plural (get_schema lists them)
idnumberrequiredRecord id
curl -X POST "https://api.crossingedge.com/v1/actions/get_record" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-d '{
"object": "deals",
"id": 101
}'const res = await fetch("https://api.crossingedge.com/v1/actions/get_record", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"object": "deals",
"id": 101
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/get_record",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}"},
json={
"object": "deals",
"id": 101
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/actions/create_recordCreate record
Adds a record of any object: a company, a deal (lands in the default pipeline unless pipeline or stage is given), a contact, or a workspace object. Runs automations and duplicate checks like the app.
Body
objectstringrequiredcontacts, companies, deals, or a workspace object by id, name or plural (get_schema lists them)
fieldsobjectrequiredField values. Companies: name, domain, industry, companySize, country, state, city, phone, linkedin, icp. Deals: name, amount, closeDate (YYYY-MM-DD), source, nextStep, lostReason, pipeline and stage (by name), companyIds, contactIds. Contacts: firstName, lastName, email, phone, jobTitle, status, source, linkedin, telegram, country, state, city, companyIds. Any object: owner (member email or name) and custom: { field label or id: value }. On a workspace object, pass its fields by label directly.
curl -X POST "https://api.crossingedge.com/v1/actions/create_record" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"object": "deals",
"fields": {}
}'const res = await fetch("https://api.crossingedge.com/v1/actions/create_record", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
"object": "deals",
"fields": {}
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/create_record",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}", "Idempotency-Key": str(uuid.uuid4())},
json={
"object": "deals",
"fields": {}
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/actions/update_recordUpdate record
Changes a record of any object. Only the fields passed change; a deal moves stage by passing stage (and pipeline if it is in several). companyIds and contactIds replace the set; link_records adds or removes one.
Body
objectstringrequiredcontacts, companies, deals, or a workspace object by id, name or plural (get_schema lists them)
idnumberrequiredRecord id
fieldsobjectrequiredField values. Companies: name, domain, industry, companySize, country, state, city, phone, linkedin, icp. Deals: name, amount, closeDate (YYYY-MM-DD), source, nextStep, lostReason, pipeline and stage (by name), companyIds, contactIds. Contacts: firstName, lastName, email, phone, jobTitle, status, source, linkedin, telegram, country, state, city, companyIds. Any object: owner (member email or name) and custom: { field label or id: value }. On a workspace object, pass its fields by label directly.
curl -X POST "https://api.crossingedge.com/v1/actions/update_record" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"object": "deals",
"id": 101,
"fields": {}
}'const res = await fetch("https://api.crossingedge.com/v1/actions/update_record", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
"object": "deals",
"id": 101,
"fields": {}
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/update_record",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}", "Idempotency-Key": str(uuid.uuid4())},
json={
"object": "deals",
"id": 101,
"fields": {}
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/actions/set_deal_splitSet deal split
Shares credit on a deal between its owner and other members. members replaces the whole split: each member (email or name) with a whole-number percent; the owner is never listed and holds the rest (at least 1%). Pass an empty list to end the split. Only works while the deal’s pipeline has split credit on. Everyone on a split can see and edit the deal, and reports by owner credit each their share.
Body
dealnumberrequiredDeal id
membersarray of objectrequiredWho shares credit besides the owner
curl -X POST "https://api.crossingedge.com/v1/actions/set_deal_split" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"deal": 101,
"members": []
}'const res = await fetch("https://api.crossingedge.com/v1/actions/set_deal_split", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
"deal": 101,
"members": []
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/set_deal_split",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}", "Idempotency-Key": str(uuid.uuid4())},
json={
"deal": 101,
"members": []
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/actions/delete_recordDelete record
Deletes a record of any object for good, with its notes and history. Ask the person first, then call with confirm: true.
Body
objectstringrequiredcontacts, companies, deals, or a workspace object by id, name or plural (get_schema lists them)
idnumberrequiredRecord id
confirmbooleanrequiredTrue once the person has confirmed the delete
curl -X POST "https://api.crossingedge.com/v1/actions/delete_record" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"object": "deals",
"id": 101,
"confirm": true
}'const res = await fetch("https://api.crossingedge.com/v1/actions/delete_record", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
"object": "deals",
"id": 101,
"confirm": true
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/delete_record",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}", "Idempotency-Key": str(uuid.uuid4())},
json={
"object": "deals",
"id": 101,
"confirm": True
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/actions/link_recordsLink records
Links two records: a contact to a company, a contact or company to a deal (with an optional role), a parent company (from) to a subsidiary (to), or any two records a workspace relationship joins (pass relationship when several do).
Body
fromobjectrequiredtoobjectrequiredrolestringA contact’s or company’s role on a deal, e.g. Decision maker
relationshipstringWhich workspace relationship, by label or id, when several join the two
curl -X POST "https://api.crossingedge.com/v1/actions/link_records" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"from": {},
"to": {}
}'const res = await fetch("https://api.crossingedge.com/v1/actions/link_records", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
"from": {},
"to": {}
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/link_records",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}", "Idempotency-Key": str(uuid.uuid4())},
json={
"from": {},
"to": {}
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/actions/unlink_recordsUnlink records
Removes a link between two records (the records themselves stay). Same pairs as link_records.
Body
fromobjectrequiredtoobjectrequiredrelationshipstringWhich workspace relationship, by label or id, when several join the two
curl -X POST "https://api.crossingedge.com/v1/actions/unlink_records" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"from": {},
"to": {}
}'const res = await fetch("https://api.crossingedge.com/v1/actions/unlink_records", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
"from": {},
"to": {}
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/unlink_records",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}", "Idempotency-Key": str(uuid.uuid4())},
json={
"from": {},
"to": {}
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}Workspace settings
ActionsPipelines, objects, fields, relationships, automations, members and workspace settings. Owners and admins.
/actions/get_settingsGet settings
How the workspace is set up: pipelines and their stages, objects, custom fields per object, the choices of standard fields (contact status, source, buying roles, company ICP), relationships, workspace settings (currency, fiscal year, business hours, stage time targets, file limits: maxFileMb and storageMb), automations, members and AI. Pass section to read just one.
Body
sectionstringOne of pipelines objects fields choices relationships workspace automations members ai
curl -X POST "https://api.crossingedge.com/v1/actions/get_settings" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-d '{
"section": "pipelines"
}'const res = await fetch("https://api.crossingedge.com/v1/actions/get_settings", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"section": "pipelines"
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/get_settings",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}"},
json={
"section": "pipelines"
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/actions/create_pipelineCreate pipeline
Adds a deal pipeline with its stages. Needs at least one open stage; won and lost stages close a deal.
Body
namestringrequiredPipeline name
descriptionstringWhat it is for
stagesarray of objectrequiredThe full list of stages, in order: { name, kind: open|won|lost, probability 0-100, color: gray|blue|green|yellow|orange|red|purple, targetHours (how long a deal should sit there) }. Keep a stage’s id (from get_settings) to rename it; a stage left out is removed (refused while open deals sit in it).
makeDefaultbooleanMake it the pipeline new deals land in
splitCreditbooleanLet several people share credit on its deals (see set_deal_split)
curl -X POST "https://api.crossingedge.com/v1/actions/create_pipeline" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"name": "Acme",
"stages": []
}'const res = await fetch("https://api.crossingedge.com/v1/actions/create_pipeline", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
"name": "Acme",
"stages": []
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/create_pipeline",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}", "Idempotency-Key": str(uuid.uuid4())},
json={
"name": "Acme",
"stages": []
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/actions/update_pipelineUpdate pipeline
Renames a pipeline or changes its stages. stages replaces the whole list: keep each stage’s id to rename it; stages matched by name keep their deals.
Body
pipelinestringrequiredPipeline name or id
namestringNew name
descriptionstringNew description
stagesarray of objectThe full list of stages, in order: { name, kind: open|won|lost, probability 0-100, color: gray|blue|green|yellow|orange|red|purple, targetHours (how long a deal should sit there) }. Keep a stage’s id (from get_settings) to rename it; a stage left out is removed (refused while open deals sit in it).
splitCreditbooleanLet several people share credit on its deals. Off keeps existing splits; they stop counting until it is on again
curl -X POST "https://api.crossingedge.com/v1/actions/update_pipeline" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"pipeline": "…"
}'const res = await fetch("https://api.crossingedge.com/v1/actions/update_pipeline", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
"pipeline": "…"
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/update_pipeline",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}", "Idempotency-Key": str(uuid.uuid4())},
json={
"pipeline": "…"
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/actions/set_default_pipelineSet default pipeline
Makes a pipeline the one new deals land in.
Body
pipelinestringrequiredPipeline name or id
curl -X POST "https://api.crossingedge.com/v1/actions/set_default_pipeline" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"pipeline": "…"
}'const res = await fetch("https://api.crossingedge.com/v1/actions/set_default_pipeline", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
"pipeline": "…"
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/set_default_pipeline",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}", "Idempotency-Key": str(uuid.uuid4())},
json={
"pipeline": "…"
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/actions/archive_pipelineArchive pipeline
Archives a pipeline (its deals and history stay; it can be restored) or restores one with archived: false. The last live pipeline can’t be archived.
Body
pipelinestringrequiredPipeline name or id
archivedbooleanfalse to restore; default true
curl -X POST "https://api.crossingedge.com/v1/actions/archive_pipeline" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"pipeline": "…"
}'const res = await fetch("https://api.crossingedge.com/v1/actions/archive_pipeline", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
"pipeline": "…"
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/archive_pipeline",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}", "Idempotency-Key": str(uuid.uuid4())},
json={
"pipeline": "…"
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/actions/create_objectCreate object
Adds an object of the workspace’s own (like Projects or Tickets), with a required Name field to start. Add more fields with create_field, and join it to others with create_relationship.
Body
namestringrequiredSingular, e.g. Project
pluralstringrequiredPlural, e.g. Projects
iconstringOne of box folder ticket calendar chart tag star flag
colorstringgray, blue, green, yellow, orange, red, purple
curl -X POST "https://api.crossingedge.com/v1/actions/create_object" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"name": "Acme",
"plural": "…"
}'const res = await fetch("https://api.crossingedge.com/v1/actions/create_object", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
"name": "Acme",
"plural": "…"
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/create_object",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}", "Idempotency-Key": str(uuid.uuid4())},
json={
"name": "Acme",
"plural": "…"
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/actions/update_objectUpdate object
Renames a workspace object or changes its icon, colour, or which fields name and describe its records.
Body
objectstringrequiredcontacts, companies, deals, or a workspace object by id, name or plural
namestringSingular
pluralstringPlural
iconstringOne of box folder ticket calendar chart tag star flag
colorstringgray, blue, green, yellow, orange, red, purple
titleFieldstringField (label or id) that names a record
subtitleFieldstringField (label or id) shown under the name
curl -X POST "https://api.crossingedge.com/v1/actions/update_object" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"object": "deals"
}'const res = await fetch("https://api.crossingedge.com/v1/actions/update_object", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
"object": "deals"
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/update_object",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}", "Idempotency-Key": str(uuid.uuid4())},
json={
"object": "deals"
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/actions/archive_objectArchive object
Archives a workspace object (hidden, records kept, can be restored) or restores it with archived: false.
Body
objectstringrequiredcontacts, companies, deals, or a workspace object by id, name or plural
archivedbooleanfalse to restore; default true
curl -X POST "https://api.crossingedge.com/v1/actions/archive_object" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"object": "deals"
}'const res = await fetch("https://api.crossingedge.com/v1/actions/archive_object", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
"object": "deals"
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/archive_object",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}", "Idempotency-Key": str(uuid.uuid4())},
json={
"object": "deals"
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/actions/delete_objectDelete object
Deletes a workspace object for good, with its fields and views. Only allowed once it has no records, relationships or automations. Ask the person first, then call with confirm: true.
Body
objectstringrequiredcontacts, companies, deals, or a workspace object by id, name or plural
confirmbooleanrequiredTrue once the person has confirmed
curl -X POST "https://api.crossingedge.com/v1/actions/delete_object" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"object": "deals",
"confirm": true
}'const res = await fetch("https://api.crossingedge.com/v1/actions/delete_object", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
"object": "deals",
"confirm": true
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/delete_object",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}", "Idempotency-Key": str(uuid.uuid4())},
json={
"object": "deals",
"confirm": True
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/actions/create_fieldCreate field
Adds a custom field to any object, built in or the workspace’s own. Types: text, longText, number, currency, percent, date, datetime, checkbox, singleSelect, multiSelect, email, phone, url, country, user. Select types need options.
Body
objectstringrequiredcontacts, companies, deals, or a workspace object by id, name or plural
labelstringrequiredField name, e.g. Contract value
typestringrequiredOne of text longText number currency percent date datetime checkbox singleSelect multiSelect email phone url country user
optionsarray of stringChoices, for singleSelect and multiSelect
helpstringA line of help under the field
requiredbooleanEvery record must have it
uniquebooleanNo two records may share a value (text, email, phone, url, number, currency, date)
defaultValueanyWhat new records start with
curl -X POST "https://api.crossingedge.com/v1/actions/create_field" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"object": "deals",
"label": "…",
"type": "text"
}'const res = await fetch("https://api.crossingedge.com/v1/actions/create_field", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
"object": "deals",
"label": "…",
"type": "text"
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/create_field",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}", "Idempotency-Key": str(uuid.uuid4())},
json={
"object": "deals",
"label": "…",
"type": "text"
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/actions/update_fieldUpdate field
Changes a custom field’s label, help, required, unique or default. Its type can’t change. To rename or remove choices use set_field_choices; adding choices works here too.
Body
objectstringrequiredcontacts, companies, deals, or a workspace object by id, name or plural
fieldstringrequiredField label or id
labelstringNew label
helpstringHelp line
requiredbooleanRequired
uniquebooleanUnique
defaultValueanyDefault for new records
optionsarray of stringFull list of choices (only adding; use set_field_choices to rename or remove)
curl -X POST "https://api.crossingedge.com/v1/actions/update_field" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"object": "deals",
"field": "…"
}'const res = await fetch("https://api.crossingedge.com/v1/actions/update_field", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
"object": "deals",
"field": "…"
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/update_field",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}", "Idempotency-Key": str(uuid.uuid4())},
json={
"object": "deals",
"field": "…"
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/actions/set_field_choicesSet field choices
Sets the choices of a select field: a custom single or multi select, or a standard one (contacts: status, source, buyingRoles; companies: icp). Records using a removed or renamed choice move through replacements: { old: new } (null clears them). Standard fields also take colours and a default.
Body
objectstringrequiredcontacts, companies, deals, or a workspace object by id, name or plural
fieldstringrequiredField label or id, or status / source / buyingRoles / icp
choicesarray of objectrequiredThe full list, in order: strings, or { value, color (gray, blue, green, yellow, orange, red, purple) }
replacementsobjectWhere records on an old choice go: { "Old": "New" or null }
defaultValuestringStandard fields: the choice new records start with
curl -X POST "https://api.crossingedge.com/v1/actions/set_field_choices" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"object": "deals",
"field": "…",
"choices": []
}'const res = await fetch("https://api.crossingedge.com/v1/actions/set_field_choices", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
"object": "deals",
"field": "…",
"choices": []
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/set_field_choices",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}", "Idempotency-Key": str(uuid.uuid4())},
json={
"object": "deals",
"field": "…",
"choices": []
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/actions/archive_fieldArchive field
Archives a custom field (hidden, values kept, can be restored) or restores it with archived: false. A field automations use needs force: true, which leaves those automations flagged.
Body
objectstringrequiredcontacts, companies, deals, or a workspace object by id, name or plural
fieldstringrequiredField label or id
archivedbooleanfalse to restore; default true
forcebooleanArchive even though automations use it
curl -X POST "https://api.crossingedge.com/v1/actions/archive_field" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"object": "deals",
"field": "…"
}'const res = await fetch("https://api.crossingedge.com/v1/actions/archive_field", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
"object": "deals",
"field": "…"
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/archive_field",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}", "Idempotency-Key": str(uuid.uuid4())},
json={
"object": "deals",
"field": "…"
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/actions/arrange_fieldsArrange fields
Shapes an object’s fields for everyone in the workspace: the order they appear in (record pages, forms, tables), standard fields to hide or show again, and standard fields to make required or optional. Fields are named by label or key. order may list just the fields that should come first; the rest keep their order after them. Hidden fields keep their data. Name, owner, stage, email and phone can’t be hidden; Crossing Edge’s own fields (created at and so on) can’t be required. Required is checked when people save (app, Claude, the assistant), not on leads captured automatically. Custom fields are required on the field itself (update_field) and archived rather than hidden.
Body
objectstringrequiredcontacts, companies, deals, or a workspace object by id, name or plural
orderarray of stringFields in the order they should appear, first first
hidearray of stringStandard fields to hide
showarray of stringHidden standard fields to show again
requirearray of stringStandard fields to make required
optionalarray of stringStandard fields to make optional again
curl -X POST "https://api.crossingedge.com/v1/actions/arrange_fields" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"object": "deals"
}'const res = await fetch("https://api.crossingedge.com/v1/actions/arrange_fields", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
"object": "deals"
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/arrange_fields",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}", "Idempotency-Key": str(uuid.uuid4())},
json={
"object": "deals"
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/actions/delete_fieldDelete field
Deletes an archived custom field and every value it holds, permanently. It cannot be undone, so always ask the person first and only then call with confirm: true. Without confirm it reports what would be erased (records holding a value) and anything still using the field (automations, reports, calculated fields, stage timing), which must be changed first. Archive the field with archive_field before deleting it. Standard fields are never deleted: hide them with arrange_fields.
Body
objectstringrequiredcontacts, companies, deals, or a workspace object by id, name or plural
fieldstringrequiredCustom field label or id
confirmbooleantrue only after the person has agreed to erase it for good
curl -X POST "https://api.crossingedge.com/v1/actions/delete_field" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"object": "deals",
"field": "…"
}'const res = await fetch("https://api.crossingedge.com/v1/actions/delete_field", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
"object": "deals",
"field": "…"
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/delete_field",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}", "Idempotency-Key": str(uuid.uuid4())},
json={
"object": "deals",
"field": "…"
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/actions/create_relationshipCreate relationship
Joins two objects so their records can be linked, e.g. companies ↔ Projects. Each side gets its own label: what the other side is called when read from it.
Body
fromstringrequiredcontacts, companies, deals, or a workspace object by id, name or plural
tostringrequiredcontacts, companies, deals, or a workspace object by id, name or plural
fromLabelstringrequiredWhat a from record calls its linked to records, e.g. Projects
toLabelstringrequiredWhat a to record calls its linked from records, e.g. Account
manyTobooleanA from record may hold several to records (default true)
manyFrombooleanA to record may be held by several from records (default true)
curl -X POST "https://api.crossingedge.com/v1/actions/create_relationship" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"from": "…",
"to": "…",
"fromLabel": "…",
"toLabel": "…"
}'const res = await fetch("https://api.crossingedge.com/v1/actions/create_relationship", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
"from": "…",
"to": "…",
"fromLabel": "…",
"toLabel": "…"
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/create_relationship",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}", "Idempotency-Key": str(uuid.uuid4())},
json={
"from": "…",
"to": "…",
"fromLabel": "…",
"toLabel": "…"
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/actions/update_relationshipUpdate relationship
Renames a relationship’s labels or changes whether each side may hold several records.
Body
relationshipstringrequiredRelationship id or either label
fromLabelstringNew from label
toLabelstringNew to label
manyTobooleanmanyTo
manyFrombooleanmanyFrom
showReversebooleanShow it on the to side too
curl -X POST "https://api.crossingedge.com/v1/actions/update_relationship" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"relationship": "…"
}'const res = await fetch("https://api.crossingedge.com/v1/actions/update_relationship", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
"relationship": "…"
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/update_relationship",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}", "Idempotency-Key": str(uuid.uuid4())},
json={
"relationship": "…"
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/actions/archive_relationshipArchive relationship
Archives a relationship (hidden, links kept, can be restored) or restores it with archived: false.
Body
relationshipstringrequiredRelationship id or either label
archivedbooleanfalse to restore; default true
curl -X POST "https://api.crossingedge.com/v1/actions/archive_relationship" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"relationship": "…"
}'const res = await fetch("https://api.crossingedge.com/v1/actions/archive_relationship", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
"relationship": "…"
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/archive_relationship",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}", "Idempotency-Key": str(uuid.uuid4())},
json={
"relationship": "…"
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/actions/delete_relationshipDelete relationship
Deletes a relationship for good. Only allowed once no records are linked through it. Ask the person first, then call with confirm: true.
Body
relationshipstringrequiredRelationship id or either label
confirmbooleanrequiredTrue once the person has confirmed
curl -X POST "https://api.crossingedge.com/v1/actions/delete_relationship" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"relationship": "…",
"confirm": true
}'const res = await fetch("https://api.crossingedge.com/v1/actions/delete_relationship", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
"relationship": "…",
"confirm": true
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/delete_relationship",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}", "Idempotency-Key": str(uuid.uuid4())},
json={
"relationship": "…",
"confirm": True
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/actions/update_workspace_settingsUpdate workspace settings
Changes workspace-wide settings: its name, currency (USD, EUR, GBP, INR, …), fiscal year start month, business hours for stage clocks, stage time targets for contact statuses ({ "contacts.status.Working": 48 } hours; 0 removes), which statuses make the funnel, which select field a record’s stage clock follows, and the file limits: the largest file anyone may upload (maxFileMb, 1 to 25 MB, default 5) and all the workspace’s files together (storageMb, 100 to 5120 MB, default 1024). Lowering a file limit keeps files already stored; only new uploads are checked.
Body
namestringWorkspace name
currencystringISO currency code
fiscalYearStartnumberMonth the fiscal year starts, 1-12
businessHoursobject{ mode: 'calendar' | 'business', days: [1..5] (0 is Sunday), startMinute: 540, endMinute: 1080, timezone: 'Asia/Kolkata' }
targetsobjectHours allowed per stage, keyed object.field.value
funnelarray of stringContact statuses in funnel order
tracksobjectWhich select field each object’s stage clock follows, e.g. { contacts: "status" }
maxFileMbnumberThe largest file anyone may upload, in MB: 1 to 25
storageMbnumberAll the workspace’s files together, in MB: 100 to 5120 (5 GB)
curl -X POST "https://api.crossingedge.com/v1/actions/update_workspace_settings" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"name": "Acme",
"currency": "…"
}'const res = await fetch("https://api.crossingedge.com/v1/actions/update_workspace_settings", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
"name": "Acme",
"currency": "…"
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/update_workspace_settings",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}", "Idempotency-Key": str(uuid.uuid4())},
json={
"name": "Acme",
"currency": "…"
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/actions/create_automationCreate automation
Adds an automation: a rule that acts when records are created or change. An automation: { name, object (contacts, companies, deals, a workspace object, or activities), enabled, triggers: [{ kind: 'created' } | { kind: 'changed', field, to? } | { kind: 'overdue', days } (activities only)], conditions: [{ key, values? | text? | min?, max? }], tree: [node] }. Activities (object 'activities') are tasks, calls, meetings, emails, messages and notes: filter by type (task, call, meeting, email, message, note) and status (planned, in_progress, done, cancelled); other fields: subject, body, at (due date), overdueDays, ownerId (the assignee), createdBy, completedAt, linkedTo (contacts, companies, deals), contactOwnerId, companyOwnerId, dealOwnerId, dealStage. { kind: 'overdue', days: 2 } runs once per activity still to do, 2 whole days past its due date (checked every 15 minutes). On an activity: owner reassigns it (who: owner = current assignee, creator, a user, or { kind: 'field', field: 'dealOwnerId' } for the linked deal's owner); set changes status, subject, body or at (at may be a when, e.g. { kind: 'in', amount: 2, unit: 'days' }); activity and note steps land on the records the activity is on; related { from: contacts | companies | deals } reaches those records; link is not available. A node is { id, kind, config, children: [] }; kinds and their config: - condition { filters: [{ key, values? }] } (children run only when it matches) - activity { type: task|call|meeting|email|message|note, subject (body for a note), who?: { kind: owner|creator } | { kind: 'user', userId }, when?: { kind: 'in', amount, unit: hours|days|weeks, skipWeekends? } } - note { body } - set { field, value } - owner { who }: who is { kind: 'owner' } | { kind: 'creator' } | { kind: 'user', userId } | { kind: 'field', field } (a user field on the record) | { kind: 'rotate', id, userIds: [...] } (take turns, fair over time, skipping anyone who left; id is any short unique name like 'rot_inbound', and keeping it keeps the place in the turn) | { kind: 'rules', rules: [{ when: [{ key, values }], then: who }], otherwise: who } (first match wins; inside rules { kind: 'user', userId: 0 } means nobody, so the record stays unassigned). This is how leads get assigned: webhook leads arrive unassigned and their source is the webhook's name. - record { object, title (may use {{field}}), values?, pipelineId?, stageId? }: object is a standard object or a workspace object's id (obj_…, from get_schema); title becomes the new record's name. values must set every field that object marks required and has no default, or the rule is refused. The new record is attached to the one that started the rule (contacts, companies and deals directly; other objects through a relationship between the two). - related { from, relationshipId?, direction? } (its children act on the related record) - link { from, recordId, relationshipId?, mode?: 'unlink' } Lead assignment example: { name: 'Assign inbound leads', object: 'contacts', triggers: [{ kind: 'created' }], conditions: [{ key: 'source', values: ['Website form'] }], tree: [{ id: 'n1', kind: 'owner', config: { who: { kind: 'rules', rules: [{ when: [{ key: 'city', values: ['Chennai'] }], then: { kind: 'user', userId: 12 } }], otherwise: { kind: 'rotate', id: 'rot_inbound', userIds: [12, 15] } } }, children: [] }] }. Example: { name: 'Call new leads', object: 'contacts', triggers: [{ kind: 'created' }], conditions: [], tree: [{ id: 'n1', kind: 'activity', config: { type: 'task', subject: 'Call {{firstName}}', who: { kind: 'owner' }, when: { kind: 'in', amount: 1, unit: 'days' } }, children: [] }] }. Try it with test_automation before switching it on.
Body
automationobjectrequiredThe automation, as described above
curl -X POST "https://api.crossingedge.com/v1/actions/create_automation" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"automation": {}
}'const res = await fetch("https://api.crossingedge.com/v1/actions/create_automation", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
"automation": {}
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/create_automation",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}", "Idempotency-Key": str(uuid.uuid4())},
json={
"automation": {}
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/actions/update_automationUpdate automation
Changes an automation: pass only what changes (name, enabled, triggers, conditions, tree). enabled: false switches it off without deleting it.
Body
automationstringrequiredAutomation name or id
changesobjectrequiredFields to change, same shape as create_automation
curl -X POST "https://api.crossingedge.com/v1/actions/update_automation" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"automation": "…",
"changes": {}
}'const res = await fetch("https://api.crossingedge.com/v1/actions/update_automation", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
"automation": "…",
"changes": {}
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/update_automation",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}", "Idempotency-Key": str(uuid.uuid4())},
json={
"automation": "…",
"changes": {}
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/actions/test_automationTest automation
Dry-runs an automation over existing records: which would match, why, and what it would do. Changes nothing.
Body
automationstringrequiredAutomation name or id
limitnumberHow many records to try, default 20, at most 50
curl -X POST "https://api.crossingedge.com/v1/actions/test_automation" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-d '{
"automation": "…"
}'const res = await fetch("https://api.crossingedge.com/v1/actions/test_automation", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"automation": "…"
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/test_automation",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}"},
json={
"automation": "…"
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/actions/delete_automationDelete automation
Deletes an automation and its run history for good (update_automation with enabled: false just switches it off). Ask the person first, then call with confirm: true.
Body
automationstringrequiredAutomation name or id
confirmbooleanrequiredTrue once the person has confirmed
curl -X POST "https://api.crossingedge.com/v1/actions/delete_automation" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"automation": "…",
"confirm": true
}'const res = await fetch("https://api.crossingedge.com/v1/actions/delete_automation", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
"automation": "…",
"confirm": true
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/delete_automation",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}", "Idempotency-Key": str(uuid.uuid4())},
json={
"automation": "…",
"confirm": True
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/actions/add_memberAdd member
Invites someone to the workspace by email (or phone): they are added straight away and emailed an invite with a Join button (notify: false to add them quietly). Role: member (default) or admin; permissions: a preset (full, standard, own, readOnly) or leave it to the workspace default. The answer says whether the invite went out.
Body
emailstringrequiredTheir email or phone
namestringTheir name
rolestringOne of member admin
permissionsstringPreset: full, standard, own or readOnly
notifybooleanEmail them an invite (default true)
curl -X POST "https://api.crossingedge.com/v1/actions/add_member" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"email": "priya@acme.com"
}'const res = await fetch("https://api.crossingedge.com/v1/actions/add_member", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
"email": "priya@acme.com"
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/add_member",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}", "Idempotency-Key": str(uuid.uuid4())},
json={
"email": "priya@acme.com"
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/actions/resend_inviteResend invite
Emails someone who was added but hasn’t signed in yet their invite again.
Body
memberstringrequiredMember email or name
curl -X POST "https://api.crossingedge.com/v1/actions/resend_invite" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"member": "…"
}'const res = await fetch("https://api.crossingedge.com/v1/actions/resend_invite", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
"member": "…"
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/resend_invite",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}", "Idempotency-Key": str(uuid.uuid4())},
json={
"member": "…"
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/actions/update_memberUpdate member
Changes a member’s role (member or admin) or what they can do: a preset (full, standard, own, readOnly), "default" for the workspace default, or a full permissions object.
Body
memberstringrequiredMember email or name
rolestringOne of member admin
permissionsanyPreset name, "default", or a permissions object
curl -X POST "https://api.crossingedge.com/v1/actions/update_member" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"member": "…"
}'const res = await fetch("https://api.crossingedge.com/v1/actions/update_member", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
"member": "…"
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/update_member",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}", "Idempotency-Key": str(uuid.uuid4())},
json={
"member": "…"
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/actions/remove_memberRemove member
Removes someone from the workspace; the records they own stay. Ask the person first, then call with confirm: true.
Body
memberstringrequiredMember email or name
confirmbooleanrequiredTrue once the person has confirmed
curl -X POST "https://api.crossingedge.com/v1/actions/remove_member" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"member": "…",
"confirm": true
}'const res = await fetch("https://api.crossingedge.com/v1/actions/remove_member", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
"member": "…",
"confirm": true
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/remove_member",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}", "Idempotency-Key": str(uuid.uuid4())},
json={
"member": "…",
"confirm": True
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/actions/update_ai_settingsUpdate AI settings
Switches AI duplicate detection on or off. Switching on can also check existing contacts and companies from a date (YYYY-MM-DD) or all of them.
Body
duplicatesbooleanrequiredDetect duplicates
backfillSincestring'all' or YYYY-MM-DD: check existing records too
curl -X POST "https://api.crossingedge.com/v1/actions/update_ai_settings" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"duplicates": true
}'const res = await fetch("https://api.crossingedge.com/v1/actions/update_ai_settings", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
"duplicates": true
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/update_ai_settings",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}", "Idempotency-Key": str(uuid.uuid4())},
json={
"duplicates": True
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}Insights and history
ActionsDuplicates, merging, history, stage times, overdue work, insights, spend and saved views.
/actions/find_duplicatesFind duplicates
Finds duplicate contacts or companies. With an id: checks that record now (AI, when the workspace has it on) and lists its lookalikes. Without one: every open AI suggestion plus exact lookalikes (same name, email, phone or website) across the workspace, most likely first. Follow with merge_preview and merge_records, or dismiss_duplicate.
Body
objectstringrequiredcontacts or companies
One of contacts companies
idnumberOne record to check
limitnumberHow many pairs, default 30, at most 200
curl -X POST "https://api.crossingedge.com/v1/actions/find_duplicates" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"object": "contacts"
}'const res = await fetch("https://api.crossingedge.com/v1/actions/find_duplicates", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
"object": "contacts"
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/find_duplicates",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}", "Idempotency-Key": str(uuid.uuid4())},
json={
"object": "contacts"
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/actions/scan_duplicatesScan for duplicates
Runs the AI duplicate check over existing contacts and companies (all of them, or those created since a date), in the background. Switches AI duplicate detection on for the workspace. Owners and admins. Pairs already judged are skipped, so re-running is cheap; call find_duplicates afterwards.
Body
sincestring'all' (default) or YYYY-MM-DD
curl -X POST "https://api.crossingedge.com/v1/actions/scan_duplicates" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"since": "…"
}'const res = await fetch("https://api.crossingedge.com/v1/actions/scan_duplicates", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
"since": "…"
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/scan_duplicates",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}", "Idempotency-Key": str(uuid.uuid4())},
json={
"since": "…"
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/actions/dismiss_duplicateDismiss duplicate
Marks two records as not duplicates, so the pair stops being suggested.
Body
objectstringrequiredcontacts or companies
One of contacts companies
anumberrequiredOne record id
bnumberrequiredThe other record id
curl -X POST "https://api.crossingedge.com/v1/actions/dismiss_duplicate" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"object": "contacts",
"a": 101,
"b": 101
}'const res = await fetch("https://api.crossingedge.com/v1/actions/dismiss_duplicate", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
"object": "contacts",
"a": 101,
"b": 101
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/dismiss_duplicate",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}", "Idempotency-Key": str(uuid.uuid4())},
json={
"object": "contacts",
"a": 101,
"b": 101
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/actions/merge_previewMerge preview
Shows what merging two contacts or companies would do before doing it: which values the kept record keeps or takes from the duplicate (with the choices per field), and the deals, activities, notes, links and history that move over. Show this to the person before merge_records.
Body
objectstringrequiredcontacts or companies
One of contacts companies
keepnumberrequiredId of the record that stays
removenumberrequiredId of the duplicate folded into it and then deleted
curl -X POST "https://api.crossingedge.com/v1/actions/merge_preview" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-d '{
"object": "contacts",
"keep": 101,
"remove": 101
}'const res = await fetch("https://api.crossingedge.com/v1/actions/merge_preview", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"object": "contacts",
"keep": 101,
"remove": 101
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/merge_preview",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}"},
json={
"object": "contacts",
"keep": 101,
"remove": 101
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/actions/merge_recordsMerge records
Merges a duplicate contact or company into the one that stays: its deals, activities, notes, links, people and history move over, chosen field values are copied, and the duplicate is deleted. Defaults match the app (the kept value wins, blanks are filled, companies are kept from both). Override per field with choices: { field: existing | incoming | both }. Can’t be undone: show merge_preview, ask the person, then call with confirm: true.
Body
objectstringrequiredcontacts or companies
One of contacts companies
keepnumberrequiredId of the record that stays
removenumberrequiredId of the duplicate
choicesobjectPer field, from merge_preview: "existing" keeps the kept record’s value, "incoming" takes the duplicate’s, "both" keeps both companies
confirmbooleanrequiredTrue once the person has confirmed
curl -X POST "https://api.crossingedge.com/v1/actions/merge_records" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"object": "contacts",
"keep": 101,
"remove": 101,
"confirm": true
}'const res = await fetch("https://api.crossingedge.com/v1/actions/merge_records", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
"object": "contacts",
"keep": 101,
"remove": 101,
"confirm": true
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/merge_records",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}", "Idempotency-Key": str(uuid.uuid4())},
json={
"object": "contacts",
"keep": 101,
"remove": 101,
"confirm": True
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/actions/get_historyGet history
A record’s change history, newest first: who created, changed (field by field, from and to), linked, merged or deleted things, and when. Any object. Page with before.
Body
objectstringrequiredAny object
idnumberrequiredRecord id
limitnumberHow many, default 20, at most 100
beforestringThe cursor from the previous page
curl -X POST "https://api.crossingedge.com/v1/actions/get_history" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-d '{
"object": "deals",
"id": 101
}'const res = await fetch("https://api.crossingedge.com/v1/actions/get_history", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"object": "deals",
"id": 101
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/get_history",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}"},
json={
"object": "deals",
"id": 101
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/actions/get_stage_timesGet stage times
How long a record has spent in each stage (deal pipeline stages, or a contact’s status), counting business hours when the workspace uses them: where it is now, for how long, against the target, and every stage it passed through.
Body
objectstringrequiredAny object with a stage: deals, contacts, …
idnumberrequiredRecord id
curl -X POST "https://api.crossingedge.com/v1/actions/get_stage_times" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-d '{
"object": "deals",
"id": 101
}'const res = await fetch("https://api.crossingedge.com/v1/actions/get_stage_times", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"object": "deals",
"id": 101
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/get_stage_times",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}"},
json={
"object": "deals",
"id": 101
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/actions/list_overdueList overdue
Records that have sat in their stage past its target (overdue) or are close to it (due soon), longest over first. Only records you can see.
Body
objectstringOnly this object (deals, contacts, …)
includestringDefault overdue
One of overdue dueSoon both
limitnumberHow many, default 30
curl -X POST "https://api.crossingedge.com/v1/actions/list_overdue" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-d '{
"object": "deals",
"include": "overdue"
}'const res = await fetch("https://api.crossingedge.com/v1/actions/list_overdue", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"object": "deals",
"include": "overdue"
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/list_overdue",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}"},
json={
"object": "deals",
"include": "overdue"
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/actions/get_insightsGet insights
The Insights page as data: leads and conversion, won value, win rate, time to win, the funnel, segments, execution, what needs attention, and observations, for a period against the one before. Owners and admins.
Body
periodstringDefault month
One of week month quarter year custom
yearnumberYear
quarternumber1-4
fromstringcustom: first day, YYYY-MM-DD
tostringcustom: last day, YYYY-MM-DD
pipelinestringPipeline name or id
filtersarray of objectDeal filters: [{ key, values? | text? | min?, max? }]
curl -X POST "https://api.crossingedge.com/v1/actions/get_insights" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-d '{
"period": "week",
"year": 101
}'const res = await fetch("https://api.crossingedge.com/v1/actions/get_insights", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"period": "week",
"year": 101
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/get_insights",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}"},
json={
"period": "week",
"year": 101
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/actions/get_spendGet spend
Marketing spend by source and month, as entered for Insights. Owners and admins.
curl -X POST "https://api.crossingedge.com/v1/actions/get_spend" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-d '{}'const res = await fetch("https://api.crossingedge.com/v1/actions/get_spend", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/get_spend",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}"},
json={},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/actions/set_spendSet spend
Records what was spent on a lead source in a month (amount 0 means nothing was spent; null clears it back to unknown). Owners and admins.
Body
sourcestringrequiredLead source, as in contact sources
monthstringrequiredYYYY-MM
amountnumberrequiredAmount in the workspace currency, or null for unknown
curl -X POST "https://api.crossingedge.com/v1/actions/set_spend" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"source": "…",
"month": "…",
"amount": 12000
}'const res = await fetch("https://api.crossingedge.com/v1/actions/set_spend", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
"source": "…",
"month": "…",
"amount": 12000
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/set_spend",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}", "Idempotency-Key": str(uuid.uuid4())},
json={
"source": "…",
"month": "…",
"amount": 12000
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/actions/get_automation_runsGet automation runs
What automations actually did, newest first: which record, whether it matched, what it did, and any error. One automation or all.
Body
automationstringAutomation name or id; all when left out
failedOnlybooleanOnly runs with an error
limitnumberHow many, default 30, at most 200
curl -X POST "https://api.crossingedge.com/v1/actions/get_automation_runs" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-d '{
"automation": "…",
"failedOnly": true
}'const res = await fetch("https://api.crossingedge.com/v1/actions/get_automation_runs", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"automation": "…",
"failedOnly": true
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/get_automation_runs",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}"},
json={
"automation": "…",
"failedOnly": True
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/actions/list_viewsList views
Saved list views: yours and the shared ones, with their filters, sort and hidden columns, and which one opens by default for you.
Body
objectstringOnly views of this object
curl -X POST "https://api.crossingedge.com/v1/actions/list_views" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-d '{
"object": "deals"
}'const res = await fetch("https://api.crossingedge.com/v1/actions/list_views", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"object": "deals"
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/list_views",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}"},
json={
"object": "deals"
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/actions/save_viewSave view
Saves a list view, or changes one (pass view). filters: [{ key, values? | text? | min?, max? }] with field keys from get_schema; sort: { id: field key, dir: asc | desc }; hidden: column keys to hide; cardFields: what each card shows on the board, as field keys in order (at most 5; timeInStage = time in the current stage; a field of a linked record as <relation field>.<field>, e.g. companyIds.industry on deals; [] for just the name); shared: everyone sees it (needs the share-views permission).
Body
objectstringrequiredObject the view lists
viewstringAn existing view’s name or id, to change it
namestringView name
filtersarray of objectsortobject{ id, dir }
hiddenarray of stringcardFieldsarray of stringField keys shown on board cards, in order, at most 5; companyIds.industry reads the linked company
sharedbooleanShare with the workspace
makeDefaultbooleanOpen this view by default for you
curl -X POST "https://api.crossingedge.com/v1/actions/save_view" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"object": "deals"
}'const res = await fetch("https://api.crossingedge.com/v1/actions/save_view", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
"object": "deals"
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/save_view",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}", "Idempotency-Key": str(uuid.uuid4())},
json={
"object": "deals"
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/actions/set_default_viewSet default view
Which view a list opens on for you: a saved view by name or id, a built-in one (all, mine, leads, open), or null for the page default.
Body
objectstringrequiredObject
viewstringrequiredView name or id, a built-in id, or null
curl -X POST "https://api.crossingedge.com/v1/actions/set_default_view" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"object": "deals",
"view": "…"
}'const res = await fetch("https://api.crossingedge.com/v1/actions/set_default_view", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
"object": "deals",
"view": "…"
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/set_default_view",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}", "Idempotency-Key": str(uuid.uuid4())},
json={
"object": "deals",
"view": "…"
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/actions/delete_viewDelete view
Deletes a saved view (the records it lists are untouched). A shared view disappears for everyone.
Body
viewstringrequiredView name or id
objectstringIts object, when names repeat across objects
curl -X POST "https://api.crossingedge.com/v1/actions/delete_view" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"view": "…"
}'const res = await fetch("https://api.crossingedge.com/v1/actions/delete_view", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
"view": "…"
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/delete_view",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}", "Idempotency-Key": str(uuid.uuid4())},
json={
"view": "…"
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/actions/delete_reportDelete report
Deletes a report for good (its author, or an owner or admin). Ask the person first, then call with confirm: true.
Body
reportstringrequiredReport id or name
confirmbooleanrequiredTrue once the person has confirmed
curl -X POST "https://api.crossingedge.com/v1/actions/delete_report" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"report": "…",
"confirm": true
}'const res = await fetch("https://api.crossingedge.com/v1/actions/delete_report", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
"report": "…",
"confirm": true
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/delete_report",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}", "Idempotency-Key": str(uuid.uuid4())},
json={
"report": "…",
"confirm": True
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}Email conversations, replies, drafts in the member’s own style, and their writing profile.
/actions/list_email_conversationsList email conversations
Email conversations brought in by Gmail sync or logged by hand: subject, people, how many emails, the newest one, its AI brief and whether it needs a reply. The workspace’s (as far as the person can see), only their own inboxes with mine: true, or one record’s.
Body
minebooleanOnly conversations from the person’s own inboxes
qstringSearch subject, people and text
recordobjectOnly the ones on this record
curl -X POST "https://api.crossingedge.com/v1/actions/list_email_conversations" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-d '{
"mine": true,
"q": "…"
}'const res = await fetch("https://api.crossingedge.com/v1/actions/list_email_conversations", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"mine": true,
"q": "…"
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/list_email_conversations",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}"},
json={
"mine": True,
"q": "…"
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/actions/read_email_conversationRead email conversation
One email conversation, oldest first: each email’s sender, recipients and own text (quoted history cut), the brief, the records it is on, and whether the person can reply from Crossing Edge (from which of their inboxes, and who Reply and Reply all go to).
Body
keystringrequiredConversation key from list_email_conversations
curl -X POST "https://api.crossingedge.com/v1/actions/read_email_conversation" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-d '{
"key": "…"
}'const res = await fetch("https://api.crossingedge.com/v1/actions/read_email_conversation", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"key": "…"
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/read_email_conversation",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}"},
json={
"key": "…"
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/actions/draft_email_replyDraft email reply
Drafts the person’s reply to an email conversation in their own writing style (learned from the email they send), with their signature on the end. Nothing is sent: show them the draft, let them change it, then send_email_reply. Facts the thread does not give are left as [placeholders] to fill in.
Body
keystringrequiredConversation key
allbooleanReply all rather than reply
curl -X POST "https://api.crossingedge.com/v1/actions/draft_email_reply" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-d '{
"key": "…"
}'const res = await fetch("https://api.crossingedge.com/v1/actions/draft_email_reply", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"key": "…"
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/draft_email_reply",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}"},
json={
"key": "…"
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/actions/send_email_replySend email reply
Sends a reply to an email conversation through the person’s own Gmail, threaded under it, and keeps it in the conversation. Recipients default to Reply (or Reply all with all: true); to, cc and bcc replace them. It goes to people outside the workspace: show the person the text and recipients, then call with confirm: true. Attachments are added in the app.
Body
keystringrequiredConversation key
textstringrequiredThe message, plain text
allbooleanReply all: everyone else on the thread too
toarray of stringEmail addresses to send to (replaces the default)
ccarray of stringCc addresses (replaces the default)
bccarray of stringBcc addresses
subjectstringSubject (default Re: the conversation’s)
inboxstringWhich of the person’s inboxes to send from (default the one it came through)
confirmbooleanrequiredTrue once the person has seen it and said send
curl -X POST "https://api.crossingedge.com/v1/actions/send_email_reply" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"key": "…",
"text": "…",
"confirm": true
}'const res = await fetch("https://api.crossingedge.com/v1/actions/send_email_reply", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
"key": "…",
"text": "…",
"confirm": true
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/send_email_reply",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}", "Idempotency-Key": str(uuid.uuid4())},
json={
"key": "…",
"text": "…",
"confirm": True
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/actions/get_writing_profileGet writing profile
How the person writes their email, as Crossing Edge learned it from what they send (tone, length, greeting, sign-off, phrases, what they avoid), and the emails they pasted in to learn from. Private to them.
curl -X POST "https://api.crossingedge.com/v1/actions/get_writing_profile" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-d '{}'const res = await fetch("https://api.crossingedge.com/v1/actions/get_writing_profile", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/get_writing_profile",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}"},
json={},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/actions/relearn_writing_profileLearn writing style again
Learns the person’s writing profile again now, from their latest sent email and pasted samples.
curl -X POST "https://api.crossingedge.com/v1/actions/relearn_writing_profile" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{}'const res = await fetch("https://api.crossingedge.com/v1/actions/relearn_writing_profile", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/relearn_writing_profile",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}", "Idempotency-Key": str(uuid.uuid4())},
json={},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/actions/add_writing_sampleAdd writing sample
Teaches the person’s writing profile from an email they wrote, pasted whole (up to 5 kept). Use their own email only, as they sent it.
Body
textstringrequiredAn email the person wrote, whole
curl -X POST "https://api.crossingedge.com/v1/actions/add_writing_sample" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"text": "…"
}'const res = await fetch("https://api.crossingedge.com/v1/actions/add_writing_sample", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
"text": "…"
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/add_writing_sample",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}", "Idempotency-Key": str(uuid.uuid4())},
json={
"text": "…"
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/actions/set_email_signatureSet email signature
The signature added to the end of the person’s drafted replies: text to use word for word (line breaks kept; "" for no signature), or null to go back to the one found at the end of their emails.
Body
textstringrequiredThe signature, or "" for none, or null for the one in their email
curl -X POST "https://api.crossingedge.com/v1/actions/set_email_signature" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"text": "…"
}'const res = await fetch("https://api.crossingedge.com/v1/actions/set_email_signature", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
"text": "…"
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/set_email_signature",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}", "Idempotency-Key": str(uuid.uuid4())},
json={
"text": "…"
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/actions/remove_writing_sampleRemove writing sample
Removes one of the emails the person pasted into their writing profile, by its index from get_writing_profile.
Body
indexnumberrequiredIndex from get_writing_profile
curl -X POST "https://api.crossingedge.com/v1/actions/remove_writing_sample" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"index": 101
}'const res = await fetch("https://api.crossingedge.com/v1/actions/remove_writing_sample", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
"index": 101
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/remove_writing_sample",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}", "Idempotency-Key": str(uuid.uuid4())},
json={
"index": 101
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/actions/forget_writing_profileForget writing profile
Forgets what was learned about how the person writes, and the emails they pasted. It learns again from the next emails they send. Ask the person first, then call with confirm: true.
Body
confirmbooleanrequiredTrue once the person has confirmed
curl -X POST "https://api.crossingedge.com/v1/actions/forget_writing_profile" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"confirm": true
}'const res = await fetch("https://api.crossingedge.com/v1/actions/forget_writing_profile", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
"confirm": true
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/forget_writing_profile",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}", "Idempotency-Key": str(uuid.uuid4())},
json={
"confirm": True
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}Gmail sync
ActionsThe member’s own connected Gmail inboxes and their Review.
/actions/get_gmailGet Gmail
The person’s own connected Gmail inboxes: address, status, last check, problems, how much was brought in, and how many emails wait in each Review. Connecting an inbox needs a Gmail app password, typed in Settings › Email, never in a chat.
curl -X POST "https://api.crossingedge.com/v1/actions/get_gmail" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-d '{}'const res = await fetch("https://api.crossingedge.com/v1/actions/get_gmail", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/get_gmail",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}"},
json={},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/actions/list_gmail_brought_inList emails brought in
Emails Gmail sync brought into the CRM from one of the person’s inboxes: when, which way, why, and the records each was logged on.
Body
inboxstringInbox address or id (optional when there is one)
daysnumberHow many days back (default 7)
curl -X POST "https://api.crossingedge.com/v1/actions/list_gmail_brought_in" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-d '{
"inbox": "…",
"days": 101
}'const res = await fetch("https://api.crossingedge.com/v1/actions/list_gmail_brought_in", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"inbox": "…",
"days": 101
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/list_gmail_brought_in",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}"},
json={
"inbox": "…",
"days": 101
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/actions/set_gmail_statusPause or resume Gmail
Pauses or resumes Gmail sync for one of the person’s inboxes.
Body
inboxstringInbox address or id (optional when there is one)
statusstringrequiredOne of paused active
curl -X POST "https://api.crossingedge.com/v1/actions/set_gmail_status" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"status": "paused"
}'const res = await fetch("https://api.crossingedge.com/v1/actions/set_gmail_status", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
"status": "paused"
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/set_gmail_status",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}", "Idempotency-Key": str(uuid.uuid4())},
json={
"status": "paused"
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/actions/check_gmail_nowCheck Gmail now
Reads new mail in one of the person’s inboxes now, rather than waiting for the next minute.
Body
inboxstringInbox address or id (optional when there is one)
curl -X POST "https://api.crossingedge.com/v1/actions/check_gmail_now" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"inbox": "…"
}'const res = await fetch("https://api.crossingedge.com/v1/actions/check_gmail_now", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
"inbox": "…"
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/check_gmail_now",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}", "Idempotency-Key": str(uuid.uuid4())},
json={
"inbox": "…"
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/actions/disconnect_gmailDisconnect Gmail
Disconnects one of the person’s own inboxes; emails already brought in stay. Ask the person first, then call with confirm: true.
Body
inboxstringInbox address or id (optional when there is one)
confirmbooleanrequiredTrue once the person has confirmed
curl -X POST "https://api.crossingedge.com/v1/actions/disconnect_gmail" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"confirm": true
}'const res = await fetch("https://api.crossingedge.com/v1/actions/disconnect_gmail", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
"confirm": true
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/disconnect_gmail",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}", "Idempotency-Key": str(uuid.uuid4())},
json={
"confirm": True
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/actions/list_team_inboxesList team inboxes
Owners and admins: every member’s connected Gmail inbox (address, status, last check). Never their mail.
curl -X POST "https://api.crossingedge.com/v1/actions/list_team_inboxes" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-d '{}'const res = await fetch("https://api.crossingedge.com/v1/actions/list_team_inboxes", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/list_team_inboxes",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}"},
json={},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/actions/disconnect_team_inboxDisconnect a member’s inbox
Owners and admins: disconnects a member’s Gmail inbox, by its id from list_team_inboxes. Ask the person first, then call with confirm: true.
Body
idstringrequiredInbox id
confirmbooleanrequiredTrue once the person has confirmed
curl -X POST "https://api.crossingedge.com/v1/actions/disconnect_team_inbox" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"id": "101",
"confirm": true
}'const res = await fetch("https://api.crossingedge.com/v1/actions/disconnect_team_inbox", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
"id": "101",
"confirm": true
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/disconnect_team_inbox",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}", "Idempotency-Key": str(uuid.uuid4())},
json={
"id": "101",
"confirm": True
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/actions/list_email_reviewList emails to review
Emails waiting in the person’s own Review page (the ones Jev was unsure about: maybe not sales, maybe private, many people): who, subject, snippet and why. Only ever their own inbox.
Body
inboxstringInbox address or id (optional: all of theirs)
curl -X POST "https://api.crossingedge.com/v1/actions/list_email_review" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-d '{
"inbox": "…"
}'const res = await fetch("https://api.crossingedge.com/v1/actions/list_email_review", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"inbox": "…"
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/list_email_review",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}"},
json={
"inbox": "…"
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/actions/read_review_emailRead email to review
One email waiting in the person’s Review, in full, by its id from list_email_review.
Body
idstringrequiredEmail id
curl -X POST "https://api.crossingedge.com/v1/actions/read_review_email" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-d '{
"id": "101"
}'const res = await fetch("https://api.crossingedge.com/v1/actions/read_review_email", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"id": "101"
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/read_review_email",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}"},
json={
"id": "101"
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/actions/bring_in_review_emailsBring emails into the CRM
Brings emails from the person’s Review into the CRM: logged on the people (and their companies) outside the team, creating contacts where needed. By id from list_email_review.
Body
idsarray of stringrequiredEmail ids
curl -X POST "https://api.crossingedge.com/v1/actions/bring_in_review_emails" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"ids": []
}'const res = await fetch("https://api.crossingedge.com/v1/actions/bring_in_review_emails", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
"ids": []
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/bring_in_review_emails",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}", "Idempotency-Key": str(uuid.uuid4())},
json={
"ids": []
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/actions/dismiss_review_emailsDismiss emails
Dismisses emails from the person’s Review: they never come into the CRM and their copy is deleted. By id from list_email_review. Ask the person first, then call with confirm: true.
Body
idsarray of stringrequiredEmail ids
confirmbooleanrequiredTrue once the person has confirmed
curl -X POST "https://api.crossingedge.com/v1/actions/dismiss_review_emails" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"ids": [],
"confirm": true
}'const res = await fetch("https://api.crossingedge.com/v1/actions/dismiss_review_emails", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
"ids": [],
"confirm": true
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/dismiss_review_emails",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}", "Idempotency-Key": str(uuid.uuid4())},
json={
"ids": [],
"confirm": True
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}Telegram
ActionsTelegram chats, replies and links to records.
/actions/get_telegramGet Telegram
The person’s Telegram in Crossing Edge: the workspace bot, whether their account is linked (and the link to do it), their Business chatbot and personal account, their filters, the groups the bot is in, and how many chats are tracked or waiting. Bot tokens, app keys and phone sign-in stay in Settings › Telegram, never in a chat.
curl -X POST "https://api.crossingedge.com/v1/actions/get_telegram" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-d '{}'const res = await fetch("https://api.crossingedge.com/v1/actions/get_telegram", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/get_telegram",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}"},
json={},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/actions/set_telegram_filtersSet Telegram filters
The person’s own Telegram filters. onlySalesChats: only chats Jev judges to be sales come in (off: every chat). holdPrivateMessages: messages that look private wait for them before they come in (off: everything comes straight in).
Body
onlySalesChatsbooleanOnly sales chats come in
holdPrivateMessagesbooleanPrivate-looking messages wait for you
curl -X POST "https://api.crossingedge.com/v1/actions/set_telegram_filters" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"onlySalesChats": true,
"holdPrivateMessages": true
}'const res = await fetch("https://api.crossingedge.com/v1/actions/set_telegram_filters", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
"onlySalesChats": true,
"holdPrivateMessages": true
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/set_telegram_filters",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}", "Idempotency-Key": str(uuid.uuid4())},
json={
"onlySalesChats": True,
"holdPrivateMessages": True
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/actions/list_telegram_chatsList Telegram chats
Telegram chats brought into Crossing Edge (1:1 Business chats, groups with the workspace bot, personal account chats): people, last message, AI brief, linked records. The workspace’s tracked chats as far as the person can see; mine: true for their own; review: true for their chats waiting on them; ignored: true for ones they ignored; or one record’s.
Body
minebooleanOnly the person’s own chats
qstringSearch
kindstringOne of private group
reviewbooleanTheir chats waiting for them to track or ignore
ignoredbooleanChats they ignored
recordobjectOnly the ones on this record
curl -X POST "https://api.crossingedge.com/v1/actions/list_telegram_chats" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-d '{
"mine": true,
"q": "…"
}'const res = await fetch("https://api.crossingedge.com/v1/actions/list_telegram_chats", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"mine": true,
"q": "…"
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/list_telegram_chats",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}"},
json={
"mine": True,
"q": "…"
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/actions/read_telegram_chatRead Telegram chat
One Telegram chat with its messages, oldest first, and whether the person can reply to it from Crossing Edge (as themselves in a Business chat, or through the workspace bot in a group). Held private messages show only to their owner.
Body
idstringrequiredChat id from list_telegram_chats
curl -X POST "https://api.crossingedge.com/v1/actions/read_telegram_chat" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-d '{
"id": "101"
}'const res = await fetch("https://api.crossingedge.com/v1/actions/read_telegram_chat", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"id": "101"
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/read_telegram_chat",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}"},
json={
"id": "101"
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/actions/reply_telegram_chatReply on Telegram
Replies in one of the person’s own Telegram chats: as them in a Business chat, through the workspace bot (with their name) in a group. It goes to people outside the workspace: show the person the text, then call with confirm: true.
Body
idstringrequiredChat id
textstringrequiredThe message
confirmbooleanrequiredTrue once the person has seen it and said send
curl -X POST "https://api.crossingedge.com/v1/actions/reply_telegram_chat" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"id": "101",
"text": "…",
"confirm": true
}'const res = await fetch("https://api.crossingedge.com/v1/actions/reply_telegram_chat", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
"id": "101",
"text": "…",
"confirm": true
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/reply_telegram_chat",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}", "Idempotency-Key": str(uuid.uuid4())},
json={
"id": "101",
"text": "…",
"confirm": True
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/actions/set_telegram_chat_statusTrack or ignore a Telegram chat
Tracks one of the person’s Telegram chats (its messages come into the CRM) or ignores it (nothing more comes in; it can be tracked again).
Body
idstringrequiredChat id
statusstringrequiredOne of tracked ignored
curl -X POST "https://api.crossingedge.com/v1/actions/set_telegram_chat_status" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"id": "101",
"status": "tracked"
}'const res = await fetch("https://api.crossingedge.com/v1/actions/set_telegram_chat_status", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
"id": "101",
"status": "tracked"
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/set_telegram_chat_status",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}", "Idempotency-Key": str(uuid.uuid4())},
json={
"id": "101",
"status": "tracked"
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/actions/link_telegram_chatLink Telegram chat
Links one of the person’s Telegram chats to a record, so its messages show there: an existing contact, company, deal or workspace record (object + recordId), or a new contact made for someone in the chat (newContact). Linking a contact sets their Telegram handle and source Telegram.
Body
idstringrequiredChat id
objectstringcontacts, companies, deals, or a workspace object id
recordIdnumberRecord id
newContactobjectMake a contact and link it. person: who in the chat (their name, @username or tgUserId; optional in a 1:1 chat)
curl -X POST "https://api.crossingedge.com/v1/actions/link_telegram_chat" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"id": "101"
}'const res = await fetch("https://api.crossingedge.com/v1/actions/link_telegram_chat", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
"id": "101"
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/link_telegram_chat",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}", "Idempotency-Key": str(uuid.uuid4())},
json={
"id": "101"
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/actions/unlink_telegram_chatUnlink Telegram chat
Takes a record off one of the person’s Telegram chats; its messages stop showing there.
Body
idstringrequiredChat id
objectstringrequiredRecord object
recordIdnumberrequiredRecord id
curl -X POST "https://api.crossingedge.com/v1/actions/unlink_telegram_chat" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"id": "101",
"object": "deals",
"recordId": 101
}'const res = await fetch("https://api.crossingedge.com/v1/actions/unlink_telegram_chat", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
"id": "101",
"object": "deals",
"recordId": 101
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/unlink_telegram_chat",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}", "Idempotency-Key": str(uuid.uuid4())},
json={
"id": "101",
"object": "deals",
"recordId": 101
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/actions/settle_held_telegram_messageBring in or dismiss a held message
A message held back as private in one of the person’s chats: bring: true brings it into the CRM, false dismisses it for good. By messageId from read_telegram_chat.
Body
idstringrequiredChat id
messageIdnumberrequiredMessage id
bringbooleanrequiredTrue to bring it in, false to dismiss it
curl -X POST "https://api.crossingedge.com/v1/actions/settle_held_telegram_message" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"id": "101",
"messageId": 101,
"bring": true
}'const res = await fetch("https://api.crossingedge.com/v1/actions/settle_held_telegram_message", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
"id": "101",
"messageId": 101,
"bring": true
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/settle_held_telegram_message",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}", "Idempotency-Key": str(uuid.uuid4())},
json={
"id": "101",
"messageId": 101,
"bring": True
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/actions/list_telegram_connectionsList Telegram connections
Owners and admins: who in the workspace has connected Telegram (linked account, Business chatbot, personal account, groups) and which filters they turned off. Never their chats.
curl -X POST "https://api.crossingedge.com/v1/actions/list_telegram_connections" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-d '{}'const res = await fetch("https://api.crossingedge.com/v1/actions/list_telegram_connections", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/list_telegram_connections",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}"},
json={},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}Webhooks
ActionsIncoming webhooks that bring leads in from forms and tools.
/actions/list_webhooksList webhooks
The workspace’s incoming webhooks: addresses forms and tools post leads to. Each one’s status, address, the fields it has seen, and how many leads came in. Setting one up (mapping its fields) is done in Settings › Integrations › Webhooks.
curl -X POST "https://api.crossingedge.com/v1/actions/list_webhooks" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-d '{}'const res = await fetch("https://api.crossingedge.com/v1/actions/list_webhooks", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/list_webhooks",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}"},
json={},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/actions/get_webhook_logGet webhook log
One webhook’s recent posts, newest first: what each lead said, and whether it made a new contact, updated one, waited, or failed and why.
Body
webhookstringWebhook name or id (optional when there is one)
limitnumberHow many (default 20)
curl -X POST "https://api.crossingedge.com/v1/actions/get_webhook_log" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-d '{
"webhook": "…",
"limit": 20
}'const res = await fetch("https://api.crossingedge.com/v1/actions/get_webhook_log", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"webhook": "…",
"limit": 20
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/get_webhook_log",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}"},
json={
"webhook": "…",
"limit": 20
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/actions/set_webhook_statusPause or resume a webhook
Pauses a webhook (leads wait in its log) or turns it back on (the waiting ones go in).
Body
webhookstringWebhook name or id
statusstringrequiredOne of paused active
curl -X POST "https://api.crossingedge.com/v1/actions/set_webhook_status" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"status": "paused"
}'const res = await fetch("https://api.crossingedge.com/v1/actions/set_webhook_status", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
"status": "paused"
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/set_webhook_status",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}", "Idempotency-Key": str(uuid.uuid4())},
json={
"status": "paused"
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/actions/create_webhookCreate webhook
Makes a new webhook: an address a form or tool posts leads to. It starts out listening: posts are kept as tests and nothing is written. Give the person the address to paste into their tool, ask them to send one lead, then call map_webhook.
Body
namestringrequiredWhere the leads come from, like “Website form”. New contacts get it as their source.
curl -X POST "https://api.crossingedge.com/v1/actions/create_webhook" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"name": "Acme"
}'const res = await fetch("https://api.crossingedge.com/v1/actions/create_webhook", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
"name": "Acme"
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/create_webhook",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}", "Idempotency-Key": str(uuid.uuid4())},
json={
"name": "Acme"
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/actions/map_webhookMap and turn on a webhook
Maps a webhook’s fields (from the tests it has received) onto contact and company fields, sets values every lead gets, and turns it on; on a live one it saves the change. Fields not given are matched by AI, as an import’s columns are. Leads arrive unassigned and the workspace’s automations always run on them: assign leads with an automation on new contacts (create_automation, owner step).
Body
webhookstringrequiredWebhook name or id
fieldsobjectPayload field (as list_webhooks shows it, e.g. "lead.email") → "contacts:email", "Contact · Email", "skip", or "new:Budget" for a new contact field. Unlisted fields are matched by AI.
valuesarray of objectValues every lead gets. Defaults to the source set to the webhook’s name.
onExistingstringA contact already in the CRM (same email or phone): fill its blanks (default), overwrite, or leave it
One of fill overwrite skip
companyFromDomainbooleanFind or add the company from a work email (default true; free mail never makes one)
namestringA new name for it
curl -X POST "https://api.crossingedge.com/v1/actions/map_webhook" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"webhook": "…"
}'const res = await fetch("https://api.crossingedge.com/v1/actions/map_webhook", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
"webhook": "…"
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/map_webhook",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}", "Idempotency-Key": str(uuid.uuid4())},
json={
"webhook": "…"
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/actions/preview_webhookPreview a webhook lead
What a webhook’s latest post would become, written nowhere: the fields it would set, the contact it would update (same email or phone), the company its email finds or makes, and the automations that run.
Body
webhookstringWebhook name or id
curl -X POST "https://api.crossingedge.com/v1/actions/preview_webhook" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-d '{
"webhook": "…"
}'const res = await fetch("https://api.crossingedge.com/v1/actions/preview_webhook", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"webhook": "…"
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/preview_webhook",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}"},
json={
"webhook": "…"
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/actions/run_webhook_post_againRun a webhook post again
Runs one post from a webhook’s log again (one that failed, waited while paused, or was a test), by its id from get_webhook_log.
Body
webhookstringWebhook name or id
poststringrequiredPost id from get_webhook_log
curl -X POST "https://api.crossingedge.com/v1/actions/run_webhook_post_again" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"post": "…"
}'const res = await fetch("https://api.crossingedge.com/v1/actions/run_webhook_post_again", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
"post": "…"
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/run_webhook_post_again",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}", "Idempotency-Key": str(uuid.uuid4())},
json={
"post": "…"
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/actions/new_webhook_addressNew webhook address
Gives a webhook a new address; the old one stops working at once, so the tool must be given the new one. Ask the person first, then call with confirm: true.
Body
webhookstringWebhook name or id
confirmbooleanrequiredTrue once the person has confirmed
curl -X POST "https://api.crossingedge.com/v1/actions/new_webhook_address" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"confirm": true
}'const res = await fetch("https://api.crossingedge.com/v1/actions/new_webhook_address", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
"confirm": true
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/new_webhook_address",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}", "Idempotency-Key": str(uuid.uuid4())},
json={
"confirm": True
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/actions/delete_webhookDelete webhook
Deletes a webhook: its address stops working and its log goes. Contacts it brought in stay. Ask the person first, then call with confirm: true.
Body
webhookstringrequiredWebhook name or id
confirmbooleanrequiredTrue once the person has confirmed
curl -X POST "https://api.crossingedge.com/v1/actions/delete_webhook" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"webhook": "…",
"confirm": true
}'const res = await fetch("https://api.crossingedge.com/v1/actions/delete_webhook", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
"webhook": "…",
"confirm": true
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/delete_webhook",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}", "Idempotency-Key": str(uuid.uuid4())},
json={
"webhook": "…",
"confirm": True
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}IndiaMART
ActionsIndiaMART enquiries arriving as leads.
/actions/get_indiamartGet IndiaMART
How IndiaMART is connected: status, the key (last 4 only), the webhook address, what each enquiry becomes (mapping, values every lead gets, deal, call task), who gets each lead, and counts. IndiaMART fields: SENDER_NAME (Buyer name), SENDER_MOBILE (Mobile), SENDER_EMAIL (Email), SENDER_COMPANY (Buyer company), SENDER_CITY (City), SENDER_STATE (State), SENDER_PINCODE (Pincode), SENDER_COUNTRY_ISO (Country), SENDER_ADDRESS (Address), SUBJECT (Enquiry subject), QUERY_PRODUCT_NAME (Product), QUERY_MESSAGE (Message), QUERY_MCAT_NAME (Category), QUERY_TYPE (Enquiry type), QUERY_TIME (Enquired at), RECEIVER_MOBILE (Received on), CALL_DURATION (Call duration), SENDER_MOBILE_ALT (Alternate mobile), SENDER_PHONE (Landline), SENDER_PHONE_ALT (Alternate landline), SENDER_EMAIL_ALT (Alternate email), UNIQUE_QUERY_ID (Enquiry ID). Enquiry types: Direct enquiry, Buy lead, Phone call, Catalogue view, WhatsApp enquiry.
curl -X POST "https://api.crossingedge.com/v1/actions/get_indiamart" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-d '{}'const res = await fetch("https://api.crossingedge.com/v1/actions/get_indiamart", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/get_indiamart",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}"},
json={},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/actions/list_indiamart_enquiriesList IndiaMART enquiries
The latest IndiaMART enquiries and what each became: a new lead, updated, already in the CRM, failed (with why) or waiting. Newest first.
Body
limitnumberHow many (default 20, up to 200)
resultstringOnly this result
One of created updated skipped failed held
curl -X POST "https://api.crossingedge.com/v1/actions/list_indiamart_enquiries" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-d '{
"limit": 20,
"result": "created"
}'const res = await fetch("https://api.crossingedge.com/v1/actions/list_indiamart_enquiries", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"limit": 20,
"result": "created"
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/list_indiamart_enquiries",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}"},
json={
"limit": 20,
"result": "created"
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/actions/connect_indiamartConnect IndiaMART
Connects IndiaMART, or replaces its CRM key. With a key (from IndiaMART Lead Manager › ⋮ › Import/Export Leads › Pull API) IndiaMART is checked at once and the answer says how many enquiries the last day had; with no key it connects for the webhook only. A new connection then needs update_indiamart to go live.
Body
keystringThe CRM key, when the person gave one
curl -X POST "https://api.crossingedge.com/v1/actions/connect_indiamart" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"key": "…"
}'const res = await fetch("https://api.crossingedge.com/v1/actions/connect_indiamart", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
"key": "…"
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/connect_indiamart",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}", "Idempotency-Key": str(uuid.uuid4())},
json={
"key": "…"
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/actions/update_indiamartUpdate IndiaMART
Changes what IndiaMART enquiries become and who gets them, and switches a new connection on. Pass only what changes; the rest stays. - map: { IndiaMART field: "object:field" | "skip" | { new: { object, label, type } } }, e.g. { "QUERY_PRODUCT_NAME": "contacts:note", "QUERY_MCAT_NAME": { "new": { "object": "contacts", "label": "Category", "type": "singleSelect" } } }. - everyLeadGets: [{ field: "contacts:source", value: "IndiaMART" }] replaces the list. - owners: { mode: "none" } | { mode: "one", member } | { mode: "rotate", members: [...] } | { mode: "rules", rules: [{ when: [{ field: "SENDER_CITY", op: "is", value: "Mumbai, Pune" }], to: [...] }], fallback: [...] }. Members by email or name. Rule fields: SENDER_CITY, SENDER_STATE, SENDER_PINCODE, SENDER_COUNTRY_ISO, QUERY_PRODUCT_NAME, QUERY_MCAT_NAME, QUERY_TYPE, SUBJECT, QUERY_MESSAGE, SENDER_COMPANY, RECEIVER_MOBILE; ops: is, isNot, contains, startsWith; a comma list means any of. - deal: { on, pipelineId, stage }; callTask: { on, dueMinutes }; existingRecords: fill | overwrite | skip; automations: true/false. - pastDays (7, 30, 90 or 365): also bring in past enquiries, once. IndiaMART fields: SENDER_NAME (Buyer name), SENDER_MOBILE (Mobile), SENDER_EMAIL (Email), SENDER_COMPANY (Buyer company), SENDER_CITY (City), SENDER_STATE (State), SENDER_PINCODE (Pincode), SENDER_COUNTRY_ISO (Country), SENDER_ADDRESS (Address), SUBJECT (Enquiry subject), QUERY_PRODUCT_NAME (Product), QUERY_MESSAGE (Message), QUERY_MCAT_NAME (Category), QUERY_TYPE (Enquiry type), QUERY_TIME (Enquired at), RECEIVER_MOBILE (Received on), CALL_DURATION (Call duration), SENDER_MOBILE_ALT (Alternate mobile), SENDER_PHONE (Landline), SENDER_PHONE_ALT (Alternate landline), SENDER_EMAIL_ALT (Alternate email), UNIQUE_QUERY_ID (Enquiry ID). Enquiry types: Direct enquiry, Buy lead, Phone call, Catalogue view, WhatsApp enquiry.
Body
mapobjectIndiaMART field → target
everyLeadGetsarray of objectValues every lead gets
ownersobjectWho gets each lead
dealobject{ on, pipelineId, stage }
callTaskobject{ on, dueMinutes }
existingRecordsstringOne of fill overwrite skip
automationsbooleanRun automations on each lead
pastDaysnumber7, 30, 90 or 365
curl -X POST "https://api.crossingedge.com/v1/actions/update_indiamart" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"map": {},
"everyLeadGets": []
}'const res = await fetch("https://api.crossingedge.com/v1/actions/update_indiamart", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
"map": {},
"everyLeadGets": []
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/update_indiamart",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}", "Idempotency-Key": str(uuid.uuid4())},
json={
"map": {},
"everyLeadGets": []
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/actions/set_indiamart_statusPause or resume IndiaMART
Pauses IndiaMART (enquiries sent by webhook are held and come in on resume) or resumes it.
Body
statusstringrequiredOne of paused active
curl -X POST "https://api.crossingedge.com/v1/actions/set_indiamart_status" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"status": "paused"
}'const res = await fetch("https://api.crossingedge.com/v1/actions/set_indiamart_status", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
"status": "paused"
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/set_indiamart_status",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}", "Idempotency-Key": str(uuid.uuid4())},
json={
"status": "paused"
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/actions/check_indiamart_nowCheck IndiaMART now
Asks IndiaMART for new enquiries now. IndiaMART allows one check every 5 minutes; if it is too soon, the answer says when the next one is allowed.
curl -X POST "https://api.crossingedge.com/v1/actions/check_indiamart_now" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{}'const res = await fetch("https://api.crossingedge.com/v1/actions/check_indiamart_now", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/check_indiamart_now",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}", "Idempotency-Key": str(uuid.uuid4())},
json={},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/actions/retry_indiamart_enquiryRetry IndiaMART enquiry
Takes a failed or waiting IndiaMART enquiry again, by its id from list_indiamart_enquiries.
Body
idstringrequiredEnquiry id
curl -X POST "https://api.crossingedge.com/v1/actions/retry_indiamart_enquiry" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"id": "101"
}'const res = await fetch("https://api.crossingedge.com/v1/actions/retry_indiamart_enquiry", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
"id": "101"
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/retry_indiamart_enquiry",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}", "Idempotency-Key": str(uuid.uuid4())},
json={
"id": "101"
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/actions/new_indiamart_webhookNew IndiaMART webhook address
Makes a new webhook address for IndiaMART; the old one stops working at once, so the new one must be pasted into IndiaMART’s Push API page. For an address shared by mistake. Ask the person first, then call with confirm: true.
Body
confirmbooleanrequiredTrue once the person has confirmed
curl -X POST "https://api.crossingedge.com/v1/actions/new_indiamart_webhook" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"confirm": true
}'const res = await fetch("https://api.crossingedge.com/v1/actions/new_indiamart_webhook", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
"confirm": true
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/new_indiamart_webhook",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}", "Idempotency-Key": str(uuid.uuid4())},
json={
"confirm": True
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/actions/disconnect_indiamartDisconnect IndiaMART
Disconnects IndiaMART: the key, mapping, owners and enquiry log go; leads already made stay. Ask the person first, then call with confirm: true.
Body
confirmbooleanrequiredTrue once the person has confirmed
curl -X POST "https://api.crossingedge.com/v1/actions/disconnect_indiamart" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"confirm": true
}'const res = await fetch("https://api.crossingedge.com/v1/actions/disconnect_indiamart", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
"confirm": true
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/disconnect_indiamart",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}", "Idempotency-Key": str(uuid.uuid4())},
json={
"confirm": True
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}Events
ActionsEvent mode: who was met at a conference or trade fair.
/actions/list_eventsList events
The workspace’s events in event mode (conferences, trade fairs), running ones first: their lead source, how many people were captured at each by you and in total, and the link to the capture page.
curl -X POST "https://api.crossingedge.com/v1/actions/list_events" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-d '{}'const res = await fetch("https://api.crossingedge.com/v1/actions/list_events", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/list_events",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}"},
json={},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/actions/get_eventGet event
One event and everyone captured at it: who, who captured them, how (QR, card photo or typed) and when, newest first. Use it for "who did we meet at TOKEN2049".
Body
eventstringrequiredEvent name or id
curl -X POST "https://api.crossingedge.com/v1/actions/get_event" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-d '{
"event": "…"
}'const res = await fetch("https://api.crossingedge.com/v1/actions/get_event", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"event": "…"
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/get_event",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}"},
json={
"event": "…"
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/actions/create_eventCreate event
Starts an event in event mode and returns its capture-page link (open it on a phone to scan QR codes and cards). source is the lead source captures start on: one of the choices get_schema lists for contacts.source, or a new one with addSource: true (owners and admins).
Body
namestringrequiredEvent name, e.g. TOKEN2049
sourcestringLead source captures start on
addSourcebooleanAdd source as a new lead source choice first
curl -X POST "https://api.crossingedge.com/v1/actions/create_event" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"name": "Acme"
}'const res = await fetch("https://api.crossingedge.com/v1/actions/create_event", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
"name": "Acme"
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/create_event",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}", "Idempotency-Key": str(uuid.uuid4())},
json={
"name": "Acme"
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/actions/end_eventEnd event
Ends an event so its link stops capturing, or reopens it with reopen: true. Whoever started it, or an owner or admin.
Body
eventstringrequiredEvent name or id
reopenbooleanReopen an ended event
curl -X POST "https://api.crossingedge.com/v1/actions/end_event" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"event": "…"
}'const res = await fetch("https://api.crossingedge.com/v1/actions/end_event", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
"event": "…"
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/end_event",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}", "Idempotency-Key": str(uuid.uuid4())},
json={
"event": "…"
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/actions/capture_at_eventCapture at event
Adds someone met at an event: either an existing contact (contactId), or a new lead from their details, owned by you and on the event’s source. Either way they are counted at the event and get a “Met at …” note. A new lead needs a first name and an email, a phone, or a Telegram handle (someone known only by their Telegram handle is matched when they message).
Body
eventstringrequiredEvent name or id
contactIdnumberAn existing contact, instead of new details
firstNamestringFirst name
lastNamestringLast name
emailstringphonestringPhone
jobTitlestringJob title
companyIdnumberTheir company, if already in the CRM
telegramstringTelegram handle, without the @
xstringX (Twitter) handle, without the @
linkedinstringLinkedIn profile URL
notestringAnything else worth keeping, added to the note
methodstringHow they were captured; default typed
One of qr photo typed
curl -X POST "https://api.crossingedge.com/v1/actions/capture_at_event" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"event": "…"
}'const res = await fetch("https://api.crossingedge.com/v1/actions/capture_at_event", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
"event": "…"
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/capture_at_event",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}", "Idempotency-Key": str(uuid.uuid4())},
json={
"event": "…"
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}Exports
ActionsSpreadsheets of records.
/actions/export_recordsExport records
Exports records as a spreadsheet and returns a download link (kept 7 days). One object gives a CSV; several give a zip with one CSV per object. Give record ids to export only those (search_records or search_contacts finds them), and field keys from get_schema to choose columns; otherwise every record the person can see, with every field. Calculated fields are left out. Needs the Export records permission; every export is logged.
Body
objectsarray of objectrequiredWhat to export, one entry per object
curl -X POST "https://api.crossingedge.com/v1/actions/export_records" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-d '{
"objects": []
}'const res = await fetch("https://api.crossingedge.com/v1/actions/export_records", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"objects": []
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/export_records",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}"},
json={
"objects": []
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}Reports and schema
ActionsReports, the workspace schema and queries.
/actions/report_guideReport guide
How reports work: the sandboxed runtime, window.crossingEdge, the query language, making a dashboard interactive (drill-downs, filters, tabs, dialogs) and the house style. Read this before building.
curl -X POST "https://api.crossingedge.com/v1/actions/report_guide" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-d '{}'const res = await fetch("https://api.crossingedge.com/v1/actions/report_guide", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/report_guide",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}"},
json={},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/actions/get_schemaGet schema
The workspace data model: every object and field (with types and choices), pipelines and stages, members, currency and today’s date.
curl -X POST "https://api.crossingedge.com/v1/actions/get_schema" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-d '{}'const res = await fetch("https://api.crossingedge.com/v1/actions/get_schema", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/get_schema",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}"},
json={},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/actions/run_queryRun query
Runs one report query and returns the answer, exactly as a report would get it. Use it to check numbers before publishing.
Body
queryobjectrequiredA report query. See report_guide for the full language.
curl -X POST "https://api.crossingedge.com/v1/actions/run_query" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-d '{
"query": {}
}'const res = await fetch("https://api.crossingedge.com/v1/actions/run_query", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"query": {}
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/run_query",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}"},
json={
"query": {}
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/actions/list_reportsList reports
Reports in the workspace this person can see: their own and the shared ones.
curl -X POST "https://api.crossingedge.com/v1/actions/list_reports" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-d '{}'const res = await fetch("https://api.crossingedge.com/v1/actions/list_reports", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/list_reports",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}"},
json={},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/actions/get_reportGet report
One report with its full HTML, to read or change it.
Body
idstringrequiredReport id
curl -X POST "https://api.crossingedge.com/v1/actions/get_report" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-d '{
"id": "101"
}'const res = await fetch("https://api.crossingedge.com/v1/actions/get_report", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"id": "101"
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/get_report",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}"},
json={
"id": "101"
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/actions/check_reportCheck report
Checks a native report spec and works out every figure on it for a period and the one before, exactly as the page will show them. Run it before create_report and read the numbers back.
Body
specobjectrequiredThe report spec (see report_guide)
periodobject{ kind: week | month | quarter | year | custom, year?, quarter?, from?, to? }. Default: the spec’s, else this month
pipelinestringA pipeline name, as the pipeline picker would set it
filtersarray of objectFilter bar filters on the spec’s object
curl -X POST "https://api.crossingedge.com/v1/actions/check_report" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-d '{
"spec": {}
}'const res = await fetch("https://api.crossingedge.com/v1/actions/check_report", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"spec": {}
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/check_report",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}"},
json={
"spec": {}
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/actions/create_reportCreate report
Publishes a new report into Crossing Edge. Returns its URL. Private to its author unless shared is true. Prefer a native report (spec): the app draws it with Insights’ own pieces. Use html only for what a spec cannot draw.
Body
namestringrequiredShort title, e.g. "Pipeline health"
descriptionstringOne line on what it answers
specobjectA native report spec (see report_guide). Check it with check_report first
htmlstringInstead of a spec: the complete, self-contained HTML page
sharedbooleanShow it to everyone in the workspace (each sees only their own data access)
curl -X POST "https://api.crossingedge.com/v1/actions/create_report" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"name": "Acme"
}'const res = await fetch("https://api.crossingedge.com/v1/actions/create_report", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
"name": "Acme"
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/create_report",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}", "Idempotency-Key": str(uuid.uuid4())},
json={
"name": "Acme"
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}/actions/update_reportUpdate report
Changes a report: any of its name, description, spec, HTML or sharing. Only its author, an owner or an admin can. A spec replaces HTML and the other way round. To change part of an HTML report, send edits rather than the whole page: read it with get_report, then give each piece of text to find (copied exactly, appearing once) and what replaces it. A long page written out in full may not fit in one reply.
Body
idstringrequiredReport id
namestringNew title
descriptionstringNew description
specobjectThe complete new spec
htmlstringThe complete new HTML
editsarray of objectChanges to part of the HTML page, applied in order: each find is exact text from the current page that appears once, replaced by replace
sharedbooleancurl -X POST "https://api.crossingedge.com/v1/actions/update_report" \
-H "Authorization: Bearer $CROSSING_EDGE_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"id": "101"
}'const res = await fetch("https://api.crossingedge.com/v1/actions/update_report", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CROSSING_EDGE_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
"id": "101"
}),
});
const { data, error } = await res.json();import os, uuid, requests
res = requests.post(
"https://api.crossingedge.com/v1/actions/update_report",
headers={"Authorization": f"Bearer {os.environ['CROSSING_EDGE_KEY']}", "Idempotency-Key": str(uuid.uuid4())},
json={
"id": "101"
},
)
data = res.json()["data"]{
"data": {
"id": 101,
"…": "…"
},
"request_id": "req_7c1f0e2a9b4d"
}