Skip to main content

Upload a Third-Party Contract and Send It for Signature

Goal

Upload a third-party paper contract and send it into SpotDraft's signing workflow in a single public API call.

Endpoints used

  • POST /api/v2.1/public/contracts/upload_sign_contracts/
  • GET /api/v2.1/public/contract_types/{contract_type_id}/intake_form/questionnaire/

Prerequisites

  • a valid public API key
  • a contract_type_id linked to a published third-party paper upload workflow
  • the PDF file content available as a base64 string
  • any creator organization entity id, counterparty details, signatory details, and intake-form answers required by your workflow

Overview

This recipe assumes the selected upload contract type is accessible in the target workspace and that your signatory data matches that workflow's creator-side entity model.

Request sequence

1. Fetch the intake-form questionnaire for the contract type

Use the questionnaire endpoint to discover the allowed variable names and the expected value types for intake_form_data.

import os
import requests

base_url = "https://api.in.spotdraft.com" # Replace with your workspace region.
headers = {
"client-id": SPOTDRAFT_CLIENT_ID,
"client-secret": SPOTDRAFT_CLIENT_SECRET,
"Content-Type": "application/json",
}

questionnaire_response = requests.get(
f"{base_url}/api/v2.1/public/contract_types/{os.environ['SPOTDRAFT_CONTRACT_TYPE_ID']}/intake_form/questionnaire/",
headers=headers,
timeout=30,
)
questionnaire_response.raise_for_status()
questionnaire = questionnaire_response.json()

Example response excerpt:

[
{
"display_label": "Contract term",
"variable": "term",
"type": "string",
"required": true
},
{
"display_label": "Payment method",
"variable": "payment_method",
"type": "enum",
"options": [
{
"label": "Annual invoice",
"value": "annual_invoice"
}
]
}
]

2. Upload the contract for signature

This endpoint takes the file content inline as file_base64. It does not use the workspace file upload flow.

contract_type_id = int(os.environ["SPOTDRAFT_CONTRACT_TYPE_ID"])
creator_entity_id = int(os.environ["SPOTDRAFT_CREATOR_ENTITY_ID"])

payload = {
"contract_name": "Acme Corporation NDA",
"contract_type_id": contract_type_id,
"file_name": "acme-nda.pdf",
"file_base64": PDF_FILE_BASE64,
"creator_organization_entity_id": creator_entity_id,
"counterparty_organization_name": "Acme Corporation",
"counterparty_is_individual": False,
"counterparty_poc_details": {
"first_name": "Avery",
"last_name": "Stone",
"email": "legal@acme.example",
},
"business_user_email": "owner@company.com",
"creator_signatories": [
{
"email": "signatory@company.com",
"title": "VP Legal",
"note": "Primary signer for the creator entity.",
}
],
"external_metadata": {
"id": "hubspot-deal-10024",
"integration_name": "HubSpot",
"record_type": "Deal",
},
"intake_form_data": {
"term": {"days": 180, "type": "MONTHS", "value": 6},
"notes": "Customer requested revised indemnity language.",
"start_date": "2026-04-01",
"payment_method": "annual_invoice",
},
}

upload_response = requests.post(
f"{base_url}/api/v2.1/public/contracts/upload_sign_contracts/",
headers=headers,
json=payload,
timeout=30,
)
upload_response.raise_for_status()
contract = upload_response.json()

Example response excerpt:

{
"id": "T-1234",
"created": "2026-04-17T11:15:00Z",
"contract_name": "Acme Corporation NDA",
"contract_link": "https://app.spotdraft.com/contracts/v2/4322",
"contract_status": "SIGN"
}

Production notes

  • file_base64 must contain a valid PDF.
  • Use questionnaire keys exactly as returned by the questionnaire endpoint.
  • Creator entity and signatory requirements vary by upload workflow.
  • If some intake-form answers are learned later, you can update the saved contract response after creation with PATCH /api/v2.1/public/contracts/{composite_id}/intake_form/response.

Extract:

  • id: the SpotDraft composite contract id, such as T-1234
  • contract_link: the UI link to the created contract

Common failure points

  • upload workflow not linked to the contract type The schema explicitly notes this can fail with SD_CONTRACTS_00289 when contract_type_id is not linked to a published third-party paper upload workflow.

  • invalid intake_form_data The keys must match questionnaire variable names, and the values must match the configured question types.

  • wrong file encoding file_base64 must be the actual base64 file content, not a file path or a data URL wrapper.

  • missing counterparty details The endpoint requires counterparty_organization_name and often a valid counterparty_poc_details block for real workflows.