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

# Process from Upload

> Call API endpoints after file upload with delegation tokens

## Overview

After uploading a file via TUS, you can call any API endpoint that supports post-upload processing. The same delegation token used for the upload authenticates the processing request.

<Info>
  This endpoint pattern replaces the previous webhook-based flow. Your frontend now calls processing endpoints directly after upload, giving you immediate control over when processing occurs.
</Info>

## Authentication

Use the same delegation token that was used for the TUS upload:

```http theme={"theme":"github-dark"}
Authorization: Bearer <delegation_token>
```

The token contains the `merchant_id` used for billing, so no additional authentication is required.

## Processing Flow

```mermaid theme={"theme":"github-dark"}
sequenceDiagram
    participant F as Your Frontend
    participant T as TUS Server
    participant A as SuperSeeded API
    participant P as Parser
    participant E as Enrichment
    participant D as Database

    F->>T: Upload file with JWT
    T-->>F: Return file URL
    F->>A: POST /v1/{endpoint}
    A->>T: Fetch file internally
    T-->>A: File contents
    A->>P: Parse file
    P-->>A: Extracted data
    A->>D: Record usage event
    A->>E: Enrich/process data
    E-->>A: Processed results
    A-->>F: Return results + usage
```

<Steps>
  <Step title="Upload Complete">
    After the TUS upload completes, your frontend receives the file URL.
  </Step>

  <Step title="Call Processing Endpoint">
    Your frontend sends a POST request with the file URL and delegation token to any supported endpoint.
  </Step>

  <Step title="Internal Fetch">
    The API fetches the file from storage using the provided URL.
  </Step>

  <Step title="Parsing">
    The parser extracts structured data from the uploaded file.
  </Step>

  <Step title="Usage Recording">
    Usage is recorded against the merchant's ledger (from the JWT). See [Usage & Billing](/platform-integration/usage-billing).
  </Step>

  <Step title="Processing">
    The endpoint processes the extracted data (validation, classification, enrichment, etc.).
  </Step>

  <Step title="Response">
    Processed data and usage information are returned directly to your frontend.
  </Step>
</Steps>

## Discovering Available Endpoints

Use the route discovery endpoint to find all endpoints that support post-upload processing:

```bash theme={"theme":"github-dark"}
curl https://api.superseeded.ai/v1/routes/from-upload
```

**Response:**

```json theme={"theme":"github-dark"}
{
  "routes": [
    {
      "id": "verify-plant-names",
      "name": "Verify Plant Names",
      "description": "Verify botanical plant names are correct and spelled properly",
      "endpoint": "/v1/verify/plant-names",
      "method": "POST",
      "requires_auth": true,
      "accepted_file_types": [".json", ".xlsx", ".xls", ".csv", ".txt", ".pdf"],
      "category": "verification"
    },
    {
      "id": "validate-pot-sizes",
      "name": "Validate Pot Sizes",
      "description": "Classify pot sizes and plant specifications into Growth Equivalent categories",
      "endpoint": "/v1/verify/pot-sizes",
      "method": "POST",
      "requires_auth": true,
      "accepted_file_types": [".json", ".xlsx", ".xls", ".pdf", ".txt", ".png", ".jpg", ".jpeg", ".gif", ".webp"],
      "category": "enrichment"
    }
  ],
  "version": "1.0"
}
```

## Example: Species Name Validation

This example shows how to validate botanical names from an uploaded file.

### Request

**Headers:**

| Header          | Value              | Description                                          |
| --------------- | ------------------ | ---------------------------------------------------- |
| `Authorization` | `Bearer <token>`   | The delegation token from `/v1/auth/delegate-upload` |
| `Content-Type`  | `application/json` | Required for JSON body                               |

**Request Body:**

| Field      | Type   | Required | Description                                        |
| ---------- | ------ | -------- | -------------------------------------------------- |
| `file_url` | string | Yes      | The TUS upload URL returned after upload completes |
| `filename` | string | No       | Original filename for context                      |

### Example Request

<CodeGroup>
  ```bash cURL theme={"theme":"github-dark"}
  curl -X POST https://api.superseeded.ai/v1/verify/plant-names \
    -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." \
    -H "Content-Type: application/json" \
    -d '{
      "file_url": "https://secure.superseeded.ai/files/abc123",
      "filename": "plant_schedule.xlsx"
    }'
  ```

  ```javascript JavaScript theme={"theme":"github-dark"}
  const response = await fetch('https://api.superseeded.ai/v1/verify/plant-names', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${delegationToken}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      file_url: uploadResult.uploadURL,
      filename: 'plant_schedule.xlsx'
    })
  });

  const { results, summary } = await response.json();
  ```

  ```python Python theme={"theme":"github-dark"}
  import requests

  response = requests.post(
      "https://api.superseeded.ai/v1/verify/plant-names",
      headers={
          "Authorization": f"Bearer {delegation_token}",
          "Content-Type": "application/json"
      },
      json={
          "file_url": "https://secure.superseeded.ai/files/abc123",
          "filename": "plant_schedule.xlsx"
      }
  )
  result = response.json()
  ```
