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

# Run Extractor

> Execute a custom extractor on a document to extract structured data.

<RequestExample>
  ```bash cURL theme={null}
  curl -X POST https://api.doctly.ai/api/v1/e/invoice-extractor \
    -H "Authorization: Bearer YOUR_API_KEY" \
    -F "file=@invoice.pdf"
  ```
</RequestExample>

**POST** `/api/v1/e/{slug}`

Run a custom extractor on a document file. Extractors are pre-configured pipelines that extract specific data from documents and return structured output (JSON, CSV, XML, or Markdown).

## Request

### Headers

<ParamField header="Authorization" type="string" required>
  Bearer token authentication. Example: `Bearer YOUR_API_KEY`
</ParamField>

### Path Parameters

<ParamField path="slug" type="string" required>
  The unique slug identifier of the extractor (e.g., `invoice-extractor`)
</ParamField>

### Body Parameters

<ParamField body="file" type="file">
  The document file to process. Supported formats: PDF, DOCX, PNG, JPG, JPEG, WEBP, GIF.

  <Note>Provide either `file` or `url`, not both.</Note>
</ParamField>

<ParamField body="url" type="string">
  URL to download the document from. The file will be fetched and processed.

  <Note>Provide either `file` or `url`, not both.</Note>
</ParamField>

<ParamField body="callback_url" type="string">
  Webhook URL to receive a POST request when extraction completes.
</ParamField>

## Example Request

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://api.doctly.ai/api/v1/e/invoice-extractor \
    -H "Authorization: Bearer YOUR_API_KEY" \
    -F "file=@invoice.pdf"
  ```

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

  slug = "invoice-extractor"
  url = f"https://api.doctly.ai/api/v1/e/{slug}"
  headers = {"Authorization": "Bearer YOUR_API_KEY"}

  with open("invoice.pdf", "rb") as f:
      files = {"file": ("invoice.pdf", f, "application/pdf")}
      data = {"callback_url": "https://your-domain.com/webhook"}  # optional
      response = requests.post(url, headers=headers, files=files, data=data)

  print(response.json())
  ```

  ```javascript JavaScript theme={null}
  const formData = new FormData();
  formData.append('file', fileInput.files[0]);
  formData.append('callback_url', 'https://your-domain.com/webhook');

  const response = await fetch('https://api.doctly.ai/api/v1/e/invoice-extractor', {
    method: 'POST',
    headers: {
      'Authorization': 'Bearer YOUR_API_KEY'
    },
    body: formData
  });

  const data = await response.json();
  ```
</CodeGroup>

### From URL

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://api.doctly.ai/api/v1/e/invoice-extractor \
    -H "Authorization: Bearer YOUR_API_KEY" \
    -F "url=https://example.com/invoice.pdf"
  ```

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

  slug = "invoice-extractor"
  url = f"https://api.doctly.ai/api/v1/e/{slug}"
  headers = {"Authorization": "Bearer YOUR_API_KEY"}

  data = {"url": "https://example.com/invoice.pdf"}
  response = requests.post(url, headers=headers, data=data)

  print(response.json())
  ```
</CodeGroup>

## Response

<Expandable title="Extraction Response">
  <ResponseField name="id" type="string">
    Unique identifier (UUID) for the document/extraction job
  </ResponseField>

  <ResponseField name="file_name" type="string">
    Original filename
  </ResponseField>

  <ResponseField name="file_size" type="integer">
    Size of the file in bytes
  </ResponseField>

  <ResponseField name="page_count" type="integer">
    Number of pages in the document
  </ResponseField>

  <ResponseField name="status" type="string">
    Processing status: `PENDING`, `PROCESSING`, `COMPLETED`, or `FAILED`
  </ResponseField>

  <ResponseField name="extractor_id" type="string">
    UUID of the extractor used
  </ResponseField>

  <ResponseField name="extractor" type="object">
    Details of the extractor used

    <Expandable title="Extractor Object">
      <ResponseField name="id" type="string">
        Extractor UUID
      </ResponseField>

      <ResponseField name="name" type="string">
        Display name of the extractor
      </ResponseField>

      <ResponseField name="slug" type="string">
        URL-friendly identifier
      </ResponseField>

      <ResponseField name="cost_type" type="string">
        Pricing model: `PER_PAGE` or `PER_DOCUMENT`
      </ResponseField>

      <ResponseField name="cost_credits" type="integer">
        Credits charged per page or per document
      </ResponseField>
    </Expandable>
  </ResponseField>

  <ResponseField name="created_at" type="string">
    ISO 8601 timestamp
  </ResponseField>
