---
title: "Create a direct upload session for a local file"
method: POST
path: "/api/artifact-uploads"
tags: ["Uploads"]
---

# Create a direct upload session for a local file

`POST /api/artifact-uploads`

## Request

- Base URL: `https://courseprofiler.com`
- URL: `https://courseprofiler.com/api/artifact-uploads`
- Auth: one of:
  - API key in header `X-API-Key`
  - HTTP bearer
  - none

Upload bridge for clients and AI assistants with local/sandbox files. Creates a short-lived pre-signed upload target. Complete the session to register an opaque source_file artifact ID.

## Request body

- ArtifactUploadCreateRequest
  - `file_name` string, required
  - `content_type` string, required
  - `size_bytes` integer, required
  - `purpose` 'course_source' | 'runner_evidence' | 'usrprof_source' | 'generic_source', required: Upload purpose. Use `usrprof_source` when uploading an existing local `.usrprof` runner profile; completed `source_file` artifacts can then be passed through `runner.sources` or `/api/usrprof/imports`.
  - `checksum` ArtifactUploadChecksum
    - `algorithm` 'sha256', required
    - `value` string, required
  - `metadata` object

## Response `201`

Upload session created

- ArtifactUploadSession
  - `upload_id` string, required
  - `status` 'waiting_for_upload' | 'uploaded' | 'completed' | 'failed' | 'expired' | 'cancelled', required
  - `upload` ArtifactUploadTarget
    - `method` 'PUT', required
    - `url` string, uri, required: Private pre-signed direct-upload URL.
    - `headers` object: Headers that must be replayed exactly on the direct PUT upload request. Missing or changed headers can invalidate the pre-signed URL.
    - `expires_at` string, date-time, required
    - `max_size_bytes` integer, required
  - `complete_url` string
  - `artifact_id` string: Present after completion.
  - `created_at` string, date-time
  - `expires_at` string, date-time, required
  - `warnings` ApiProblem[]
    - `code` string, required
    - `message` string, required
    - `severity` 'info' | 'warning' | 'error', required
    - `field` string
    - `details` object

## Other responses

- `400`: Invalid request
- `413`: Payload too large
- `429`: Rate limit exceeded

---

[API](https://skmtc.dev/courseprofiler/apis/courseprofiler-public-api.md) · [All operations](https://skmtc.dev/courseprofiler/apis/courseprofiler-public-api/llms.txt) · [OpenAPI document](https://skmtc.dev/courseprofiler/apis/courseprofiler-public-api/revisions/e07403d7dba9?raw)
