Skip to content
SSalesShiftDocs
API reference

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.
Auth
get_org_user
Scope
organization
Success
200 · application/json
Envelope
success+data

Query parameters

NameTypeRequiredNotes
pageintegeroptionalDefault 1. min 1.
limitintegeroptionalDefault 25. min 1. max 100.
searchstring?optional
sort_bystringoptionalDefault "created_at".
sort_orderstringoptionalDefault "desc".

Request

curl
curl 'https://api.vxcloud.io/api/v1/salesshift/companies' \
  -H "Authorization: Bearer $SS_TOKEN"

Response · 200

Observed shape
{
  "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"
  }
}
Observed on 2026-08-06 — keys are real, values are the types that came back.
#get-api-v1-salesshift-companiescrm_router · vxcloud_fastapiclient/app/services/salesshift/crm_router.py:911Called against http://127.0.0.1:8741 on 2026-08-06 with a real JWT; the response matched the shape recorded below.
POST/api/v1/salesshift/companiesNot exercised hereCreate a company record owned by the calling user.
Auth
get_org_user
Scope
organization
Success
201 · application/json
Envelope
bare-model

Request body (required) — CompanyCreate

FieldTypeRequiredNotes
namestringrequired
domainstring?optional
industrystring?optional
employee_countinteger?optional
annual_revenuenumber?optional
citystring?optional
state_provincestring?optional
countrystring?optional
websitestring?optional
linkedin_urlstring?optional
tagsstring[]optional
custom_fieldsobjectoptional

Values in the request below are typed placeholders, not sample data.

Request

curl
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

CompanyOut fields
{
  "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)"
}
Fields declared by CompanyOut; values shown are types.
#post-api-v1-salesshift-companiescrm_router · vxcloud_fastapiclient/app/services/salesshift/crm_router.py:983Implemented and read in source for this inventory, but not exercised against a running server here. Treat as undemonstrated until someone calls it.
PUT/api/v1/salesshift/companies/{company_id}Not exercised hereUpdate a company record from a partial payload.
Auth
get_org_user
Scope
organization
Success
200 · application/json
Envelope
bare-model

Path parameters

NameTypeRequiredNotes
company_idstring(uuid)required

Request body (required) — CompanyUpdate

FieldTypeRequiredNotes
namestring?optional
domainstring?optional
industrystring?optional
employee_countinteger?optional
annual_revenuenumber?optional
citystring?optional
state_provincestring?optional
countrystring?optional
websitestring?optional
linkedin_urlstring?optional
tagsstring[]?optional
custom_fieldsobject?optional

Values in the request below are typed placeholders, not sample data.

Request

curl
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

CompanyOut fields
{
  "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)"
}
Fields declared by CompanyOut; values shown are types.

Errors

Statusdetail
404Company not found
#put-api-v1-salesshift-companies-company-idcrm_router · vxcloud_fastapiclient/app/services/salesshift/crm_router.py:1000Implemented and read in source for this inventory, but not exercised against a running server here. Treat as undemonstrated until someone calls it.
DELETE/api/v1/salesshift/companies/{company_id}Not exercised hereDelete a company record.
Auth
get_org_user
Scope
organization
Success
200 · application/json
Envelope
success+custom

Path parameters

NameTypeRequiredNotes
company_idstring(uuid)required

Request

curl
curl -X DELETE 'https://api.vxcloud.io/api/v1/salesshift/companies/{company_id}' \
  -H "Authorization: Bearer $SS_TOKEN"

Response · 200

Top-level keys
{
  "success": "…"
}
Top-level keys read from the handler's return statements.

Errors

Statusdetail
404Company not found
#delete-api-v1-salesshift-companies-company-idcrm_router · vxcloud_fastapiclient/app/services/salesshift/crm_router.py:1022Implemented and read in source for this inventory, but not exercised against a running server here. Treat as undemonstrated until someone calls it.
GET/api/v1/salesshift/contactsCalled livePaged, filterable list of the organization's contacts.
Auth
get_org_user
Scope
organization
Success
200 · application/json
Envelope
success+data

Query parameters

