Skip to content
SSalesShiftDocs
API reference

Forms

Forms v2 submissions review, CSV export and per-form analytics.

8 endpoints· 8 called live· verified against http://127.0.0.1:8741

8 endpoints

GET/api/v1/salesshift/forms/{form_id}/analyticsCalled liveForm analytics: tiles, per-day series, top sources, enriched fields (W15).

`{range, tiles:{views, unique_views, starts, submissions, conversion_rate, new_contacts, enriched, spam, held, blocked}, held_pending, series:[{day, views, submissions}], sources:[{source, views, submissions, conversion}], enriched_fields:[{field, label, count}]}` over UTC days. Conversion = submissions ÷ unique visitors, clamped at 100%.

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

Path parameters

NameTypeRequiredNotes
form_idstring(uuid)required

Query parameters

NameTypeRequiredNotes
rangestringoptionalDefault "all". One of "all" | "week" | "month" | "30d" | "custom".
fromstring(date)optionalcustom only
tostring(date)optionalcustom only; ≤ 366 days

Request

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

Response · 200

Top-level keys
{
  "data": "…",
  "success": "…"
}
Top-level keys observed in a live response.

Errors

Statusdetail
404Form not found
422computed at runtime: {message, issues:[{code: invalid_range}]}
#get-api-v1-salesshift-forms-form-id-analyticsforms_router · vxcloud_fastapiclient/app/services/salesshift/forms/router.py:1413Called against a test instance of the current code (http://127.0.0.1:8765) on 2026-10-13 with a real JWT for the test workspace, by the Forms E2E (scripts/sales/salesshift_forms_check.py steps 8-9) and the WP-12 API smoke; also covered by app/tests/unit/test_forms_review.py / test_forms_export.py.
GET/api/v1/salesshift/forms/{form_id}/submissionsCalled liveOne form's submissions, newest first (W16 table).

Returns `{items:[SubmissionRow], total, page, page_size, counts}`; `counts` is per status for the whole form. Name and company are what the visitor typed, via the version's field mapping.

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

Path parameters

NameTypeRequiredNotes
form_idstring(uuid)required

Query parameters

NameTypeRequiredNotes
statusstringoptionalDefault "accepted". One of "accepted" | "spam" | "held" | "blocked" | "all".
qstringoptionalMatches the email address or any answer (case-insensitive).
fromstring(date)optionalYYYY-MM-DD, UTC day, inclusive.
tostring(date)optionalYYYY-MM-DD, UTC day, inclusive.
sourcestringoptional"utm_source / utm_medium", the embedding site's host, or "(direct)".
pageintegeroptionalDefault 1. min 1.
page_sizeintegeroptionalDefault 25. min 1. max 100.

Request

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

Response · 200

Top-level keys
{
  "data": "…",
  "success": "…"
}
Top-level keys observed in a live response.

Errors

Statusdetail
404Form not found
422computed at runtime: {code: invalid_status | invalid_date | invalid_range, message}
#get-api-v1-salesshift-forms-form-id-submissionsforms_router · vxcloud_fastapiclient/app/services/salesshift/forms/router.py:1079Called against a test instance of the current code (http://127.0.0.1:8765) on 2026-10-13 with a real JWT for the test workspace, by the Forms E2E (scripts/sales/salesshift_forms_check.py steps 8-9) and the WP-12 API smoke; also covered by app/tests/unit/test_forms_review.py / test_forms_export.py.
GET/api/v1/salesshift/forms/{form_id}/submissions.csvCalled liveEvery submission matching the filters as CSV, streamed.

UTF-8 with a BOM, RFC 4180 quoting, 1,000 rows per batch. Fixed columns, then one column per answer key across every published version (newest label). Cells starting with = + - @ tab or CR are prefixed with '. IP address and user agent columns are included for admins only. Over 100,000 rows answers 413.

Auth
get_org_user
Scope
organization
Success
200 · text/csv; charset=utf-8
Envelope
none

Path parameters

NameTypeRequiredNotes
form_idstring(uuid)required

Query parameters

NameTypeRequiredNotes
statusstringoptionalDefault "accepted". One of "accepted" | "spam" | "held" | "blocked" | "all".
qstringoptionalMatches the email address or any answer (case-insensitive).
fromstring(date)optionalYYYY-MM-DD, UTC day, inclusive.
tostring(date)optionalYYYY-MM-DD, UTC day, inclusive.
sourcestringoptional"utm_source / utm_medium", the embedding site's host, or "(direct)".

