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

# Get Import Presigned URL

> Get an S3 presigned URL for importing large policy files

Step 1 of the large-file custom policy import flow. Returns an `import_id` and an S3 presigned
`upload_url` so you can upload large policy documents directly to S3, bypassing the API Gateway
and Lambda payload limits that cap the inline [Import Policy](/api-reference/custom-policies/import-policy)
endpoint.

After uploading, call [Start Import](/api-reference/custom-policies/start-import) with the
`import_id` to begin rule extraction.

<Note>
  Use the inline [Import Policy](/api-reference/custom-policies/import-policy) endpoint for plain
  text and small files. Use this presigned flow for large files (above a few MB). Maximum upload
  size is **1 GB**.

  Large documents (e.g. a multi-hundred-page regulatory handbook) are fully extracted — rule
  extraction runs in the background in chunks, so the entire document is analyzed, not just the
  first pages. The trade-off is time: a very large document can stay in `processing` for several
  minutes. Keep polling [Get Import Details](/api-reference/custom-policies/get-import-details)
  until the status leaves `processing`.
</Note>

## Request Body

<ParamField body="filename" type="string">
  Original filename, for reference/audit.
</ParamField>

<ParamField body="content_type" type="string" default="application/pdf">
  MIME type of the file you will upload. Must match the `Content-Type` header you send on the PUT.
</ParamField>

## Response

<ResponseField name="import_id" type="string">
  Unique identifier for the import. Pass this to [Start Import](/api-reference/custom-policies/start-import) after uploading.
</ResponseField>

<ResponseField name="upload_url" type="string">
  S3 presigned URL for the file upload (HTTP PUT).
</ResponseField>

<ResponseField name="upload_method" type="string">
  HTTP method to use for upload (always `PUT`).
</ResponseField>

<ResponseField name="s3_bucket" type="string">
  S3 bucket name.
</ResponseField>

<ResponseField name="s3_key" type="string">
  S3 object key the file will be uploaded to.
</ResponseField>

<ResponseField name="required_headers" type="object">
  **Important:** Headers that MUST be included on the upload PUT. The presigned URL is signed
  with these, so omitting any results in a `SignatureDoesNotMatch` error from S3.
</ResponseField>

<ResponseField name="expires_in_seconds" type="integer">
  Seconds until the presigned URL expires (default 900).
</ResponseField>

<ResponseField name="expires_at" type="string">
  ISO 8601 timestamp when the URL expires.
</ResponseField>

<ResponseField name="max_upload_bytes" type="integer">
  Maximum allowed upload size in bytes, enforced at [Start Import](/api-reference/custom-policies/start-import).
</ResponseField>

<ResponseField name="next_steps" type="object">
  Step-by-step instructions for uploading and starting the import.
</ResponseField>

<ResponseExample>
  ```json 200 OK theme={null}
  {
    "import_id": "550e8400-e29b-41d4-a716-446655440000",
    "upload_url": "https://example-bucket.s3.amazonaws.com/policy-imports/raw/550e8400-e29b-41d4-a716-446655440000.bin?X-Amz-Algorithm=...",
    "upload_method": "PUT",
    "s3_bucket": "example-bucket",
    "s3_key": "policy-imports/raw/550e8400-e29b-41d4-a716-446655440000.bin",
    "required_headers": {
      "Content-Type": "application/pdf"
    },
    "expires_in_seconds": 900,
    "expires_at": "2026-06-15T10:45:00Z",
    "max_upload_bytes": 1073741824,
    "next_steps": {
      "step_1": "PUT the raw file bytes to upload_url with the exact required_headers",
      "step_2": "POST /api/policies/import/start with { \"import_id\": \"550e8400-...\" } to begin extraction"
    }
  }
  ```
</ResponseExample>

<Warning>
  **Required headers:** Include **all** headers from `required_headers` exactly as provided when uploading your file. Missing or mismatched headers (including `Content-Type`) can cause S3 to reject the upload with `SignatureDoesNotMatch`.
</Warning>

## Example

<CodeGroup>
  ```bash cURL theme={null}
  # Step 1: Get the presigned URL
  RESPONSE=$(curl -s -X POST "https://api.zerodrift.ai/api/policies/import/presigned_url" \
    -H "x-api-key: YOUR_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "filename": "compliance-policy.pdf",
      "content_type": "application/pdf"
    }')

  IMPORT_ID=$(printf '%s' "$RESPONSE" | jq -r '.import_id')
  UPLOAD_URL=$(printf '%s' "$RESPONSE" | jq -r '.upload_url')

  # Build curl -H args from required_headers
  CURL_HEADERS=()
  while IFS=$'\t' read -r key value; do
    CURL_HEADERS+=(-H "$key: $value")
  done < <(printf '%s' "$RESPONSE" | jq -r '.required_headers | to_entries[] | "\(.key)\t\(.value)"')

  # Step 2: Upload the raw file directly to S3 (no API key)
  curl -X PUT "$UPLOAD_URL" \
    "${CURL_HEADERS[@]}" \
    --data-binary @compliance-policy.pdf

  echo "Import ID: $IMPORT_ID"
  # Step 3: call POST /api/policies/import/start with this import_id
  ```

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

  API_KEY = "YOUR_API_KEY"
  API_BASE = "https://api.zerodrift.ai"

  # Step 1: Get the presigned URL
  resp = requests.post(
      f"{API_BASE}/api/policies/import/presigned_url",
      headers={"x-api-key": API_KEY, "Content-Type": "application/json"},
      json={"filename": "compliance-policy.pdf", "content_type": "application/pdf"},
  ).json()

  import_id = resp["import_id"]
  upload_url = resp["upload_url"]
  required_headers = resp["required_headers"]

  # Step 2: Upload the raw file directly to S3
  with open("compliance-policy.pdf", "rb") as f:
      requests.put(upload_url, headers=required_headers, data=f)

  print(f"Import ID: {import_id}")
  # Step 3: call POST /api/policies/import/start with this import_id
  ```

  ```javascript JavaScript theme={null}
  const fs = require('fs');
  const axios = require('axios');

  const API_KEY = 'YOUR_API_KEY';
  const API_BASE = 'https://api.zerodrift.ai';

  (async () => {
    // Step 1: Get the presigned URL
    const { data } = await axios.post(
      `${API_BASE}/api/policies/import/presigned_url`,
      { filename: 'compliance-policy.pdf', content_type: 'application/pdf' },
      { headers: { 'x-api-key': API_KEY, 'Content-Type': 'application/json' } }
    );

    // Step 2: Upload the raw file directly to S3 with the signed required_headers
    const fileStream = fs.createReadStream('compliance-policy.pdf');
    await axios.put(data.upload_url, fileStream, {
      headers: data.required_headers,
      maxBodyLength: Infinity,
      maxContentLength: Infinity,
    });

    console.log(`Import ID: ${data.import_id}`);
    // Step 3: call POST /api/policies/import/start with this import_id
  })();
  ```
</CodeGroup>