NameTypeRequiredNotes
pageintegeroptionalDefault 1. min 1.
limitintegeroptionalDefault 25. min 1. max 100.
searchstring?optional
lifecycle_stagestring?optional
company_idstring(uuid)?optional
min_scoreinteger?optional
job_titlestring[]?optional
email_statusstring?optionalMatches ^(has_email|unsubscribed)$.
created_afterstring(date-time)?optional
list_idstring(uuid)?optional
in_listboolean?optional
sort_bystringoptionalDefault "created_at".
sort_orderstringoptionalDefault "desc".

Request

curl
curl 'https://api.vxcloud.io/api/v1/salesshift/contacts' \
  -H "Authorization: Bearer $SS_TOKEN"

Response · 200

Observed shape
{
  "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"
  }
}
Observed on 2026-08-06 — keys are real, values are the types that came back.
#get-api-v1-salesshift-contactscrm_router · vxcloud_fastapiclient/app/services/salesshift/crm_router.py:60Called against http://127.0.0.1:8741 on 2026-08-06 with a real JWT; the response matched the shape recorded below.
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.
Auth
get_org_user
Scope
organization
Success
201 · application/json
Envelope
bare-model

Request body (required) — ContactCreate

FieldTypeRequiredNotes
first_namestring?optional
last_namestring?optional
emailstring?optional
phonestring?optional
company_idstring(uuid)?optional
company_namestring?optional
job_titlestring?optional
senioritystring?optional
linkedin_urlstring?optional
citystring?optional
countrystring?optional
timezonestring?optional
sourcestring?optional
lifecycle_stagestringoptionalDefault "lead".
tagsstring[]optional
custom_fieldsobjectoptional

Values in the request below are typed placeholders, not sample data.

Request

curl
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

ContactOut fields
{
  "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)"
}
Fields declared by ContactOut; values shown are types.

Errors

Statusdetail
409Contact with email {...} already exists
402computed 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-contactscrm_router · vxcloud_fastapiclient/app/services/salesshift/crm_router.py:169Implemented and read in source for this inventory, but not exercised against a running server here. Treat as undemonstrated until someone calls it.
GET/api/v1/salesshift/contacts/{contact_id}Called liveOne contact by id, scoped to the caller's organization.
Auth
get_org_user
Scope
organization
Success
200 · application/json
Envelope
bare-model

Path parameters

NameTypeRequiredNotes
contact_idstring(uuid)required

Request

curl
curl 'https://api.vxcloud.io/api/v1/salesshift/contacts/{contact_id}' \
  -H "Authorization: Bearer $SS_TOKEN"

Response · 200

Observed shape
{
  "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"
}
Observed on 2026-08-06 — keys are real, values are the types that came back.

Errors

Statusdetail
404Contact not found
#get-api-v1-salesshift-contacts-contact-idcrm_router · vxcloud_fastapiclient/app/services/salesshift/crm_router.py:536Called against http://127.0.0.1:8741 on 2026-08-06 with a real JWT; the response matched the shape recorded below.
PUT/api/v1/salesshift/contacts/{contact_id}Not exercised hereUpdate a contact from a partial payload (unset fields are left alone).
Auth
get_org_user
Scope
organization
Success
200 · application/json
Envelope
bare-model

Path parameters

NameTypeRequiredNotes
contact_idstring(uuid)required

Request body (required) — ContactUpdate

FieldTypeRequiredNotes
first_namestring?optional
last_namestring?optional
emailstring?optional
phonestring?optional
company_idstring(uuid)?optional
company_namestring?optional
job_titlestring?optional
senioritystring?optional
linkedin_urlstring?optional
citystring?optional
countrystring?optional
timezonestring?optional
sourcestring?optional
statusstring?optional
lifecycle_stagestring?optional
tagsstring[]?optional
custom_fieldsobject?optional
email_subscribedboolean?optional

Values in the request below are typed placeholders, not sample data.

Request

curl
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

ContactOut fields
{
  "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)"
}
Fields declared by ContactOut; values shown are types.

Errors

Statusdetail
404Contact not found
#put-api-v1-salesshift-contacts-contact-idcrm_router · vxcloud_fastapiclient/app/services/salesshift/crm_router.py:553Implemented and read in source for this inventory, but not exercised against a running server here. Treat as undemonstrated until someone calls it.
DELETE/api/v1/salesshift/contacts/{contact_id}Not exercised hereDelete a contact and its dependent bookings, deals, email-tracking and form-submission rows.
Auth
get_org_user
Scope
organization
Success
200 · application/json
Envelope
success+custom

Path parameters