Request

curl
curl 'https://api.vxcloud.io/api/v1/salesshift/forms/{form_id}/submissions.csv' \
  -H "Authorization: Bearer $SS_TOKEN"

Response · 200

A CSV file (Content-Disposition: attachment; {form-slug}-submissions-{date}.csv).

Errors

Statusdetail
404Form not found
422computed at runtime: {code: invalid_status | invalid_date | invalid_range, message}
413computed at runtime: {code: export_too_large, message, total}
#get-api-v1-salesshift-forms-form-id-submissions-csvforms_router · vxcloud_fastapiclient/app/services/salesshift/forms/router.py:1112Called against a test instance of the current code (http://127.0.0.1:8765) on 2026-10-13 with a real JWT for the test workspace, by the Forms E2E (scripts/sales/salesshift_forms_check.py steps 8-9) and the WP-12 API smoke; also covered by app/tests/unit/test_forms_review.py / test_forms_export.py.
GET/api/v1/salesshift/forms/{form_id}/submissions/{submission_id}Called liveOne submission for the response drawer.

`{submission, answers:[{key,label,type,value,maps_to}], version_schema, contact, prev_id, next_id}`. Pass the table's filters so prev (newer) / next (older) follow it. IP and user agent are present for admins only.

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

Path parameters

NameTypeRequiredNotes
form_idstring(uuid)required
submission_idstring(uuid)required

Query parameters

NameTypeRequiredNotes
statusstringoptionalDefault "all". One of "accepted" | "spam" | "held" | "blocked" | "all".
qstringoptionalMatches the email address or any answer (case-insensitive).
fromstring(date)optionalYYYY-MM-DD, UTC day, inclusive.
tostring(date)optionalYYYY-MM-DD, UTC day, inclusive.
sourcestringoptional"utm_source / utm_medium", the embedding site's host, or "(direct)".

Request

curl
curl 'https://api.vxcloud.io/api/v1/salesshift/forms/{form_id}/submissions/{submission_id}' \
  -H "Authorization: Bearer $SS_TOKEN"

Response · 200

Top-level keys
{
  "data": "…",
  "success": "…"
}
Top-level keys observed in a live response.

Errors

Statusdetail
404Form not found
404computed at runtime: {code: not_found, message: 'Submission not found'}
422computed at runtime: {code: invalid_status | invalid_date | invalid_range, message}
#get-api-v1-salesshift-forms-form-id-submissions-submission-idforms_router · vxcloud_fastapiclient/app/services/salesshift/forms/router.py:1321Called against a test instance of the current code (http://127.0.0.1:8765) on 2026-10-13 with a real JWT for the test workspace, by the Forms E2E (scripts/sales/salesshift_forms_check.py steps 8-9) and the WP-12 API smoke; also covered by app/tests/unit/test_forms_review.py / test_forms_export.py.
DELETE/api/v1/salesshift/forms/{form_id}/submissions/{submission_id}Called liveDelete a submission's answers (admin).

The contact stays. An SMS consent ledger row that points at the submission is kept with its evidence pointer cleared. Writes an audit line with ids only.

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

Admin only (require_admin); a member gets 403.

Path parameters

NameTypeRequiredNotes
form_idstring(uuid)required
submission_idstring(uuid)required

Request

curl
curl -X DELETE 'https://api.vxcloud.io/api/v1/salesshift/forms/{form_id}/submissions/{submission_id}' \
  -H "Authorization: Bearer $SS_TOKEN"

Response · 200

Top-level keys
{
  "data": "…",
  "success": "…"
}
Top-level keys observed in a live response.

Errors

Statusdetail
404Form not found
403Only an organization admin can delete a submission.
#delete-api-v1-salesshift-forms-form-id-submissions-submission-idforms_router · vxcloud_fastapiclient/app/services/salesshift/forms/router.py:1395Called against a test instance of the current code (http://127.0.0.1:8765) on 2026-10-13 with a real JWT for the test workspace, by the Forms E2E (scripts/sales/salesshift_forms_check.py steps 8-9) and the WP-12 API smoke; also covered by app/tests/unit/test_forms_review.py / test_forms_export.py.
POST/api/v1/salesshift/forms/{form_id}/submissions/{submission_id}/statusCalled liveMark a submission as spam, or restore it.

