Skip to main content

Upload a Third-Party Contract for Review

Goal

Upload a third-party paper contract and create it directly in a review workflow instead of sending it for signature immediately.

Endpoints used

  • POST /api/v2.1/public/contracts/upload_review_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 file content available as base64
  • either a counterparty_workspace_id or a counterparty_organization_name
  • an optional reviewer email or reviewer role id

Overview

This flow is only valid when the selected contract_type_id is accessible in the target workspace. Validate the questionnaire first, then map intake_form_data to the exact keys returned by that endpoint.

Request sequence

1. Inspect the contract type questionnaire

If your upload workflow uses intake-form questions, fetch them first.

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 = requests.get(
f"{base_url}/api/v2.1/public/contract_types/{os.environ['SPOTDRAFT_CONTRACT_TYPE_ID']}/intake_form/questionnaire/",
headers=headers,
timeout=30,
).json()

2. Upload the contract and assign a reviewer

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

payload = {
"contract_name": "Acme Vendor Paper",
"contract_type_id": contract_type_id,
"file_name": "vendor-paper.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",
},
"reviewer": {
"org_user_email": "reviewer@company.com",
"description": "Please review the indemnity and payment terms.",
},
"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",
},
}

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

Example response excerpt:

{
"id": "T-1234",
"created": "2026-04-17T11:30:00Z",
"contract_name": "Acme Vendor Paper",
"contract_link": "https://app.spotdraft.com/contracts/v2/4322",
"contract_status": "REVIEW"
}

Notes on reviewer assignment

The public schema allows the reviewer object to contain either:

  • org_user_email
  • role_id

Use whichever matches how review assignment is modeled in your workspace.

Production notes

  • The API validates file_base64 as a real PDF, not just any base64 string.
  • Contract type access is enforced per workspace.
  • intake_form_data must use the exact questionnaire keys returned by the questionnaire endpoint.
  • If your integration needs to update contract-level intake answers later, use PATCH /api/v2.1/public/contracts/{composite_id}/intake_form/response after creation.

Common failure points

  • missing counterparty identity For review uploads, provide either counterparty_workspace_id or counterparty_organization_name.

  • invalid reviewer block Keep the reviewer payload minimal and valid for your workspace model. Do not send both email and unrelated user metadata.

  • invalid questionnaire keys intake_form_data should be keyed only by questionnaire field names returned by the contract type questionnaire endpoint.

  • wrong upload workflow If the contract type is not linked to the right published upload workflow, the create request can fail before the review is created.