> ## Documentation Index
> Fetch the complete documentation index at: https://docs.spitshake.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Quickstart

> Send your first document for signing in under 5 minutes using the SpitShake API.

This guide walks you through the complete signing flow: uploading a PDF, sending it for signature, and downloading the completed document. By the end, you will have a working integration you can build on.

## Prerequisites

* A SpitShake account ([sign up free](https://spitshake.io/sign_up))
* A PDF document to send for signing
* An API token (generated in the next step)

## Step 1: Get your API token

Navigate to **Settings > API** in your SpitShake dashboard and click **Create Token**. Give it a descriptive name (e.g., "Quickstart") and select the scopes you need. For this tutorial, enable `templates:write` and `submissions:write`.

Copy the token -- you will not be able to see it again.

```bash theme={null}
export SPITSHAKE_TOKEN="your-api-token-here"
export SPITSHAKE_URL="https://spitshake.io"
```

<Warning>
  Keep your API token secret. Do not commit it to version control or expose it in client-side code.
</Warning>

## Step 2: Create a template from PDF

Upload a PDF and SpitShake will create a template with a default submitter role. You can optionally specify fields, but for this quickstart we will keep it simple and let the signer fill in all fields manually.

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST "$SPITSHAKE_URL/api/templates/pdf" \
    -H "X-Auth-Token: $SPITSHAKE_TOKEN" \
    -F "files[]=@/path/to/contract.pdf" \
    -F "name=Quickstart Contract"
  ```

  ```javascript Node.js theme={null}
  const fs = require("fs");

  const form = new FormData();
  form.append("files[]", new Blob([fs.readFileSync("./contract.pdf")]), "contract.pdf");
  form.append("name", "Quickstart Contract");

  const response = await fetch(`${process.env.SPITSHAKE_URL}/api/templates/pdf`, {
    method: "POST",
    headers: { "X-Auth-Token": process.env.SPITSHAKE_TOKEN },
    body: form,
  });

  const template = await response.json();
  console.log("Template ID:", template.id);
  ```

  ```python Python theme={null}
  import requests
  import os

  url = f"{os.environ['SPITSHAKE_URL']}/api/templates/pdf"
  headers = {"X-Auth-Token": os.environ["SPITSHAKE_TOKEN"]}

  with open("contract.pdf", "rb") as f:
      files = {"files[]": ("contract.pdf", f, "application/pdf")}
      data = {"name": "Quickstart Contract"}
      response = requests.post(url, headers=headers, files=files, data=data)

  template = response.json()
  print("Template ID:", template["id"])
  ```
</CodeGroup>

**Response:**

```json theme={null}
{
  "id": "tpl_7VQhP2tM9xA1kR8bN",
  "name": "Quickstart Contract",
  "slug": "qk7x9m2p",
  "external_id": null,
  "folder_name": "Default",
  "source": "api",
  "shared": false,
  "field_count": 0,
  "submitter_count": 1,
  "schema": [],
  "submitters": [
    {
      "uuid": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
      "name": "First Party"
    }
  ],
  "thumbnail_url": null,
  "created_at": "2026-04-08T10:30:00.000Z",
  "updated_at": "2026-04-08T10:30:00.000Z"
}
```

<Tip>
  Save the `id` from the response. You will use it in the next step to create a submission.
</Tip>

## Step 3: Create a submission

Now send the template for signing. Provide the submitter's email and name, mapped to the submitter role from the template.

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST "$SPITSHAKE_URL/api/submissions" \
    -H "X-Auth-Token: $SPITSHAKE_TOKEN" \
    -H "Content-Type: application/json" \
    -d '{
      "template_id": "tpl_7VQhP2tM9xA1kR8bN",
      "send_email": true,
      "submitters": [
        {
          "role": "First Party",
          "email": "jane@example.com",
          "name": "Jane Smith"
        }
      ]
    }'
  ```

  ```javascript Node.js theme={null}
  const response = await fetch(`${process.env.SPITSHAKE_URL}/api/submissions`, {
    method: "POST",
    headers: {
      "X-Auth-Token": process.env.SPITSHAKE_TOKEN,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      template_id: "tpl_7VQhP2tM9xA1kR8bN",
      send_email: true,
      submitters: [
        {
          role: "First Party",
          email: "jane@example.com",
          name: "Jane Smith",
        },
      ],
    }),
  });

  const submission = await response.json();
  console.log("Submission ID:", submission.id);
  console.log("Signing URL:", `${process.env.SPITSHAKE_URL}/s/${submission.submitters[0].slug}`);
  ```

  ```python Python theme={null}
  import requests
  import os
  import json

  url = f"{os.environ['SPITSHAKE_URL']}/api/submissions"
  headers = {
      "X-Auth-Token": os.environ["SPITSHAKE_TOKEN"],
      "Content-Type": "application/json",
  }
  payload = {
      "template_id": "tpl_7VQhP2tM9xA1kR8bN",
      "send_email": True,
      "submitters": [
          {
              "role": "First Party",
              "email": "jane@example.com",
              "name": "Jane Smith",
          }
      ],
  }

  response = requests.post(url, headers=headers, json=payload)
  submission = response.json()
  print("Submission ID:", submission["id"])
  print("Signing URL:", f"{os.environ['SPITSHAKE_URL']}/s/{submission['submitters'][0]['slug']}")
  ```
</CodeGroup>

**Response:**

```json theme={null}
{
  "id": 187,
  "slug": "n3k8p1w5",
  "source": "api",
  "status": "pending",
  "template_id": "tpl_7VQhP2tM9xA1kR8bN",
  "submitter_count": 1,
  "created_at": "2026-04-08T10:31:00.000Z",
  "updated_at": "2026-04-08T10:31:00.000Z",
  "completed_at": null,
  "expire_at": null,
  "archived_at": null,
  "submitters": [
    {
      "id": 301,
      "uuid": "f9e8d7c6-b5a4-3210-fedc-ba9876543210",
      "slug": "r7t2q9v4",
      "email": "jane@example.com",
      "name": "Jane Smith",
      "role": "First Party",
      "status": "sent",
      "phone": null,
      "external_id": null,
      "metadata": {},
      "opened_at": null,
      "sent_at": "2026-04-08T10:31:01.000Z",
      "completed_at": null,
      "declined_at": null
    }
  ]
}
```

Jane will receive an email with a link to sign the document. You can also construct the signing URL directly: `https://spitshake.io/s/r7t2q9v4`.

## Step 4: Check submission status

Poll the submission to see when it has been completed, or set up [webhooks](/guides/webhooks) for real-time notifications.

<CodeGroup>
  ```bash cURL theme={null}
  curl "$SPITSHAKE_URL/api/submissions/187" \
    -H "X-Auth-Token: $SPITSHAKE_TOKEN"
  ```

  ```javascript Node.js theme={null}
  const response = await fetch(`${process.env.SPITSHAKE_URL}/api/submissions/187`, {
    headers: { "X-Auth-Token": process.env.SPITSHAKE_TOKEN },
  });

  const submission = await response.json();
  console.log("Status:", submission.status);
  ```

  ```python Python theme={null}
  import requests
  import os

  url = f"{os.environ['SPITSHAKE_URL']}/api/submissions/187"
  headers = {"X-Auth-Token": os.environ["SPITSHAKE_TOKEN"]}

  response = requests.get(url, headers=headers)
  submission = response.json()
  print("Status:", submission["status"])
  ```
</CodeGroup>

**Response when completed:**

```json theme={null}
{
  "id": 187,
  "slug": "n3k8p1w5",
  "source": "api",
  "status": "completed",
  "template_id": "tpl_7VQhP2tM9xA1kR8bN",
  "submitter_count": 1,
  "created_at": "2026-04-08T10:31:00.000Z",
  "updated_at": "2026-04-08T11:15:00.000Z",
  "completed_at": "2026-04-08T11:15:00.000Z",
  "expire_at": null,
  "archived_at": null,
  "submitters": [
    {
      "id": 301,
      "uuid": "f9e8d7c6-b5a4-3210-fedc-ba9876543210",
      "slug": "r7t2q9v4",
      "email": "jane@example.com",
      "name": "Jane Smith",
      "role": "First Party",
      "status": "completed",
      "phone": null,
      "external_id": null,
      "metadata": {},
      "opened_at": "2026-04-08T11:10:00.000Z",
      "sent_at": "2026-04-08T10:31:01.000Z",
      "completed_at": "2026-04-08T11:15:00.000Z",
      "declined_at": null
    }
  ]
}
```

<Tip>
  Instead of polling, use [webhooks](/guides/webhooks) to receive a `submission.completed` event in real time.
</Tip>

## Step 5: Download the signed document

Once the submission status is `completed`, download the final signed PDF with all fields filled and signatures applied.

<CodeGroup>
  ```bash cURL theme={null}
  curl -O -J "$SPITSHAKE_URL/api/submissions/187/documents/download" \
    -H "X-Auth-Token: $SPITSHAKE_TOKEN"
  ```

  ```javascript Node.js theme={null}
  const response = await fetch(
    `${process.env.SPITSHAKE_URL}/api/submissions/187/documents/download`,
    { headers: { "X-Auth-Token": process.env.SPITSHAKE_TOKEN } }
  );

  const buffer = await response.arrayBuffer();
  const fs = require("fs");
  fs.writeFileSync("signed-contract.pdf", Buffer.from(buffer));
  console.log("Downloaded signed-contract.pdf");
  ```

  ```python Python theme={null}
  import requests
  import os

  url = f"{os.environ['SPITSHAKE_URL']}/api/submissions/187/documents/download"
  headers = {"X-Auth-Token": os.environ["SPITSHAKE_TOKEN"]}

  response = requests.get(url, headers=headers)
  with open("signed-contract.pdf", "wb") as f:
      f.write(response.content)
  print("Downloaded signed-contract.pdf")
  ```
</CodeGroup>

The response is a binary PDF file with `Content-Disposition: attachment` headers.

## What's next?

You have successfully sent a document for signing and downloaded the completed result. Here are some next steps to explore:

<CardGroup cols={2}>
  <Card title="Templates" icon="file-lines" href="/guides/templates">
    Define field schemas, submitter roles, and create templates from DOCX or HTML.
  </Card>

  <Card title="Submissions" icon="paper-plane" href="/guides/submissions">
    Pre-fill fields, use quick sign modes, create drafts, and bulk-send documents.
  </Card>

  <Card title="Submitters" icon="user-pen" href="/guides/submitters">
    Track individual signer status, resend invitations, and map external IDs.
  </Card>

  <Card title="Webhooks" icon="bell" href="/guides/webhooks">
    Get real-time notifications instead of polling for submission status changes.
  </Card>

  <Card title="Embedding" icon="window" href="/embed/overview">
    Embed the signing experience directly in your application.
  </Card>

  <Card title="Authentication" icon="key" href="/guides/authentication">
    Learn about API token scopes, JWT tokens, and security best practices.
  </Card>
</CardGroup>
