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

# Get an Upload URL

> Get a short-lived, signed URL to upload a file directly to storage.

The first step of the two-step upload flow described in [File Uploads](/essentials/file-uploads) — the SDK's `client.form(id).upload()` (or automatic `File`/`FileList` detection inside `submit()`) does this for you; call it directly only if you're building a fully custom upload UI.

<ParamField path="public_id" type="string" required>
  The form's public ID.
</ParamField>

<ParamField body="fieldId" type="string" required>
  The schema field this file belongs to — must be a `file`/`image`/`signature`/`video`/`audio` type field that actually exists on the form.
</ParamField>

<ParamField body="fileName" type="string" required>
  Original filename, stored alongside the upload for later display/download.
</ParamField>

<ParamField body="contentType" type="string" required>
  Declared MIME type. Checked against the field's `allowedTypes` at this step — but not trusted blindly; the actual uploaded bytes are re-verified after the PUT completes.
</ParamField>

<ParamField body="sizeBytes" type="number" required>
  Declared file size. Checked against the field's `maxSizeMB` and your plan's per-file/total storage limits.
</ParamField>

### Response

<ResponseField name="path" type="string">
  Internal storage path — pass this (wrapped in a file reference object) as the field's value on [Submit a Form](/api-reference/submit-form).
</ResponseField>

<ResponseField name="uploadUrl" type="string">
  A signed URL, valid for a short window — `PUT` the raw file bytes here directly. This request never touches your server or Raykoi's API.
</ResponseField>

<ResponseField name="uploadToken" type="string">
  Internal bookkeeping ID — not needed for the upload itself.
</ResponseField>

<ResponseField name="supabaseToken" type="string">
  If present, include as `Authorization: Bearer <supabaseToken>` on the `PUT` to `uploadUrl`.
</ResponseField>

<RequestExample>
  ```bash Step 1 — get the URL theme={null}
  curl -X POST "https://api.raykoi.com/api/v1/forms/p/YOUR_PUBLIC_ID/upload-url" \
    -H "Content-Type: application/json" \
    -d '{"fieldId": "resume", "fileName": "resume.pdf", "contentType": "application/pdf", "sizeBytes": 204800}'
  ```

  ```bash Step 2 — upload the bytes theme={null}
  curl -X PUT "$UPLOAD_URL" \
    -H "Content-Type: application/pdf" \
    --data-binary @resume.pdf
  ```
</RequestExample>

<ResponseExample>
  ```json 200 Success theme={null}
  {
    "path": "submissions/YOUR_PUBLIC_ID/resume/a1b2c3-resume.pdf",
    "uploadUrl": "https://storage.example.com/...",
    "uploadToken": "tok_abc123",
    "supabaseToken": "eyJ..."
  }
  ```
</ResponseExample>

<Warning>
  This endpoint alone doesn't attach the file to a submission — the returned `path` still has to be included in the actual `POST` to [Submit a Form](/api-reference/submit-form). An upload URL that's never followed by a matching submission is swept up by a cleanup job and never becomes a permanent file.
</Warning>
