CRM
Contacts, companies, static lists, tasks and the per-contact conversation view.
30 endpoints· 13 called live· 17 not exercised here· verified against http://127.0.0.1:8741
30 endpoints
GET/api/v1/salesshift/companiesCalled livePaged, searchable list of company records, each with its contact count.
Query parameters
| Name | Type | Required | Notes |
|---|---|---|---|
| page | integer | optional | Default 1. min 1. |
| limit | integer | optional | Default 25. min 1. max 100. |
| search | string? | optional | |
| sort_by | string | optional | Default "created_at". |
| sort_order | string | optional | Default "desc". |
Request
curl 'https://api.vxcloud.io/api/v1/salesshift/companies' \
-H "Authorization: Bearer $SS_TOKEN"Response · 200
{
"success": "bool",
"data": [
{
"name": "str",
"domain": "str",
"industry": "str",
"employee_count": "int",
"annual_revenue": "null",
"city": "str",
"state_province": "null",
"country": "str",
"website": "null",
"linkedin_url": "null",
"tags": [
"<empty list>"
],
"custom_fields": {},
"id": "str",
"organization_id": "str",
"created_at": "str",
"updated_at": "str",
"contact_count": "int"
},
"...x1"
],
"pagination": {
"total": "int",
"page": "int",
"limit": "int",
"total_pages": "int"
}
}POST/api/v1/salesshift/companiesNot exercised hereCreate a company record owned by the calling user.
Request body (required) — CompanyCreate
| Field | Type | Required | Notes |
|---|---|---|---|
| name | string | required | |
| domain | string? | optional | |
| industry | string? | optional | |
| employee_count | integer? | optional | |
| annual_revenue | number? | optional | |
| city | string? | optional | |
| state_province | string? | optional | |
| country | string? | optional | |
| website | string? | optional | |
| linkedin_url | string? | optional | |
| tags | string[] | optional | |
| custom_fields | object | optional |
Values in the request below are typed placeholders, not sample data.
Request
curl -X POST 'https://api.vxcloud.io/api/v1/salesshift/companies' \
-H "Authorization: Bearer $SS_TOKEN" \
-H 'Content-Type: application/json' \
-d '{ "name": "<string>", "domain": "<string>", "industry": "<string>", "employee_count": 0, "annual_revenue": 0, "city": "<string>", "state_province": "<string>", "country": "<string>", "website": "<string>", "linkedin_url": "<string>", "tags": [ "<string>" ], "custom_fields": {} }'Response · 201
{
"name": "string",
"domain": "string?",
"industry": "string?",
"employee_count": "integer?",
"annual_revenue": "number?",
"city": "string?",
"state_province": "string?",
"country": "string?",
"website": "string?",
"linkedin_url": "string?",
"tags": "string[]",
"custom_fields": "object",
"id": "string(uuid)",
"organization_id": "string(uuid)",
"created_at": "string(date-time)",
"updated_at": "string(date-time)"
}PUT/api/v1/salesshift/companies/{company_id}Not exercised hereUpdate a company record from a partial payload.
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
| company_id | string(uuid) | required |
Request body (required) — CompanyUpdate
| Field | Type | Required | Notes |
|---|---|---|---|
| name | string? | optional | |
| domain | string? | optional | |
| industry | string? | optional | |
| employee_count | integer? | optional | |
| annual_revenue | number? | optional | |
| city | string? | optional | |
| state_province | string? | optional | |
| country | string? | optional | |
| website | string? | optional | |
| linkedin_url | string? | optional | |
| tags | string[]? | optional | |
| custom_fields | object? | optional |
Values in the request below are typed placeholders, not sample data.
Request
curl -X PUT 'https://api.vxcloud.io/api/v1/salesshift/companies/{company_id}' \
-H "Authorization: Bearer $SS_TOKEN" \
-H 'Content-Type: application/json' \
-d '{ "name": "<string>", "domain": "<string>", "industry": "<string>", "employee_count": 0, "annual_revenue": 0, "city": "<string>", "state_province": "<string>", "country": "<string>", "website": "<string>", "linkedin_url": "<string>", "tags": [ "<string>" ], "custom_fields": {} }'Response · 200
{
"name": "string",
"domain": "string?",
"industry": "string?",
"employee_count": "integer?",
"annual_revenue": "number?",
"city": "string?",
"state_province": "string?",
"country": "string?",
"website": "string?",
"linkedin_url": "string?",
"tags": "string[]",
"custom_fields": "object",
"id": "string(uuid)",
"organization_id": "string(uuid)",
"created_at": "string(date-time)",
"updated_at": "string(date-time)"
}Errors
| Status | detail |
|---|---|
| 404 | Company not found |
DELETE/api/v1/salesshift/companies/{company_id}Not exercised hereDelete a company record.
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
| company_id | string(uuid) | required |
Request
curl -X DELETE 'https://api.vxcloud.io/api/v1/salesshift/companies/{company_id}' \
-H "Authorization: Bearer $SS_TOKEN"Response · 200
{
"success": "…"
}Errors
| Status | detail |
|---|---|
| 404 | Company not found |
GET/api/v1/salesshift/contactsCalled livePaged, filterable list of the organization's contacts.
Query parameters
| Name | Type | Required | Notes |
|---|---|---|---|
| page | integer | optional | Default 1. min 1. |
| limit | integer | optional | Default 25. min 1. max 100. |
| search | string? | optional | |
| lifecycle_stage | string? | optional | |
| company_id | string(uuid)? | optional | |
| min_score | integer? | optional | |
| job_title | string[]? | optional | |
| email_status | string? | optional | Matches ^(has_email|unsubscribed)$. |
| created_after | string(date-time)? | optional | |
| list_id | string(uuid)? | optional | |
| in_list | boolean? | optional | |
| sort_by | string | optional | Default "created_at". |
| sort_order | string | optional | Default "desc". |
Request
curl 'https://api.vxcloud.io/api/v1/salesshift/contacts' \
-H "Authorization: Bearer $SS_TOKEN"Response · 200
{
"success": "bool",
"data": [
{
"id": "str",
"organization_id": "str",
"first_name": "str",
"last_name": "str",
"email": "str",
"phone": "null",
"company_id": "null",
"company_name": "null",
"job_title": "null",
"seniority": "null",
"linkedin_url": "null",
"city": "null",
"country": "null",
"timezone": "null",
"source": "null",
"status": "str",
"lifecycle_stage": "str",
"fit_score": "int",
"intent_score": "int",
"total_score": "int",
"last_contacted": "null",
"last_activity": "null",
"emails_sent_count": "int",
"email_opens_count": "int",
"emails_replied_count": "int",
"enrichment_status": "str",
"enrichment_providers": "null",
"enrichment_data": "null",
"tags": "null",
"custom_fields": "null",
"email_subscribed": "bool",
"created_at": "str",
"updated_at": "str"
},
"...x2"
],
"pagination": {
"total": "int",
"page": "int",
"limit": "int",
"total_pages": "int"
}
}POST/api/v1/salesshift/contactsNot exercised hereCreate a contact; an existing contact with the same email in the org is returned instead of a duplicate.
Request body (required) — ContactCreate
| Field | Type | Required | Notes |
|---|---|---|---|
| first_name | string? | optional | |
| last_name | string? | optional | |
| string? | optional | ||
| phone | string? | optional | |
| company_id | string(uuid)? | optional | |
| company_name | string? | optional | |
| job_title | string? | optional | |
| seniority | string? | optional | |
| linkedin_url | string? | optional | |
| city | string? | optional | |
| country | string? | optional | |
| timezone | string? | optional | |
| source | string? | optional | |
| lifecycle_stage | string | optional | Default "lead". |
| tags | string[] | optional | |
| custom_fields | object | optional |
Values in the request below are typed placeholders, not sample data.
Request
curl -X POST 'https://api.vxcloud.io/api/v1/salesshift/contacts' \
-H "Authorization: Bearer $SS_TOKEN" \
-H 'Content-Type: application/json' \
-d '{ "first_name": "<string>", "last_name": "<string>", "email": "<string>", "phone": "<string>", "company_id": "<string(uuid)>", "company_name": "<string>", "job_title": "<string>", "seniority": "<string>", "linkedin_url": "<string>", "city": "<string>", "country": "<string>", "timezone": "<string>", "source": "<string>", "lifecycle_stage": "lead", "tags": [ "<string>" ], "custom_fields": {} }'Response · 201
{
"id": "string(uuid)",
"organization_id": "string(uuid)",
"first_name": "string?",
"last_name": "string?",
"email": "string?",
"phone": "string?",
"company_id": "string(uuid)?",
"company_name": "string?",
"job_title": "string?",
"seniority": "string?",
"linkedin_url": "string?",
"city": "string?",
"country": "string?",
"timezone": "string?",
"source": "string?",
"status": "string",
"lifecycle_stage": "string",
"fit_score": "integer",
"intent_score": "integer",
"total_score": "integer",
"last_contacted": "string(date-time)?",
"last_activity": "string(date-time)?",
"emails_sent_count": "integer",
"email_opens_count": "integer",
"emails_replied_count": "integer",
"enrichment_status": "string",
"enrichment_providers": "string[]?",
"enrichment_data": "object?",
"tags": "string[]?",
"custom_fields": "object?",
"email_subscribed": "boolean",
"created_at": "string(date-time)",
"updated_at": "string(date-time)"
}Errors
| Status | detail |
|---|---|
| 409 | Contact with email {...} already exists |
| 402 | computed at runtime: # entitlements.assert_contact_headroom
detail = (
f"{ent.plan_name} stores up to {ent.contacts:,} contacts and this "
f"workspace has {current:,}. Upgrade to add more, or remove "
f"contacts you no longer need."
) |
GET/api/v1/salesshift/contacts/{contact_id}Called liveOne contact by id, scoped to the caller's organization.
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
| contact_id | string(uuid) | required |
Request
curl 'https://api.vxcloud.io/api/v1/salesshift/contacts/{contact_id}' \
-H "Authorization: Bearer $SS_TOKEN"Response · 200
{
"id": "str",
"organization_id": "str",
"first_name": "str",
"last_name": "str",
"email": "str",
"phone": "null",
"company_id": "null",
"company_name": "null",
"job_title": "null",
"seniority": "null",
"linkedin_url": "null",
"city": "null",
"country": "null",
"timezone": "null",
"source": "null",
"status": "str",
"lifecycle_stage": "str",
"fit_score": "int",
"intent_score": "int",
"total_score": "int",
"last_contacted": "null",
"last_activity": "null",
"emails_sent_count": "int",
"email_opens_count": "int",
"emails_replied_count": "int",
"enrichment_status": "str",
"enrichment_providers": "null",
"enrichment_data": "null",
"tags": "null",
"custom_fields": "null",
"email_subscribed": "bool",
"created_at": "str",
"updated_at": "str"
}Errors
| Status | detail |
|---|---|
| 404 | Contact not found |
PUT/api/v1/salesshift/contacts/{contact_id}Not exercised hereUpdate a contact from a partial payload (unset fields are left alone).
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
| contact_id | string(uuid) | required |
Request body (required) — ContactUpdate
| Field | Type | Required | Notes |
|---|---|---|---|
| first_name | string? | optional | |
| last_name | string? | optional | |
| string? | optional | ||
| phone | string? | optional | |
| company_id | string(uuid)? | optional | |
| company_name | string? | optional | |
| job_title | string? | optional | |
| seniority | string? | optional | |
| linkedin_url | string? | optional | |
| city | string? | optional | |
| country | string? | optional | |
| timezone | string? | optional | |
| source | string? | optional | |
| status | string? | optional | |
| lifecycle_stage | string? | optional | |
| tags | string[]? | optional | |
| custom_fields | object? | optional | |
| email_subscribed | boolean? | optional |
Values in the request below are typed placeholders, not sample data.
Request
curl -X PUT 'https://api.vxcloud.io/api/v1/salesshift/contacts/{contact_id}' \
-H "Authorization: Bearer $SS_TOKEN" \
-H 'Content-Type: application/json' \
-d '{ "first_name": "<string>", "last_name": "<string>", "email": "<string>", "phone": "<string>", "company_id": "<string(uuid)>", "company_name": "<string>", "job_title": "<string>", "seniority": "<string>", "linkedin_url": "<string>", "city": "<string>", "country": "<string>", "timezone": "<string>", "source": "<string>", "status": "<string>", "lifecycle_stage": "<string>", "tags": [ "<string>" ], "custom_fields": {}, "email_subscribed": false }'Response · 200
{
"id": "string(uuid)",
"organization_id": "string(uuid)",
"first_name": "string?",
"last_name": "string?",
"email": "string?",
"phone": "string?",
"company_id": "string(uuid)?",
"company_name": "string?",
"job_title": "string?",
"seniority": "string?",
"linkedin_url": "string?",
"city": "string?",
"country": "string?",
"timezone": "string?",
"source": "string?",
"status": "string",
"lifecycle_stage": "string",
"fit_score": "integer",
"intent_score": "integer",
"total_score": "integer",
"last_contacted": "string(date-time)?",
"last_activity": "string(date-time)?",
"emails_sent_count": "integer",
"email_opens_count": "integer",
"emails_replied_count": "integer",
"enrichment_status": "string",
"enrichment_providers": "string[]?",
"enrichment_data": "object?",
"tags": "string[]?",
"custom_fields": "object?",
"email_subscribed": "boolean",
"created_at": "string(date-time)",
"updated_at": "string(date-time)"
}Errors
| Status | detail |
|---|---|
| 404 | Contact not found |
DELETE/api/v1/salesshift/contacts/{contact_id}Not exercised hereDelete a contact and its dependent bookings, deals, email-tracking and form-submission rows.
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
| contact_id | string(uuid) | required |
Request
curl -X DELETE 'https://api.vxcloud.io/api/v1/salesshift/contacts/{contact_id}' \
-H "Authorization: Bearer $SS_TOKEN"Response · 200
{
"success": "…"
}Errors
| Status | detail |
|---|---|
| 404 | Contact not found |
GET/api/v1/salesshift/contacts/{contact_id}/activitiesCalled liveThe 100 most recent activity rows recorded against a contact.
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
| contact_id | string(uuid) | required |
Request
curl 'https://api.vxcloud.io/api/v1/salesshift/contacts/{contact_id}/activities' \
-H "Authorization: Bearer $SS_TOKEN"Response · 200
{
"success": "bool",
"data": [
"<empty list>"
]
}GET/api/v1/salesshift/contacts/{contact_id}/enrollmentsCalled liveSequences this contact is (or was) enrolled in — powers the Sequences tab on the contact profile.
Sequences this contact is (or was) enrolled in — powers the Sequences tab on the contact profile.
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
| contact_id | string(uuid) | required |
Request
curl 'https://api.vxcloud.io/api/v1/salesshift/contacts/{contact_id}/enrollments' \
-H "Authorization: Bearer $SS_TOKEN"Response · 200
{
"success": "bool",
"data": [
"<empty list>"
]
}GET/api/v1/salesshift/contacts/{contact_id}/listsCalled liveThe lists this contact actually belongs to — the profile used to print the organization's list count in that row, which is a different number.
The lists this contact actually belongs to — the profile used to print the organization's list count in that row, which is a different number.
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
| contact_id | string(uuid) | required |
Request
curl 'https://api.vxcloud.io/api/v1/salesshift/contacts/{contact_id}/lists' \
-H "Authorization: Bearer $SS_TOKEN"Response · 200
{
"success": "bool",
"data": [
"<empty list>"
]
}Errors
| Status | detail |
|---|---|
| 404 | Contact not found |
POST/api/v1/salesshift/contacts/{contact_id}/notesNot exercised hereAppend a note activity to a contact's timeline.
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
| contact_id | string(uuid) | required |
Request body (required)
Untyped Dict[str, Any] body — there is no Pydantic model, so these are the field names the handler actually reads.
body
Values in the request below are typed placeholders, not sample data.
Request
curl -X POST 'https://api.vxcloud.io/api/v1/salesshift/contacts/{contact_id}/notes' \
-H "Authorization: Bearer $SS_TOKEN" \
-H 'Content-Type: application/json' \
-d '{ "body": "<value>" }'Response · 201
{
"id": "…",
"success": "…"
}Errors
| Status | detail |
|---|---|
| 404 | Contact not found |
POST/api/v1/salesshift/contacts/{contact_id}/rescoreNot exercised hereRecompute and persist a contact's fit/engagement scores.
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
| contact_id | string(uuid) | required |
Request
curl -X POST 'https://api.vxcloud.io/api/v1/salesshift/contacts/{contact_id}/rescore' \
-H "Authorization: Bearer $SS_TOKEN"Response · 200
{
"details": "…",
"success": "…"
}Errors
| Status | detail |
|---|---|
| 404 | Contact not found |
POST/api/v1/salesshift/contacts/{contact_id}/send-emailNot exercised hereOne-off tracked email to a single contact (the plan's walking skeleton, task 1.9): BYOK/platform send + pixel + unsubscribe link.
One-off tracked email to a single contact (the plan's walking skeleton, task 1.9): BYOK/platform send + pixel + unsubscribe link.
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
| contact_id | string(uuid) | required |
Request body (required)
Untyped Dict[str, Any] body — there is no Pydantic model, so these are the field names the handler actually reads.
body_htmlfrom_emailfrom_nameintegration_idreply_tosender_account_idsubject
Values in the request below are typed placeholders, not sample data.
Request
curl -X POST 'https://api.vxcloud.io/api/v1/salesshift/contacts/{contact_id}/send-email' \
-H "Authorization: Bearer $SS_TOKEN" \
-H 'Content-Type: application/json' \
-d '{ "body_html": "<value>", "from_email": "<value>", "from_name": "<value>", "integration_id": "<value>", "reply_to": "<value>", "sender_account_id": "<value>", "subject": "<value>" }'Response · 200
{
"error": "…",
"provider": "…",
"status": "…",
"success": "…",
"tracking_id": "…"
}Errors
| Status | detail |
|---|---|
| 404 | Contact not found |
| 400 | subject and body_html required |
| 400 | Cannot send: {...} |
POST/api/v1/salesshift/contacts/bulkNot exercised hereCSV import (plan 1.7): rows already column-mapped by the frontend wizard.
CSV import (plan 1.7): rows already column-mapped by the frontend wizard. Dedupes by email inside the org; skips rows without email.
Request body (required)
Untyped Dict[str, Any] body — there is no Pydantic model, so these are the field names the handler actually reads.
contactsemail
Values in the request below are typed placeholders, not sample data.
Request
curl -X POST 'https://api.vxcloud.io/api/v1/salesshift/contacts/bulk' \
-H "Authorization: Bearer $SS_TOKEN" \
-H 'Content-Type: application/json' \
-d '{ "contacts": "<value>", "email": "<value>" }'Response · 201
{
"created": "…",
"skipped": "…",
"success": "…"
}Errors
| Status | detail |
|---|---|
| 400 | contacts list required |
| 400 | Max 2000 contacts per import |
| 402 | computed at runtime: # entitlements.assert_contact_headroom
detail = (
f"{ent.plan_name} stores up to {ent.contacts:,} contacts and this "
f"workspace has {current:,}. Upgrade to add more, or remove "
f"contacts you no longer need."
) |
POST/api/v1/salesshift/contacts/enrichNot exercised hereWaterfall enrichment MVP (plan 5.8): Hunter.io via BYOK key when configured, else deterministic email-pattern inference.
Waterfall enrichment MVP (plan 5.8): Hunter.io via BYOK key when configured, else deterministic email-pattern inference. PDL/scraper stages land with the Go enrichment worker.
Request body (required)
Untyped Dict[str, Any] body — there is no Pydantic model, so these are the field names the handler actually reads.
contact_ids
Values in the request below are typed placeholders, not sample data.
Request
curl -X POST 'https://api.vxcloud.io/api/v1/salesshift/contacts/enrich' \
-H "Authorization: Bearer $SS_TOKEN" \
-H 'Content-Type: application/json' \
-d '{ "contact_ids": "<value>" }'Response · 200
{
"data": "…",
"hunter_configured": "…",
"success": "…"
}Errors
| Status | detail |
|---|---|
| 400 | contact_ids required |
GET/api/v1/salesshift/conversationsCalled liveContacts with email history, newest activity first.
Query parameters
| Name | Type | Required | Notes |
|---|---|---|---|
| q | string | optional | Default "". |
| limit | integer | optional | Default 50. |
Request
curl 'https://api.vxcloud.io/api/v1/salesshift/conversations' \
-H "Authorization: Bearer $SS_TOKEN"Response · 200
{
"success": "bool",
"data": [
{
"contact_id": "str",
"name": "str",
"email": "str",
"company": "null",
"total_emails": "int",
"replies": "int",
"last_at": "str",
"last_snippet": "str",
"last_replied": "bool"
},
"...x28"
]
}GET/api/v1/salesshift/conversations/{contact_id}Called liveFull email thread with one contact: every tracked send + captured reply.
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
| contact_id | string(uuid) | required |
Request
curl 'https://api.vxcloud.io/api/v1/salesshift/conversations/{contact_id}' \
-H "Authorization: Bearer $SS_TOKEN"Response · 200
{
"success": "bool",
"contact": {
"id": "str",
"name": "str",
"email": "str",
"company": "null",
"job_title": "null"
},
"messages": [
{
"id": "str",
"subject": "str",
"body_html": "str",
"reply_body": "str",
"reply_category": "null",
"status": "str",
"provider": "str",
"from_email": "str",
"sent_at": "null",
"opened_at": "null",
"replied_at": "null",
"created_at": "str"
},
"...x2"
]
}Errors
| Status | detail |
|---|---|
| 404 | Contact not found |
POST/api/v1/salesshift/email/sendNot exercised hereDirect tracked send — the vxcli / vxsdk surface.
Direct tracked send — the vxcli / vxsdk surface. Upserts the contact by email, then routes through the same engine as sequences (suppression gate, caps, tenant node worker, tracking, Kafka events).
Request body (required)
Untyped Dict[str, Any] body — there is no Pydantic model, so these are the field names the handler actually reads.
bodybody_htmlfirst_nameintegration_idlast_namesubjecttoto_email
Values in the request below are typed placeholders, not sample data.
Request
curl -X POST 'https://api.vxcloud.io/api/v1/salesshift/email/send' \
-H "Authorization: Bearer $SS_TOKEN" \
-H 'Content-Type: application/json' \
-d '{ "body": "<value>", "body_html": "<value>", "first_name": "<value>", "integration_id": "<value>", "last_name": "<value>", "subject": "<value>", "to": "<value>", "to_email": "<value>" }'import vxsdk
client = vxsdk.Client(access_token="$SS_TOKEN", vxcloud_url="https://api.vxcloud.io")
ss = client.salesshift
ss.send_email(to_email="[email protected]", subject="Hello", body_html="<p>Hi</p>")import { VxCloud } from '@vxcloud/sdk';
const vx = new VxCloud({
accessToken: process.env.SS_TOKEN!,
vxcloudURL: 'https://api.vxcloud.io',
});
await vx.salesshift.sendEmail({ toEmail: '[email protected]', subject: 'Hello', bodyHtml: '<p>Hi</p>' });import vxsdk "github.com/prodxcloud/vxcloud"
c, err := vxsdk.New(ctx,
vxsdk.WithJWT(os.Getenv("SS_TOKEN"), ""),
vxsdk.WithVxCloudURL("https://api.vxcloud.io"),
)
ss := c.SalesShift()
res, err := ss.SendEmail(ctx, salesshift.SendEmailInput{ToEmail: "[email protected]", Subject: "Hello", BodyHTML: "<p>Hi</p>"})Response · 200
{
"contact_id": "…",
"error": "…",
"provider": "…",
"status": "…",
"success": "…",
"tracking_id": "…"
}Errors
| Status | detail |
|---|---|
| 400 | to_email, subject and body_html required |
| 400 | Cannot send: {...} |
GET/api/v1/salesshift/listsCalled liveThe organization's static contact lists with member counts.
Request
curl 'https://api.vxcloud.io/api/v1/salesshift/lists' \
-H "Authorization: Bearer $SS_TOKEN"Response · 200
{
"success": "bool",
"data": [
{
"id": "str",
"name": "str",
"description": "null",
"list_type": "str",
"member_count": "int",
"created_at": "str"
},
"...x2"
]
}POST/api/v1/salesshift/listsCalled liveCreate a static contact list.
Request body (required)
Untyped Dict[str, Any] body — there is no Pydantic model, so these are the field names the handler actually reads.
descriptionname
The body in the request below is the exact one sent during verification.
Request
curl -X POST 'https://api.vxcloud.io/api/v1/salesshift/lists' \
-H "Authorization: Bearer $SS_TOKEN" \
-H 'Content-Type: application/json' \
-d '{ "name": "inventory-verify-1786039295", "description": "temporary row created to verify the documented shape" }'Response · 201
{
"success": "bool",
"id": "str"
}Errors
| Status | detail |
|---|---|
| 400 | name required |
DELETE/api/v1/salesshift/lists/{list_id}Called liveDelete a static contact list.
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
| list_id | string(uuid) | required |
Request
curl -X DELETE 'https://api.vxcloud.io/api/v1/salesshift/lists/{list_id}' \
-H "Authorization: Bearer $SS_TOKEN"Response · 200
{
"success": "bool"
}Errors
| Status | detail |
|---|---|
| 404 | List not found |
GET/api/v1/salesshift/lists/{list_id}/membersCalled liveThe contacts belonging to one static list.
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
| list_id | string(uuid) | required |
Request
curl 'https://api.vxcloud.io/api/v1/salesshift/lists/{list_id}/members' \
-H "Authorization: Bearer $SS_TOKEN"Response · 200
{
"success": "bool",
"data": [
"<empty list>"
]
}Errors
| Status | detail |
|---|---|
| 404 | List not found |
POST/api/v1/salesshift/lists/{list_id}/membersNot exercised hereAdd contacts to a static list; ids outside the org are ignored.
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
| list_id | string(uuid) | required |
Request body (required)
Untyped Dict[str, Any] body — there is no Pydantic model, so these are the field names the handler actually reads.
contact_ids
Values in the request below are typed placeholders, not sample data.
Request
curl -X POST 'https://api.vxcloud.io/api/v1/salesshift/lists/{list_id}/members' \
-H "Authorization: Bearer $SS_TOKEN" \
-H 'Content-Type: application/json' \
-d '{ "contact_ids": "<value>" }'Response · 200
{
"added": "…",
"success": "…"
}Errors
| Status | detail |
|---|---|
| 404 | List not found |
DELETE/api/v1/salesshift/lists/{list_id}/members/{contact_id}Not exercised hereTake one contact out of a list.
Take one contact out of a list. Without this the only way to undo a mis-click on "Add to list" was to destroy the whole list.
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
| list_id | string(uuid) | required | |
| contact_id | string(uuid) | required |
Request
curl -X DELETE 'https://api.vxcloud.io/api/v1/salesshift/lists/{list_id}/members/{contact_id}' \
-H "Authorization: Bearer $SS_TOKEN"Response · 200
{
"success": "…"
}Errors
| Status | detail |
|---|---|
| 404 | List not found |
| 404 | Contact is not in this list |
GET/api/v1/salesshift/tasksCalled liveThe organization's CRM tasks, filterable by status, type, priority and free text.
Query parameters
| Name | Type | Required | Notes |
|---|---|---|---|
| status | string? | optional | |
| task_type | string? | optional | |
| priority | string? | optional | |
| q | string? | optional | Substring match on title or description |
| limit | integer | optional | Default 200. min 1. max 500. |
Request
curl 'https://api.vxcloud.io/api/v1/salesshift/tasks' \
-H "Authorization: Bearer $SS_TOKEN"Response · 200
{
"success": "bool",
"data": [
{
"id": "str",
"organization_id": "str",
"title": "str",
"description": "null",
"task_type": "str",
"status": "str",
"priority": "str",
"due_at": "str",
"completed_at": "null",
"contact_id": "str",
"company_id": "null",
"deal_id": "null",
"created_at": "str"
},
"...x2"
],
"total": "int",
"limit": "int"
}POST/api/v1/salesshift/tasksNot exercised hereCreate a CRM task assigned to the calling user.
Request body (required) — TaskCreate
| Field | Type | Required | Notes |
|---|---|---|---|
| title | string | required | |
| description | string? | optional | |
| task_type | string | optional | Default "todo". |
| priority | string | optional | Default "medium". |
| due_at | string(date-time)? | optional | |
| contact_id | string(uuid)? | optional | |
| company_id | string(uuid)? | optional | |
| deal_id | string(uuid)? | optional |
Values in the request below are typed placeholders, not sample data.
Request
curl -X POST 'https://api.vxcloud.io/api/v1/salesshift/tasks' \
-H "Authorization: Bearer $SS_TOKEN" \
-H 'Content-Type: application/json' \
-d '{ "title": "<string>", "description": "<string>", "task_type": "todo", "priority": "medium", "due_at": "<string(date-time)>", "contact_id": "<string(uuid)>", "company_id": "<string(uuid)>", "deal_id": "<string(uuid)>" }'Response · 201
{
"id": "string(uuid)",
"organization_id": "string(uuid)",
"title": "string",
"description": "string?",
"task_type": "string",
"status": "string",
"priority": "string",
"due_at": "string(date-time)?",
"completed_at": "string(date-time)?",
"contact_id": "string(uuid)?",
"company_id": "string(uuid)?",
"deal_id": "string(uuid)?",
"created_at": "string(date-time)"
}PUT/api/v1/salesshift/tasks/{task_id}Not exercised hereUpdate a CRM task from a partial payload.
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
| task_id | string(uuid) | required |
Request body (required) — TaskUpdate
| Field | Type | Required | Notes |
|---|---|---|---|
| title | string? | optional | |
| description | string? | optional | |
| task_type | string? | optional | |
| status | string? | optional | |
| priority | string? | optional | |
| due_at | string(date-time)? | optional |
Values in the request below are typed placeholders, not sample data.
Request
curl -X PUT 'https://api.vxcloud.io/api/v1/salesshift/tasks/{task_id}' \
-H "Authorization: Bearer $SS_TOKEN" \
-H 'Content-Type: application/json' \
-d '{ "title": "<string>", "description": "<string>", "task_type": "<string>", "status": "<string>", "priority": "<string>", "due_at": "<string(date-time)>" }'Response · 200
{
"id": "string(uuid)",
"organization_id": "string(uuid)",
"title": "string",
"description": "string?",
"task_type": "string",
"status": "string",
"priority": "string",
"due_at": "string(date-time)?",
"completed_at": "string(date-time)?",
"contact_id": "string(uuid)?",
"company_id": "string(uuid)?",
"deal_id": "string(uuid)?",
"created_at": "string(date-time)"
}Errors
| Status | detail |
|---|---|
| 404 | Task not found |
DELETE/api/v1/salesshift/tasks/{task_id}Not exercised hereHard-delete a task.
Hard-delete a task. A to-do list without a delete accumulates junk until people stop trusting it. `status="cancelled"` already exists for "decided not to do this", which is a different statement and worth keeping — this is for the row that should never have been typed.
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
| task_id | string(uuid) | required |
Request
curl -X DELETE 'https://api.vxcloud.io/api/v1/salesshift/tasks/{task_id}' \
-H "Authorization: Bearer $SS_TOKEN"Response · 204
Returns None — a 200 with a null JSON body, not an envelope.
Errors
| Status | detail |
|---|---|
| 404 | Task not found |