NameTypeRequiredNotes
contact_idstring(uuid)required

Request

curl
curl -X DELETE 'https://api.vxcloud.io/api/v1/salesshift/contacts/{contact_id}' \
  -H "Authorization: Bearer $SS_TOKEN"

Response · 200

Top-level keys
{
  "success": "…"
}
Top-level keys read from the handler's return statements.

Errors

Statusdetail
404Contact not found
#delete-api-v1-salesshift-contacts-contact-idcrm_router · vxcloud_fastapiclient/app/services/salesshift/crm_router.py:576Implemented and read in source for this inventory, but not exercised against a running server here. Treat as undemonstrated until someone calls it.
GET/api/v1/salesshift/contacts/{contact_id}/activitiesCalled liveThe 100 most recent activity rows recorded against a contact.
Auth
get_org_user
Scope
organization
Success
200 · application/json
Envelope
success+data

Path parameters

NameTypeRequiredNotes
contact_idstring(uuid)required

Request

curl
curl 'https://api.vxcloud.io/api/v1/salesshift/contacts/{contact_id}/activities' \
  -H "Authorization: Bearer $SS_TOKEN"

Response · 200

Observed shape
{
  "success": "bool",
  "data": [
    "<empty list>"
  ]
}
Observed on 2026-08-06 — keys are real, values are the types that came back.
#get-api-v1-salesshift-contacts-contact-id-activitiescrm_router · vxcloud_fastapiclient/app/services/salesshift/crm_router.py:617Called against http://127.0.0.1:8741 on 2026-08-06 with a real JWT; the response matched the shape recorded below.
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.

Auth
get_org_user
Scope
organization
Success
200 · application/json
Envelope
success+data

Path parameters

NameTypeRequiredNotes
contact_idstring(uuid)required

Request

curl
curl 'https://api.vxcloud.io/api/v1/salesshift/contacts/{contact_id}/enrollments' \
  -H "Authorization: Bearer $SS_TOKEN"

Response · 200

Observed shape
{
  "success": "bool",
  "data": [
    "<empty list>"
  ]
}
Observed on 2026-08-06 — keys are real, values are the types that came back.
#get-api-v1-salesshift-contacts-contact-id-enrollmentscrm_router · vxcloud_fastapiclient/app/services/salesshift/crm_router.py:645Called against http://127.0.0.1:8741 on 2026-08-06 with a real JWT; the response matched the shape recorded below.
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.

Auth
get_org_user
Scope
organization
Success
200 · application/json
Envelope
success+data

Path parameters

NameTypeRequiredNotes
contact_idstring(uuid)required

Request

curl
curl 'https://api.vxcloud.io/api/v1/salesshift/contacts/{contact_id}/lists' \
  -H "Authorization: Bearer $SS_TOKEN"

Response · 200

Observed shape
{
  "success": "bool",
  "data": [
    "<empty list>"
  ]
}
Observed on 2026-08-06 — keys are real, values are the types that came back.

Errors

Statusdetail
404Contact not found
#get-api-v1-salesshift-contacts-contact-id-listscrm_router · vxcloud_fastapiclient/app/services/salesshift/crm_router.py:677Called against http://127.0.0.1:8741 on 2026-08-06 with a real JWT; the response matched the shape recorded below.
POST/api/v1/salesshift/contacts/{contact_id}/notesNot exercised hereAppend a note activity to a contact's timeline.
Auth
get_org_user
Scope
organization
Success
201 · application/json
Envelope
success+custom

Path parameters