</CodeGroup>

### Example Response

```json theme={"theme":"github-dark"}
{
  "results": [
    {
      "query": {
        "submitted_name": "Eucalyptus globulus",
        "normalized_name": "eucalyptus globulus",
        "query_timestamp": "2025-01-15T10:30:00Z"
      },
      "validation": {
        "status": "validated",
        "confidence": "high",
        "consensus_score": 0.98,
        "sources_checked": 11,
        "sources_matched": 9
      },
      "accepted_name": {
        "scientific_name": "Eucalyptus globulus",
        "author": "Labill.",
        "nomenclatural_status": "accepted",
        "common_names": [
          {
            "name": "Tasmanian Blue Gum",
            "language": "en",
            "region": "Global"
          }
        ],
        "taxonomic_rank": "species"
      },
      "taxonomy": {
        "kingdom": "Plantae",
        "family": "Myrtaceae",
        "genus": "Eucalyptus",
        "species": "globulus"
      },
      "cross_references": {
        "gbif_id": "3176787",
        "wfo_id": "946382",
        "powo_id": "urn:lsid:ipni.org:names:30001419-2"
      }
    }
  ],
  "summary": {
    "total": 1,
    "validated": 1,
    "uncertain": 0,
    "not_found": 0
  }
}
```

## Example: Pot Size Validation

This example shows how to classify pot sizes from an uploaded file.

### Request

```bash theme={"theme":"github-dark"}
curl -X POST https://api.superseeded.ai/v1/verify/pot-sizes \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." \
  -H "Content-Type: application/json" \
  -d '{
    "file_url": "https://secure.superseeded.ai/files/abc123",
    "filename": "inventory.xlsx"
  }'
```

### Response

```json theme={"theme":"github-dark"}
{
  "results": [
    {
      "input_label": "400mm AS",
      "match_confidence": "High",
      "standard_data": {
        "id": "4.1",
        "type": "Pot - Air Pruning",
        "stage_order": 4,
        "stage_name": "Advanced Production",
        "is_biological": true,
        "logistics": {
          "tier": "Pallet",
          "is_stackable": false,
          "freight_efficiency": "Medium"
        }
      }
    }
  ]
}
```

## Error Responses

| Status | Error              | Description                                     |
| ------ | ------------------ | ----------------------------------------------- |
| `400`  | `invalid_request`  | Missing `file_url` in request body              |
| `401`  | `invalid_token`    | JWT token validation failed or expired          |
| `403`  | `forbidden`        | Token doesn't have access to the specified file |
| `404`  | `file_not_found`   | The specified file URL does not exist           |
| `422`  | `parsing_failed`   | Could not extract data from file                |
| `500`  | `processing_error` | Processing service unavailable                  |

## Token Reuse

<Note>
  The delegation token serves dual purposes:

  1. **Upload authentication** — Authorizes the TUS upload
  2. **Processing authentication** — Authorizes processing endpoints and identifies the merchant for billing

  This design simplifies integration since you only need to manage one token per upload session.
</Note>

## Best Practices

<AccordionGroup>
  <Accordion title="Call immediately after upload">
    For the best user experience, call the processing endpoint as soon as the TUS upload completes. The delegation token has a 5-minute expiration, so don't delay processing.
  </Accordion>

  <Accordion title="Handle the response in your UI">
    Since the data is returned directly, you can display results to your users immediately without waiting for webhooks or polling.
  </Accordion>

  <Accordion title="Use route discovery">
    Call `/v1/routes/from-upload` to dynamically discover available processing endpoints and their capabilities, rather than hardcoding endpoint paths.
  </Accordion>

  <Accordion title="Check accepted file types">
    Each endpoint specifies which file types it can process. Use the `accepted_file_types` field from route discovery to validate files before upload.
  </Accordion>
</AccordionGroup>

## Complete Integration Example

```javascript theme={"theme":"github-dark"}
// 1. Get delegation token
const tokenResponse = await fetch('https://api.superseeded.ai/v1/auth/delegate-upload', {
  method: 'POST',
  headers: {
    'X-API-Key': 'sk_...',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    merchant_id: 'merchant_123'
  })
});
const { delegation_token } = await tokenResponse.json();

// 2. Upload file via TUS
const upload = new tus.Upload(file, {
  endpoint: 'https://secure.superseeded.ai/files/',
  headers: {
    'Authorization': `Bearer ${delegation_token}`
  },
  onSuccess: async () => {
    const fileUrl = upload.url;

    // 3. Process uploaded file
    const processResponse = await fetch('https://api.superseeded.ai/v1/verify/plant-names', {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${delegation_token}`,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({
        file_url: fileUrl,
        filename: file.name
      })
    });

    const results = await processResponse.json();

    // 4. Display results to user
    displayResults(results);
  }
});

upload.start();
```

## Related Documentation

* [Upload Delegation](/platform-integration/upload-delegation) — How to obtain delegation tokens
* [Usage & Billing](/platform-integration/usage-billing) — How usage is tracked and billed
* [Route Discovery](/api-reference/endpoint/route-discovery) — Endpoint to discover available processing routes