</Expandable>

## Example Responses

<ResponseExample>
  ```json 200 OK theme={null}
  {
    "id": "123e4567-e89b-12d3-a456-426614174000",
    "file_name": "invoice.pdf",
    "file_size": 524288,
    "page_count": 2,
    "status": "PENDING",
    "extractor_id": "987fcdeb-a654-3210-9876-543210987654",
    "extractor": {
      "id": "987fcdeb-a654-3210-9876-543210987654",
      "name": "Invoice Extractor",
      "slug": "invoice-extractor",
      "cost_type": "PER_PAGE",
      "cost_credits": 5
    },
    "created_at": "2024-03-21T13:45:00Z"
  }
  ```

  ```json 400 Bad Request theme={null}
  {
    "detail": "Provide only one of 'file' or 'url'."
  }
  ```

  ```json 400 Bad Request — Missing Input theme={null}
  {
    "detail": "One of 'file' or 'url' must be provided."
  }
  ```

  ```json 404 Not Found theme={null}
  {
    "detail": "Extractor with path 'unknown-extractor' not found for your account."
  }
  ```

  ```json 422 Unprocessable Entity theme={null}
  {
    "detail": [
      {
        "loc": ["body", "file"],
        "msg": "field required",
        "type": "value_error.missing"
      }
    ]
  }
  ```
</ResponseExample>

## Webhooks

If `callback_url` is provided, you'll receive a POST request when extraction completes:

```json theme={null}
{
  "document_id": "123e4567-e89b-12d3-a456-426614174000",
  "status": "COMPLETED",
  "file_name": "invoice.pdf",
  "extractor": {
    "id": "987fcdeb-a654-3210-9876-543210987654",
    "name": "Invoice Extractor",
    "slug": "invoice-extractor"
  }
}
```

## Polling for Results

After running an extractor, poll [Get Document](/api-reference/documents/get) until `status` is `COMPLETED`:

<CodeGroup>
  ```bash cURL theme={null}
  DOC_ID="123e4567-e89b-12d3-a456-426614174000"
  while true; do
    RESP=$(curl -s https://api.doctly.ai/api/v1/documents/$DOC_ID \
      -H "Authorization: Bearer YOUR_API_KEY")
    STATUS=$(echo $RESP | jq -r '.status')
    echo "Status: $STATUS"
    if [ "$STATUS" = "COMPLETED" ] || [ "$STATUS" = "FAILED" ]; then
      echo $RESP | jq -r '.output_file_url'
      break
    fi
    sleep 5
  done
  ```

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

  doc_id = "123e4567-e89b-12d3-a456-426614174000"
  headers = {"Authorization": "Bearer YOUR_API_KEY"}

  while True:
      resp = requests.get(
          f"https://api.doctly.ai/api/v1/documents/{doc_id}",
          headers=headers
      ).json()
      
      print(f"Status: {resp['status']}")
      
      if resp["status"] in ("COMPLETED", "FAILED"):
          if resp["status"] == "COMPLETED":
              # Download extraction result
              result = requests.get(resp["output_file_url"])
              data = result.json()  # JSON extraction result
              print(data)
          break
      
      time.sleep(5)
  ```

  ```javascript JavaScript theme={null}
  const docId = '123e4567-e89b-12d3-a456-426614174000';
  const headers = { 'Authorization': 'Bearer YOUR_API_KEY' };

  while (true) {
    const response = await fetch(
      `https://api.doctly.ai/api/v1/documents/${docId}`,
      { headers }
    );
    const doc = await response.json();
    
    console.log(`Status: ${doc.status}`);
    
    if (doc.status === 'COMPLETED' || doc.status === 'FAILED') {
      if (doc.status === 'COMPLETED') {
        // Download extraction result
        const result = await fetch(doc.output_file_url);
        const data = await result.json();
        console.log(data);
      }
      break;
    }
    
    await new Promise(r => setTimeout(r, 5000));
  }
  ```
</CodeGroup>

## Extractor Output Formats

Extractors can output data in different formats:

| Format   | Content-Type       | Description                    |
| -------- | ------------------ | ------------------------------ |
| JSON     | `application/json` | Structured data as JSON object |
| CSV      | `text/csv`         | Tabular data as CSV            |
| XML      | `application/xml`  | Structured data as XML         |
| Markdown | `text/markdown`    | Formatted text as Markdown     |

The output format is determined by the extractor configuration.

<Note>
  Each extractor is designed for specific document types. Using an invoice extractor on a resume may produce incomplete or incorrect results.
</Note>