NameTypeRequiredNotes
contact_idstring(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
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

Top-level keys
{
  "id": "…",
  "success": "…"
}
Top-level keys read from the handler's return statements.

Errors

Statusdetail
404Contact not found
#post-api-v1-salesshift-contacts-contact-id-notescrm_router · vxcloud_fastapiclient/app/services/salesshift/crm_router.py:708Implemented and read in source for this inventory, but not exercised against a running server here. Treat as undemonstrated until someone calls it.
POST/api/v1/salesshift/contacts/{contact_id}/rescoreNot exercised hereRecompute and persist a contact's fit/engagement scores.
Auth
get_org_user
Scope
organization
Success
200 · application/json
Envelope
success+custom

Path parameters

NameTypeRequiredNotes
contact_idstring(uuid)required

Request

curl
curl -X POST 'https://api.vxcloud.io/api/v1/salesshift/contacts/{contact_id}/rescore' \
  -H "Authorization: Bearer $SS_TOKEN"

Response · 200

Top-level keys
{
  "details": "…",
  "success": "…"
}
Top-level keys read from the handler's return statements.

Errors

Statusdetail
404Contact not found
#post-api-v1-salesshift-contacts-contact-id-rescorecrm_router · vxcloud_fastapiclient/app/services/salesshift/crm_router.py:387Implemented and read in source for this inventory, but not exercised against a running server here. Treat as undemonstrated until someone calls it.
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.

Auth
get_org_user
Scope
organization
Success
200 · application/json
Envelope
success+custom

Path parameters

NameTypeRequiredNotes
contact_idstring(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
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

Top-level keys
{
  "error": "…",
  "provider": "…",
  "status": "…",
  "success": "…",
  "tracking_id": "…"
}
Top-level keys read from the handler's return statements.

Errors

Statusdetail
404Contact not found
400subject and body_html required
400Cannot send: {...}
#post-api-v1-salesshift-contacts-contact-id-send-emailcrm_router · vxcloud_fastapiclient/app/services/salesshift/crm_router.py:266Implemented and read in source for this inventory, but not exercised against a running server here. Treat as undemonstrated until someone calls it.
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.

Auth
get_org_user
Scope
organization
Success
201 · application/json
Envelope
success+custom

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
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

Top-level keys
{
  "created": "…",
  "skipped": "…",
  "success": "…"
}
Top-level keys read from the handler's return statements.

Errors

Statusdetail
400contacts list required
400Max 2000 contacts per import
402computed 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-bulkcrm_router · vxcloud_fastapiclient/app/services/salesshift/crm_router.py:215Implemented and read in source for this inventory, but not exercised against a running server here. Treat as undemonstrated until someone calls it.
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.

Auth
get_org_user
Scope
organization
Success
200 · application/json
Envelope
success+custom

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
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

Top-level keys
{
  "data": "…",
  "hunter_configured": "…",
  "success": "…"
}
Top-level keys read from the handler's return statements.

Errors

Statusdetail
400contact_ids required
#post-api-v1-salesshift-contacts-enrichcrm_router · vxcloud_fastapiclient/app/services/salesshift/crm_router.py:406Implemented and read in source for this inventory, but not exercised against a running server here. Treat as undemonstrated until someone calls it.
GET/api/v1/salesshift/conversationsCalled liveContacts with email history, newest activity first.
Auth
get_org_user
Scope
organization
Success
200 · application/json
Envelope
success+data

Query parameters

NameTypeRequiredNotes
qstringoptionalDefault "".
limitintegeroptionalDefault 50.

Request

curl
curl 'https://api.vxcloud.io/api/v1/salesshift/conversations' \
  -H "Authorization: Bearer $SS_TOKEN"

Response · 200

Observed shape
{
  "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"
  ]
}
Observed on 2026-08-06 — keys are real, values are the types that came back.
#get-api-v1-salesshift-conversationscrm_router · vxcloud_fastapiclient/app/services/salesshift/crm_router.py:1160Called against http://127.0.0.1:8741 on 2026-08-06 with a real JWT; the response matched the shape recorded below.
GET/api/v1/salesshift/conversations/{contact_id}Called liveFull email thread with one contact: every tracked send + captured reply.
Auth
get_org_user
Scope
organization
Success
200 · application/json
Envelope
success+custom

Path parameters

NameTypeRequiredNotes
contact_idstring(uuid)required

Request

curl
curl 'https://api.vxcloud.io/api/v1/salesshift/conversations/{contact_id}' \
  -H "Authorization: Bearer $SS_TOKEN"

Response · 200

Observed shape
{
  "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"
  ]
}
Observed on 2026-08-06 — keys are real, values are the types that came back.

Errors

Statusdetail
404Contact not found
#get-api-v1-salesshift-conversations-contact-idcrm_router · vxcloud_fastapiclient/app/services/salesshift/crm_router.py:1260Called against http://127.0.0.1:8741 on 2026-08-06 with a real JWT; the response matched the shape recorded below.
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).

Auth
get_org_user
Scope
organization
Success
200 · application/json
Envelope
success+custom

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
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>" }'

Response · 200