`{status: accepted|spam, run_workflows?:false}`. spam/held → accepted runs the submit pipeline on the stored answers (contact upsert, consent from the visitor's tick, enrichment, routing; workflows only when `run_workflows` is true, with `replayed: true` in the payload). → spam relabels only; the contact stays.

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

Path parameters

NameTypeRequiredNotes
form_idstring(uuid)required
submission_idstring(uuid)required

Request body (required)

Untyped body — these are the field names the handler reads.

statusrun_workflows

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

Request

curl
curl -X POST 'https://api.vxcloud.io/api/v1/salesshift/forms/{form_id}/submissions/{submission_id}/status' \
  -H "Authorization: Bearer $SS_TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{ "status": "<value>", "run_workflows": "<value>" }'

Response · 200

Top-level keys
{
  "data": "…",
  "success": "…"
}
Top-level keys observed in a live response.

Errors

Statusdetail
404Form not found
402computed at runtime: {code: contact_cap, message}
409computed at runtime: {code: already_accepted | already_spam | blocked | invalid_transition, message}
422computed at runtime: {message, issues:[{code: invalid_status}]}
#post-api-v1-salesshift-forms-form-id-submissions-submission-id-statusforms_router · vxcloud_fastapiclient/app/services/salesshift/forms/router.py:1353Called against a test instance of the current code (http://127.0.0.1:8765) on 2026-10-13 with a real JWT for the test workspace, by the Forms E2E (scripts/sales/salesshift_forms_check.py steps 8-9) and the WP-12 API smoke; also covered by app/tests/unit/test_forms_review.py / test_forms_export.py.
POST/api/v1/salesshift/forms/{form_id}/submissions/bulkCalled liveSpam, not spam, delete or create contacts for up to 200 submissions.

`{ids, action: spam|not_spam|delete|create_contacts, run_workflows?:false}` → `{done, skipped:[{id, reason}]}`. Each row runs in its own savepoint. `delete` is admin only.

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

Path parameters

NameTypeRequiredNotes
form_idstring(uuid)required

Request body (required)

Untyped body — these are the field names the handler reads.

idsactionrun_workflows

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

Request

curl
curl -X POST 'https://api.vxcloud.io/api/v1/salesshift/forms/{form_id}/submissions/bulk' \
  -H "Authorization: Bearer $SS_TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{ "ids": "<value>", "action": "<value>", "run_workflows": "<value>" }'

Response · 200

Top-level keys
{
  "data": "…",
  "success": "…"
}
Top-level keys observed in a live response.

Errors

Statusdetail
404Form not found
403Only an organization admin can delete submissions.
422computed at runtime: {message, issues:[{code: invalid_action | invalid_ids}]}
#post-api-v1-salesshift-forms-form-id-submissions-bulkforms_router · vxcloud_fastapiclient/app/services/salesshift/forms/router.py:1211Called against a test instance of the current code (http://127.0.0.1:8765) on 2026-10-13 with a real JWT for the test workspace, by the Forms E2E (scripts/sales/salesshift_forms_check.py steps 8-9) and the WP-12 API smoke; also covered by app/tests/unit/test_forms_review.py / test_forms_export.py.
POST/api/v1/salesshift/forms/{form_id}/submissions/release-heldCalled liveCreate contacts for held submissions, oldest first (admin).

`{limit?:500, run_workflows?:false}` → `{released, still_held}`; 402 when nothing could be released because the workspace is still at its contact limit.

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

Admin only (require_admin); a member gets 403.

Path parameters

NameTypeRequiredNotes
form_idstring(uuid)required

Request body (required)

The body is optional.

limitrun_workflows

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

Request

curl
curl -X POST 'https://api.vxcloud.io/api/v1/salesshift/forms/{form_id}/submissions/release-held' \
  -H "Authorization: Bearer $SS_TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{ "limit": "<value>", "run_workflows": "<value>" }'

Response · 200

Top-level keys
{
  "data": "…",
  "success": "…"
}
Top-level keys observed in a live response.

Errors

Statusdetail
404Form not found
402computed at runtime: {code: contact_cap, message, still_held}
403Only an organization admin can release held submissions.
#post-api-v1-salesshift-forms-form-id-submissions-release-heldforms_router · vxcloud_fastapiclient/app/services/salesshift/forms/router.py:1275Called against a test instance of the current code (http://127.0.0.1:8765) on 2026-10-13 with a real JWT for the test workspace, by the Forms E2E (scripts/sales/salesshift_forms_check.py steps 8-9) and the WP-12 API smoke; also covered by app/tests/unit/test_forms_review.py / test_forms_export.py.