Uploads
Upload a file to Intuizi without owning any cloud storage. The upload flow is a three-step primitive shared by POI submissions and Cohorts:
- Reserve -
POST /api/v2/uploads/createreturns a presignedPUTURL and an opaqueupload_reference. - Upload -
PUTthe file bytes to the URL before it expires. No Intuizi authentication on this request - the signature in the URL is the credential. - Create - pass
upload_referenceto the create endpoint that matches the reserved purpose: Create Submission by Upload forpoi_submission, or Create Cohort forcohort.
The presigned URL is a one-key, short-lived write credential: it can write
exactly one object, cannot read or list anything, and expires 15 minutes after
it is issued. The upload_reference is one-shot - once a create has used
it, it cannot be used again. A cohort create refused by the build budget or the
data-scan limit, a file over the size cap, and a POI file that fails validation
all use it up. A POI file is checked at its start when the create is called, and
in full when Intuizi reads its locations (see
Create Submission by Upload).
A cohort create that fails with a generic error leaves it
usable until expires_at, so send the create again. So does a create rejected
with No file has been uploaded for this reference yet., which has two
causes. If the PUT had not finished, finish it and send the create again. If
a poi_submission file has a header row but no data rows, the create fails
the same way every time, so add the rows and upload the file again for a new
reference. A reference must also be claimed before expires_at: a create
after that is rejected even if the PUT succeeded. An uploaded file that is
never claimed is removed automatically within 24 hours.
Your organization can have up to 20 open uploads at once. An upload is open
from its reservation until a create has used its upload_reference up, or
until expires_at, whichever comes first. A reservation past the limit is
refused with 429, and nothing is
reserved. Its Retry-After header gives the seconds until the first open
upload expires, and a create that uses up one of the open references makes
room sooner. An open upload cannot be released early. See
Limits & Quotas.
Create an Upload
POST /api/v2/uploads/create
Reserves an upload slot and returns the presigned PUT URL plus the
upload_reference the create endpoints accept.
Auth: bearer token + Accept: application/json + Content-Type: application/json. Rate limit: write bucket (30 requests/min).
Body
| Field | Type | Required | Description |
|---|---|---|---|
purpose | string | Yes | What the upload is for: poi_submission or cohort. Determines where the file is stored and its size cap. |
filename | string | No | The original filename, used to name the stored object. A poi_submission filename must end in .csv or .txt. For a cohort upload the name also decides how the file is imported: a name ending .csv, .gz, or .parquet (case-sensitive) imports as one file, and any other name as a folder. Left out, the object is named upload.csv. |
content_length | integer | Yes | The exact byte size of the file you will PUT. Must not exceed the purpose’s cap - 50 MB for poi_submission, 1 GB for cohort (the cap is echoed back as max_content_length). |
content_type | string | No | The MIME type your PUT will send. Defaults to text/csv. |
curl -X POST "https://console.intuizi.com/api/v2/uploads/create" \
-H "Authorization: Bearer <YOUR_TOKEN>" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{
"purpose": "cohort",
"filename": "devices.csv",
"content_length": 1048576
}'
# Then PUT the file to the returned upload_url with the returned headers:
curl -X PUT "<UPLOAD_URL>" \
-H "Content-Type: text/csv" \
--data-binary @devices.csvResponse
{
"status": "success",
"code": 201,
"message": "Resource created successfully.",
"data": [
{
"upload_reference": "upl_01k0p3v9example",
"upload_url": "https://s3.us-west-2.amazonaws.com/...?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Expires=900&X-Amz-Signature=...",
"method": "PUT",
"headers": { "Content-Type": "text/csv" },
"expires_at": "2026-07-21 14:35:00",
"max_content_length": 1073741824
}
]
}upload_referenceis the only value you pass onwards - the create endpoints never take the URL.upload_urlis valid untilexpires_at, and a create has to claim the reference before then too. If it expires before thePUTcompletes or before the create, reserve a new upload. An expired upload no longer counts toward the open upload limit.- A file larger than the reserved cap is rejected when the reference is
claimed, so the size gate holds even if the
PUTsucceeded. - Reserve and upload again if the file changes - a reference always points at
exactly the bytes that were
PUTfor it.
The Idempotency-Key header is not used on this endpoint: reserving a slot
creates no resource, and an unused reservation simply expires.