Top-level keys
{
  "contact_id": "…",
  "error": "…",
  "provider": "…",
  "status": "…",
  "success": "…",
  "tracking_id": "…"
}
Top-level keys read from the handler's return statements.

Errors

Statusdetail
400to_email, subject and body_html required
400Cannot send: {...}
#post-api-v1-salesshift-email-sendcrm_router · vxcloud_fastapiclient/app/services/salesshift/crm_router.py:329Implemented and read in source for this inventory, but not exercised against a running server here. Treat as undemonstrated until someone calls it.
GET/api/v1/salesshift/listsCalled liveThe organization's static contact lists with member counts.
Auth
get_org_user
Scope
organization
Success
200 · application/json
Envelope
success+data

Request

curl
curl 'https://api.vxcloud.io/api/v1/salesshift/lists' \
  -H "Authorization: Bearer $SS_TOKEN"

Response · 200

Observed shape
{
  "success": "bool",
  "data": [
    {
      "id": "str",
      "name": "str",
      "description": "null",
      "list_type": "str",
      "member_count": "int",
      "created_at": "str"
    },
    "...x2"
  ]
}
Observed on 2026-08-06 — keys are real, values are the types that came back.
#get-api-v1-salesshift-listscrm_router · vxcloud_fastapiclient/app/services/salesshift/crm_router.py:747Called against http://127.0.0.1:8741 on 2026-08-06 with a real JWT; the response matched the shape recorded below.
POST/api/v1/salesshift/listsCalled liveCreate a static contact list.
Auth
get_org_user
Scope
organization
Success
201 · application/json
Envelope
success+custom

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
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

Observed shape
{
  "success": "bool",
  "id": "str"
}
Observed on 2026-08-06 — keys are real, values are the types that came back.

Errors

Statusdetail
400name required
#post-api-v1-salesshift-listscrm_router · vxcloud_fastapiclient/app/services/salesshift/crm_router.py:772Called against http://127.0.0.1:8741 on 2026-08-06 with a real JWT; the response matched the shape recorded below.
DELETE/api/v1/salesshift/lists/{list_id}Called liveDelete a static contact list.
Auth
get_org_user
Scope
organization
Success
200 · application/json
Envelope
success+custom

Path parameters

NameTypeRequiredNotes
list_idstring(uuid)required

Request

curl
curl -X DELETE 'https://api.vxcloud.io/api/v1/salesshift/lists/{list_id}' \
  -H "Authorization: Bearer $SS_TOKEN"

Response · 200

Observed shape
{
  "success": "bool"
}
Observed on 2026-08-06 — keys are real, values are the types that came back.

Errors

Statusdetail
404List not found
#delete-api-v1-salesshift-lists-list-idcrm_router · vxcloud_fastapiclient/app/services/salesshift/crm_router.py:883Called against http://127.0.0.1:8741 on 2026-08-06 with a real JWT; the response matched the shape recorded below.
GET/api/v1/salesshift/lists/{list_id}/membersCalled liveThe contacts belonging to one static list.
Auth
get_org_user
Scope
organization
Success
200 · application/json
Envelope
success+data

Path parameters

NameTypeRequiredNotes
list_idstring(uuid)required

Request

curl
curl 'https://api.vxcloud.io/api/v1/salesshift/lists/{list_id}/members' \
  -H "Authorization: Bearer $SS_TOKEN"

Response · 200

Observed shape
{
  "success": "bool",
  "data": [
    "<empty list>"
  ]
}
Observed on 2026-08-06 — keys are real, values are the types that came back.

Errors

Statusdetail
404List not found
#get-api-v1-salesshift-lists-list-id-memberscrm_router · vxcloud_fastapiclient/app/services/salesshift/crm_router.py:824Called against http://127.0.0.1:8741 on 2026-08-06 with a real JWT; the response matched the shape recorded below.
POST/api/v1/salesshift/lists/{list_id}/membersNot exercised hereAdd contacts to a static list; ids outside the org are ignored.
Auth
get_org_user
Scope
organization
Success
200 · application/json
Envelope
success+custom

Path parameters

