# Uploads


Send a POI or cohort file to Intuizi. [Conventions](/cli/reference#conventions) apply to
every command here.

Uploading is three steps. Reserve a slot, which returns a presigned URL and a
reference. PUT the bytes to that URL. Then pass the reference to a cohort or
POI submission create. `uploads put` runs the first two and prints the
reference, and the create is a separate command. `uploads reserve` runs only
the first, for a caller that wants to do its own PUT.

A reference can only be claimed by the create that matches its `--purpose`:
`cohorts create --upload-reference` for a `cohort` upload, and
`poi submissions create --upload-reference` for a `poi_submission` upload. It
is single-use: 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
purpose's size cap, and a POI file that fails validation all use the reference
up, so upload the file again for a new one before retrying.

A create that fails with `No file has been uploaded for this reference yet.`
leaves the reference usable until `expires_at`. The message has two causes. If
the PUT had not finished, finish it and run the create again. If the file is a
POI file with only a header row and no data rows, running the create again
gets the same error every time: add the rows and upload the file again for a
new reference. `uploads put` prints a reference only after its PUT has
succeeded, so for a reference it printed, the cause is always the second one.
A cohort create that fails with `Error occurred, please try again.` also leaves
the reference usable, so run the create again.
`cohorts preview --upload-reference` reads a cohort upload without claiming it.

A build-budget refusal of `cohorts create --upload-reference` is not retried,
because the refused attempt has already used the reference. The CLI prints the
`429` as it came, ending with its `Retry-After` (for example
`(429, Retry-After: 1800s)`), and adds that the file has to be uploaded again
for a new reference. Check `intuizi usage --json | jq .data.build_budget` and
upload the file again once the budget has room. `intuizi usage` requires
additional permissions which need to be approved by your Account Manager (see
[Usage](/cli/reference/usage)).

A reference also has to be claimed before the reservation's `expires_at`, the
presigned URL expiry on [Limits & Quotas](/concepts/limits#uploads). The clock
starts at the reservation, so the upload time of a large file counts against
it. A create after `expires_at` is rejected even when the PUT succeeded, and
the file has to be uploaded again for a new reference. `cohorts preview` does
not check the deadline, so a preview that works does not mean the reference
can still be claimed. `uploads put` prints only the reference, so run the
create soon after it, or read `expires_at` from `--json`. It is written as
`YYYY-MM-DD HH:MM:SS` in server time with no offset, so rather than compare it
with your local clock, count the window from the reservation.

## Put

Upload a file and print the reference a create command consumes.
See [Create an Upload](/api/v2/uploads#post-apiv2uploadscreate).

| Flag | Input |
| --- | --- |
| `--purpose` | what the upload is for, required |
| `--content-type` | the MIME type to send, `text/csv` by default |

The file is the command's argument, and its name and size go into the
reservation. So a `poi_submission` file's name must end in `.csv` or `.txt`, and
the name of a `cohort` file decides whether it imports as one file or as a
folder (see [Cohorts](/cli/reference/cohorts#create)). The accepted `--purpose` values are on
[Create an Upload](/api/v2/uploads#post-apiv2uploadscreate).

The reference is the only thing printed on stdout, so it can be captured and
passed to the create:

```bash
ref=$(intuizi uploads put customers.csv --purpose cohort)
intuizi cohorts create --name "Q3 customers" --upload-reference "$ref" \
  --file-format csv --identifier-type hem_sha256 \
  --identifier-column email_sha256
```

With `--json`, `put` prints the reservation envelope instead, once the PUT has
succeeded, so `.data[0].upload_reference` is the same value.

## Reserve

Reserve a slot and print its presigned URL without transferring anything, for
a caller that wants to do its own PUT.
See [Create an Upload](/api/v2/uploads#post-apiv2uploadscreate).

| Flag | Input |
| --- | --- |
| `--purpose` | what the upload is for, required |
| `--filename` | original filename, used to name the stored object. A `poi_submission` filename must end in `.csv` or `.txt`, and a `cohort` filename decides file or folder import |
| `--content-length` | exact byte size of the file that will be sent, required |
| `--content-type` | the MIME type the PUT will send, `text/csv` by default |

PUT the file to `upload_url` with the `headers` the reservation returned, then
claim the reference with a create, both before `expires_at`. The table shows `headers` as `{...}`, so a script reads
`upload_url`, `headers`, and `upload_reference` from `--json`:

```bash
intuizi uploads reserve --purpose cohort --filename customers.csv \
  --content-length 1048576 --json
```

The purpose's size cap applies to `--content-length` here, and again to the
bytes actually uploaded when a create claims the reference.

{{< cards >}}
  {{< card link="/developers/cli/reference/poi/" title="POI" subtitle="Manage your own POI data." >}}
  {{< card link="/developers/cli/reference/catalogs/" title="Catalogs" subtitle="Read the ids every other command needs." >}}
{{< /cards >}}
