Contracts and e-sign
Contract documents, public token signing, audit trail and executed PDFs.
12 endpoints· 2 called live· verified against http://127.0.0.1:8741
12 endpoints
GET/api/v1/salesshift/contractsCalled liveThe organization's contract documents, optionally filtered by deal.
Query parameters
| Name | Type | Required | Notes |
|---|---|---|---|
| deal_id | string(uuid)? | optional |
Request
curl 'https://api.vxcloud.io/api/v1/salesshift/contracts' \
-H "Authorization: Bearer $SS_TOKEN"Response · 200
{
"success": "bool",
"data": [
{
"id": "str",
"deal_id": "null",
"title": "str",
"status": "str",
"party_a_name": "str",
"party_a_email": "str",
"party_b_name": "str",
"party_b_email": "str",
"signed_a_at": "null",
"signed_b_at": "null",
"signature_a": "null",
"signature_b": "null",
"sent_at": "null",
"completed_at": "null",
"created_at": "str",
"content_html": "str",
"fields": {
"pages": "...",
"fields": "..."
},
"content_sha256": "null",
"token_expires_at": "null",
"declined_at": "null",
"declined_by": "null",
"decline_reason": "null",
"reminder_count": "int",
"last_reminded_at": "null",
"signer_a_claimed_name": "null",
"signer_b_claimed_name": "null",
"sign_url_a": "str",
"sign_url_b": "str",
"pdf_url_a": "str",
"pdf_url_b": "str"
},
"...x23"
]
}POST/api/v1/salesshift/contractsVerified in sessionCreate a contract document with its signing parties.
Request body (required) — ContractIn
| Field | Type | Required | Notes |
|---|---|---|---|
| deal_id | string(uuid)? | optional | |
| title | string | required | ≤ 300 chars. |
| content_html | string | optional | Default "". |
| party_a_name | string | optional | Default "". |
| party_a_email | string | optional | Default "". |
| party_b_name | string | optional | Default "". |
| party_b_email | string | optional | Default "". |
Values in the request below are typed placeholders, not sample data.
Request
curl -X POST 'https://api.vxcloud.io/api/v1/salesshift/contracts' \
-H "Authorization: Bearer $SS_TOKEN" \
-H 'Content-Type: application/json' \
-d '{ "deal_id": "<string(uuid)>", "title": "<string>", "content_html": "", "party_a_name": "", "party_a_email": "", "party_b_name": "", "party_b_email": "" }'Response · 201
{
"data": "…",
"success": "…"
}PATCH/api/v1/salesshift/contracts/{contract_id}Verified in sessionEdit a contract.
Edit a contract. The body, the title and the field layout are frozen the moment anyone signs — that is what makes the content hash meaningful. Correcting the counterparty's name or address stays open while THAT party has not signed, because fixing a typo in an email address is the single most common real envelope correction and voiding for it is absurd.
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
| contract_id | string(uuid) | required |
Request body (required) — ContractPatch
| Field | Type | Required | Notes |
|---|---|---|---|
| title | string? | optional | |
| content_html | string? | optional | |
| party_b_name | string? | optional | |
| party_b_email | string? | optional | |
| fields | object? | optional |
Values in the request below are typed placeholders, not sample data.
Request
curl -X PATCH 'https://api.vxcloud.io/api/v1/salesshift/contracts/{contract_id}' \
-H "Authorization: Bearer $SS_TOKEN" \
-H 'Content-Type: application/json' \
-d '{ "title": "<string>", "content_html": "<string>", "party_b_name": "<string>", "party_b_email": "<string>", "fields": {} }'Response · 200
{
"data": "…",
"fields_need_review": "…",
"success": "…"
}Errors
| Status | detail |
|---|---|
| 404 | Contract not found |
| 400 | Contract is {...} and can no longer be edited |
| 400 | Contract already has signatures — {...} can no longer be changed. Void it and draft a new one instead. |
| 400 | The counterparty has already signed |
DELETE/api/v1/salesshift/contracts/{contract_id}Verified in sessionVoid a contract document.
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
| contract_id | string(uuid) | required |
Request
curl -X DELETE 'https://api.vxcloud.io/api/v1/salesshift/contracts/{contract_id}' \
-H "Authorization: Bearer $SS_TOKEN"Response · 200
{
"success": "…"
}Errors
| Status | detail |
|---|---|
| 404 | Contract not found |
| 400 | A fully executed contract cannot be voided. Sign a termination or amendment agreement instead. |
GET/api/v1/salesshift/contracts/{contract_id}/auditCalled liveThe audit trail behind the Certificate of Completion, for the sender's own dashboard — the same rows the certificate page prints.
The audit trail behind the Certificate of Completion, for the sender's own dashboard — the same rows the certificate page prints.
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
| contract_id | string(uuid) | required |
Request
curl 'https://api.vxcloud.io/api/v1/salesshift/contracts/{contract_id}/audit' \
-H "Authorization: Bearer $SS_TOKEN"Response · 200
{
"success": "bool",
"content_sha256": "null",
"executed_pdf_sha256": "null",
"consent_a_at": "null",
"consent_b_at": "null",
"consent_a_text": "null",
"consent_b_text": "null",
"signer_a_ip": "null",
"signer_b_ip": "null",
"signer_a_user_agent": "null",
"signer_b_user_agent": "null",
"signer_a_claimed_name": "null",
"signer_b_claimed_name": "null",
"data": [
{
"at": "str",
"party": "str",
"event": "str",
"ip": "str",
"user_agent": "str",
"detail": {
"by": "...",
"title": "..."
}
},
"...x3"
]
}Errors
| Status | detail |
|---|---|
| 404 | Contract not found |
GET/api/v1/salesshift/contracts/{contract_id}/pdfVerified in sessionThe sender's own copy.
The sender's own copy. Without this the only route to an executed contract was the public signing surface — the org had to open a counterparty link to retrieve its own artifact.
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
| contract_id | string(uuid) | required |
Request
curl 'https://api.vxcloud.io/api/v1/salesshift/contracts/{contract_id}/pdf' \
-H "Authorization: Bearer $SS_TOKEN"Response · 200
Response carrying the contract PDF (application/pdf).
Errors
| Status | detail |
|---|---|
| 404 | Contract not found |
| 502 | PDF engine unavailable: {...} |
POST/api/v1/salesshift/contracts/{contract_id}/sendVerified in sessionDeliver signing links by real email — and, on a re-send, chase only the party who still owes a signature.
Deliver signing links by real email — and, on a re-send, chase only the party who still owes a signature.
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
| contract_id | string(uuid) | required |
Request
curl -X POST 'https://api.vxcloud.io/api/v1/salesshift/contracts/{contract_id}/send' \
-H "Authorization: Bearer $SS_TOKEN"Response · 200
{
"data": "…",
"reminder": "…",
"sent_party_a": "…",
"sent_party_b": "…",
"success": "…"
}Errors
| Status | detail |
|---|---|
| 404 | Contract not found |
| 400 | Contract is {...} and cannot be sent again |
| 400 | Counterparty email required before sending |
| 400 | Your own email is required before sending — party A would have no way to sign |
GET/api/v1/salesshift/contracts/sign/{token}url-secret-onlyVerified in sessionPublic signing view for a token; records the first open per party as a 'viewed' audit event.
The signing token is the credential; it selects the document AND the party.
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
| token | string | required |
Request
curl 'https://api.vxcloud.io/api/v1/salesshift/contracts/sign/{token}'Response · 200
{
"already_signed": "…",
"audit": "…",
"can_sign": "…",
"consent_text": "…",
"doc": "…",
"envelope_id": "…",
"mode": "…",
"other_signed": "…",
"party": "…",
"party_email": "…",
"party_name": "…",
"success": "…"
}POST/api/v1/salesshift/contracts/sign/{token}url-secret-onlyVerified in sessionPublic signature submit; row-locked so two simultaneous posts cannot both sign.
The signing token is the credential. The row is locked FOR UPDATE so two simultaneous posts cannot both sign.
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
| token | string | required |
Request body (required) — SignIn
| Field | Type | Required | Notes |
|---|---|---|---|
| name | string | required | ≤ 200 chars. |
| signature | string | required | ≤ 300 chars. |
| style | string | optional | Default "". |
| image_data | string | optional | Default "". ≤ 300000 chars. |
| initials | string | optional | Default "". ≤ 20 chars. |
| field_values | object | optional | |
| consent | boolean? | optional | |
| consent_text | string | optional | Default "". ≤ 2000 chars. |
Values in the request below are typed placeholders, not sample data.
Request
curl -X POST 'https://api.vxcloud.io/api/v1/salesshift/contracts/sign/{token}' \
-H 'Content-Type: application/json' \
-d '{ "name": "<string>", "signature": "<string>", "style": "", "image_data": "", "initials": "", "field_values": {}, "consent": false, "consent_text": "" }'Response · 200
{
"both_signed": "…",
"status": "…",
"success": "…"
}Errors
| Status | detail |
|---|---|
| 400 | This link is for downloading the executed copy only |
| 400 | Contract already {...} |
| 400 | This contract has not been sent for signature yet |
| 400 | You must agree to use electronic records and signatures in order to sign |
| 409 | The contract text changed after it was signed. This envelope can no longer be executed — void it and send a fresh one. |
| 400 | You already signed this contract |
| 400 | computed at runtime: {'message': f"Required field '{label}' on page {int(field.get('page') or 0) + 1} is not completed", 'field_id': str(field.get('id')), 'field_type': ftype, 'page': int(field.get('page') or 0)} |
POST/api/v1/salesshift/contracts/sign/{token}/declineurl-secret-onlyVerified in sessionDecline to sign.
Decline to sign. Every comparable product has this; without it a counterparty who disagrees with the agreement has no action available but to close the tab, and the sender never learns why.
The signing token is the credential.
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
| token | string | required |
Request body (required) — DeclineIn
| Field | Type | Required | Notes |
|---|---|---|---|
| reason | string | required | ≤ 2000 chars. |
| name | string | optional | Default "". ≤ 200 chars. |
Values in the request below are typed placeholders, not sample data.
Request
curl -X POST 'https://api.vxcloud.io/api/v1/salesshift/contracts/sign/{token}/decline' \
-H 'Content-Type: application/json' \
-d '{ "reason": "<string>", "name": "" }'Response · 200
{
"status": "…",
"success": "…"
}Errors
| Status | detail |
|---|---|
| 400 | This link is for downloading the executed copy only |
| 400 | Contract already {...} |
| 400 | You already signed this contract |
GET/api/v1/salesshift/contracts/sign/{token}/pdfurl-secret-onlyVerified in sessionExecuted-contract PDF, rendered by the tenant node's Go e-sign engine (document + signature frames + certificate of completion + audit trail).
Executed-contract PDF, rendered by the tenant node's Go e-sign engine (document + signature frames + certificate of completion + audit trail). Once the envelope is completed the bytes are frozen and served from the row, so the artifact a party downloads next year is the artifact they downloaded at signing.
The signing token is the credential.
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
| token | string | required |
Request
curl 'https://api.vxcloud.io/api/v1/salesshift/contracts/sign/{token}/pdf'Response · 200
Response carrying the executed PDF (application/pdf).
Errors
| Status | detail |
|---|---|
| 502 | PDF engine unavailable: {...} |
POST/api/v1/salesshift/contracts/uploadVerified in sessionBring-your-own contract: upload PDF / DOCX / TXT / MD / HTML — the content is extracted into an editable document that rides the full e-sign flow (edit → send → dual signatures → Go-rendered PDF).
Bring-your-own contract: upload PDF / DOCX / TXT / MD / HTML — the content is extracted into an editable document that rides the full e-sign flow (edit → send → dual signatures → Go-rendered PDF).
Request body (required) — Body_upload_contract_api_v1_salesshift_contracts_upload_post
| Field | Type | Required | Notes |
|---|---|---|---|
| file | string | required | |
| deal_id | string | optional | Default "". |
| title | string | optional | Default "". |
| party_b_name | string | optional | Default "". |
| party_b_email | string | optional | Default "". |
Values in the request below are typed placeholders, not sample data.
Request
curl -X POST 'https://api.vxcloud.io/api/v1/salesshift/contracts/upload' \
-H "Authorization: Bearer $SS_TOKEN" \
-H 'Content-Type: application/json' \
-d '{ "file": "<string>", "deal_id": "", "title": "", "party_b_name": "", "party_b_email": "" }'Response · 201
{
"data": "…",
"success": "…"
}Errors
| Status | detail |
|---|---|
| 400 | File too large (10 MB max) |
| 400 | computed at runtime: str(exc) |
| 400 | Could not read file: {...} |