Skip to content

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:

  1. Reserve - POST /api/v2/uploads/create returns a presigned PUT URL and an opaque upload_reference.
  2. Upload - PUT the file bytes to the URL before it expires. No Intuizi authentication on this request - the signature in the URL is the credential.
  3. Create - pass upload_reference to the create endpoint that matches the reserved purpose: Create Submission by Upload for poi_submission, or Create Cohort for cohort.

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

FieldTypeRequiredDescription
purposestringYesWhat the upload is for: poi_submission or cohort. Determines where the file is stored and its size cap.
filenamestringNoThe 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_lengthintegerYesThe 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_typestringNoThe 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.csv

Response

{
  "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_reference is the only value you pass onwards - the create endpoints never take the URL.
  • upload_url is valid until expires_at, and a create has to claim the reference before then too. If it expires before the PUT completes 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 PUT succeeded.
  • Reserve and upload again if the file changes - a reference always points at exactly the bytes that were PUT for it.

The Idempotency-Key header is not used on this endpoint: reserving a slot creates no resource, and an unused reservation simply expires.