> For the complete documentation index, see [llms.txt](https://docs.amigo.ai/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.amigo.ai/developer-guide/platform-api/data-world-model/intake-links.md).

# Intake Upload Links

Upload links let an operator collect individual files from a person who does not hold a Platform credential. The URL contains a bearer token: possession of an active token authorizes upload, without an account login.

Upload-link intake is separate from [dataset intake](/developer-guide/platform-api/data-world-model/intake.md). Link uploads are not assigned to a dataset, validated against a dataset contract, associated with a source batch, or included in a dataset update run.

{% hint style="warning" %}
Treat each upload URL as a secret. Share it through an appropriate channel, choose the shortest practical expiry and upload limit, and revoke it when collection is complete.
{% endhint %}

## Create an Upload Link

Creates a link for one workspace and `customer_slug`. `expires_in_hours` defaults to 168 and accepts 1-720 hours. `max_uploads` defaults to 100 and accepts 1-10,000 uploads.

{% openapi src="<https://api.platform.amigo.ai/v1/openapi.json>" path="/v1/{workspace\_id}/intake/links" method="post" %}
<https://api.platform.amigo.ai/v1/openapi.json>
{% endopenapi %}

```bash
curl -X POST https://api.platform.amigo.ai/v1/{workspace_id}/intake/links \
  -H "Authorization: Bearer {platform_api_key}" \
  -H "Content-Type: application/json" \
  -d '{
    "customer_slug": "acme-health",
    "display_name": "Acme Health Systems",
    "expires_in_hours": 72,
    "max_uploads": 50
  }'
```

The response returns both `upload_url` and `link_token`. Avoid writing either value to application logs.

Link creation returns `503` when the public forms service is not configured for the environment.

## List Upload Links

By default, the list excludes expired and revoked links. An exhausted but unexpired link can still appear with `status: exhausted`. Set `include_expired=true` to remove the expiry and revocation filters.

{% openapi src="<https://api.platform.amigo.ai/v1/openapi.json>" path="/v1/{workspace\_id}/intake/links" method="get" %}
<https://api.platform.amigo.ai/v1/openapi.json>
{% endopenapi %}

The endpoint returns an array and uses `limit` plus integer `offset`; it does not return the standard paginated response envelope.

## Revoke an Upload Link

Revocation invalidates an active token and returns `204 No Content`. An unknown or already revoked link returns `404`.

{% openapi src="<https://api.platform.amigo.ai/v1/openapi.json>" path="/v1/{workspace\_id}/intake/links/{link\_id}" method="delete" %}
<https://api.platform.amigo.ai/v1/openapi.json>
{% endopenapi %}

## List and Download Uploads

The listing returns files associated with one link, newest first. It uses `limit` and `offset` and returns a plain array.

{% openapi src="<https://api.platform.amigo.ai/v1/openapi.json>" path="/v1/{workspace\_id}/intake/links/{link\_id}/uploads" method="get" %}
<https://api.platform.amigo.ai/v1/openapi.json>
{% endopenapi %}

The download lookup is constrained by workspace ID, link ID, and upload ID. A missing row or missing stored object returns the same `404` response. Successful responses include `Content-Disposition: attachment`, `Cache-Control: private, no-store`, and `X-Content-Type-Options: nosniff`.

{% openapi src="<https://api.platform.amigo.ai/v1/openapi.json>" path="/v1/{workspace\_id}/intake/links/{link\_id}/uploads/{upload\_id}/download" method="get" %}
<https://api.platform.amigo.ai/v1/openapi.json>
{% endopenapi %}

Successful authenticated downloads are classified as PHI-sensitive access reads when audit logging is configured. Audit recording can fail independently, so the download response is not proof that an audit event was durably stored.

## Public Upload Flow

The returned `upload_url` opens the hosted upload form. The form reads public link metadata and sends the file to the token-authenticated API. Neither public endpoint requires a Platform bearer credential; the path token is the credential.

### Read Link Metadata

Returns display name, customer slug, maximum upload size, and the current content-type allowlist. It returns `410 Gone` for an expired or exhausted link.

{% openapi src="<https://api.platform.amigo.ai/v1/openapi.json>" path="/upload/{link\_token}/info" method="get" %}
<https://api.platform.amigo.ai/v1/openapi.json>
{% endopenapi %}

### Upload a File

The upload endpoint accepts the raw file as the request body. Pass the original filename in `x-amigo-intake-filename` and the declared MIME type in `x-amigo-intake-content-type`.

{% openapi src="<https://api.platform.amigo.ai/v1/openapi.json>" path="/upload/{link\_token}/files" method="post" %}
<https://api.platform.amigo.ai/v1/openapi.json>
{% endopenapi %}

The endpoint is limited to 10 upload requests per minute and 100 MB per file. Exhausting the link's upload count also returns `429`.

Allowed MIME types are:

* `application/pdf`
* `text/csv`
* `text/markdown`
* `image/jpeg`
* `image/png`
* `application/msword`
* `application/vnd.openxmlformats-officedocument.wordprocessingml.document`
* `application/vnd.ms-powerpoint`
* `application/vnd.openxmlformats-officedocument.presentationml.presentation`

The service verifies that the declared type is allowlisted and performs limited header inspection. CSV receives a UTF-8 and header-shape check; images require recognizable signatures; other formats have narrower checks. This is not a complete document parser and does not establish that a file is safe.

Malware scanning is deployment-dependent:

* When configured, the file is scanned before persistence. Infected files return `422`; scanner unavailability returns `503`.
* When not configured, the file is accepted without a malware verdict and the response reports `scan_status: skipped`.

### Upload Receipt and Duplicates

A successful response includes `id`, `filename`, `sha256`, `size_bytes`, `scan_status`, and optional `duplicate_of`.

Duplicate lookup is workspace-wide across link and separately provisioned integration uploads. A match is informational: the new file is still stored and `duplicate_of` points to the earliest matching upload.

Storage completes before best-effort intake-event emission. A `201 Created` response confirms the upload record and file bytes, but it does not confirm downstream event delivery, dataset processing, or world-model projection.

## Link Status Values

| Status      | Meaning                                          |
| ----------- | ------------------------------------------------ |
| `active`    | Unexpired, unrevoked, and below the upload limit |
| `expired`   | Expiration time has passed                       |
| `revoked`   | An operator revoked the token                    |
| `exhausted` | Upload count reached `max_uploads`               |


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.amigo.ai/developer-guide/platform-api/data-world-model/intake-links.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