NameTypeRequiredNotes
list_idstring(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
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

Top-level keys
{
  "added": "…",
  "success": "…"
}
Top-level keys read from the handler's return statements.

Errors

Statusdetail
404List not found
#post-api-v1-salesshift-lists-list-id-memberscrm_router · vxcloud_fastapiclient/app/services/salesshift/crm_router.py:792Implemented and read in source for this inventory, but not exercised against a running server here. Treat as undemonstrated until someone calls it.
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.

Auth
get_org_user
Scope
organization
Success
200 · application/json
Envelope
success+custom

Path parameters

NameTypeRequiredNotes
list_idstring(uuid)required
contact_idstring(uuid)required

Request

curl
curl -X DELETE 'https://api.vxcloud.io/api/v1/salesshift/lists/{list_id}/members/{contact_id}' \
  -H "Authorization: Bearer $SS_TOKEN"

Response · 200

Top-level keys
{
  "success": "…"
}
Top-level keys read from the handler's return statements.

Errors

Statusdetail
404List not found
404Contact is not in this list
#delete-api-v1-salesshift-lists-list-id-members-contact-idcrm_router · vxcloud_fastapiclient/app/services/salesshift/crm_router.py:857Implemented and read in source for this inventory, but not exercised against a running server here. Treat as undemonstrated until someone calls it.
GET/api/v1/salesshift/tasksCalled liveThe organization's CRM tasks, filterable by status, type, priority and free text.
Auth
get_org_user
Scope
organization
Success
200 · application/json
Envelope
success+custom

Query parameters

NameTypeRequiredNotes
statusstring?optional
task_typestring?optional
prioritystring?optional
qstring?optionalSubstring match on title or description
limitintegeroptionalDefault 200. min 1. max 500.

Request

curl
curl 'https://api.vxcloud.io/api/v1/salesshift/tasks' \
  -H "Authorization: Bearer $SS_TOKEN"

Response · 200

Observed shape
{
  "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"
}
Observed on 2026-08-06 — keys are real, values are the types that came back.
#get-api-v1-salesshift-taskscrm_router · vxcloud_fastapiclient/app/services/salesshift/crm_router.py:1044Called against http://127.0.0.1:8741 on 2026-08-06 with a real JWT; the response matched the shape recorded below.
POST/api/v1/salesshift/tasksNot exercised hereCreate a CRM task assigned to the calling user.
Auth
get_org_user
Scope
organization
Success
201 · application/json
Envelope
bare-model

Request body (required) — TaskCreate

FieldTypeRequiredNotes
titlestringrequired
descriptionstring?optional
task_typestringoptionalDefault "todo".
prioritystringoptionalDefault "medium".
due_atstring(date-time)?optional
contact_idstring(uuid)?optional
company_idstring(uuid)?optional
deal_idstring(uuid)?optional

Values in the request below are typed placeholders, not sample data.

Request

curl
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

TaskOut fields
{
  "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)"
}
Fields declared by TaskOut; values shown are types.
#post-api-v1-salesshift-taskscrm_router · vxcloud_fastapiclient/app/services/salesshift/crm_router.py:1084Implemented and read in source for this inventory, but not exercised against a running server here. Treat as undemonstrated until someone calls it.
PUT/api/v1/salesshift/tasks/{task_id}Not exercised hereUpdate a CRM task from a partial payload.
Auth
get_org_user
Scope
organization
Success
200 · application/json
Envelope
bare-model

Path parameters

NameTypeRequiredNotes
task_idstring(uuid)required

Request body (required) — TaskUpdate

FieldTypeRequiredNotes
titlestring?optional
descriptionstring?optional
task_typestring?optional
statusstring?optional
prioritystring?optional
due_atstring(date-time)?optional

Values in the request below are typed placeholders, not sample data.

Request

curl
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

TaskOut fields
{
  "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)"
}
Fields declared by TaskOut; values shown are types.

Errors

Statusdetail
404Task not found
#put-api-v1-salesshift-tasks-task-idcrm_router · vxcloud_fastapiclient/app/services/salesshift/crm_router.py:1101Implemented and read in source for this inventory, but not exercised against a running server here. Treat as undemonstrated until someone calls it.
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.

Auth
get_org_user
Scope
organization
Success
204 ·
Envelope
empty

Path parameters

NameTypeRequiredNotes
task_idstring(uuid)required

Request

curl
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

Statusdetail
404Task not found
#delete-api-v1-salesshift-tasks-task-idcrm_router · vxcloud_fastapiclient/app/services/salesshift/crm_router.py:1130Implemented and read in source for this inventory, but not exercised against a running server here. Treat as undemonstrated until someone calls it.