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

> ## Agent Instructions
> For Fireworks Nexus, start at https://docs.fireworks.ai/nexus.
> Use https://docs.fireworks.ai/nexus/quickstart for coding harnesses, custom agents, APIs, SDKs, and LLM gateways.
> Use https://docs.fireworks.ai/nexus/firerouter for how model routers work, the supported model list, composition, closed-model credentials, and pricing.
> Prefer canonical short model IDs such as firerouter/opus. In LiteLLM litellm_params.model, use the full path fireworks_ai/accounts/fireworks/routers/firerouter/opus.
> Family names such as opus track the latest evaluated family version; do not describe them as fixed model versions.

# Upload via REST API

> Programmatically upload custom models using the Fireworks REST API

Use the Fireworks REST API to upload custom models programmatically — ideal for automation, CI/CD pipelines, and notebooks. If you just want the quickest path from a terminal, use [`firectl`](/models/uploading-custom-models#uploading-your-model) instead.

## The upload pipeline

Uploading a model via the REST API is a four-step pipeline:

1. **Create the model** – Register a model object that references the files you're about to upload.
2. **Get upload URLs** – Request a signed URL for each file.
3. **Upload the files** – Upload each file directly to its signed URL.
4. **Validate the upload** – Finalize the upload and move the model to `READY`.

<Warning>
  Step 4 is required. Until you call `validateUpload`, your model stays in the `UPLOADING` state and **cannot be deployed** — even after every file has finished uploading.
</Warning>

## Why validation is a separate step

Transfer and validation are decoupled because uploads can arrive several ways (signed-URL upload, S3 import, Azure import) and the transfer runs asynchronously on Fireworks infrastructure. The `validateUpload` call is what:

* Confirms every expected file has landed and is intact.
* Parses your model config to detect architecture, precision, and context length.
* Transitions the model from `UPLOADING` to `READY` so it can be deployed.

Because the transfer is asynchronous, `validateUpload` returns `FAILED_PRECONDITION` while files are still landing. Poll it until it returns `200` — at that point the model is `READY`.

## Full example

This script runs the entire pipeline end to end. Set your API key, account ID, model ID, and the local folder containing your Hugging Face model files.

```python theme={null}
import os
import time
import requests

# --- Configuration ---
API_KEY = os.environ["FIREWORKS_API_KEY"]
ACCOUNT_ID = "your-account-id"
MODEL_ID = "my-custom-model"
MODEL_PATH = "/path/to/model/files/"  # folder of Hugging Face files: config.json, *.safetensors, tokenizer, ...

BASE_URL = "https://api.fireworks.ai/v1"
HEADERS = {"Authorization": f"Bearer {API_KEY}", "Content-Type": "application/json"}

files = [f for f in os.listdir(MODEL_PATH) if os.path.isfile(os.path.join(MODEL_PATH, f))]
file_sizes = {f: os.path.getsize(os.path.join(MODEL_PATH, f)) for f in files}

# --- Step 1: Create the model ---
requests.post(
    f"{BASE_URL}/accounts/{ACCOUNT_ID}/models",
    headers=HEADERS,
    json={
        "modelId": MODEL_ID,
        "model": {
            "kind": "HF_BASE_MODEL",
            "huggingFaceUrl": "https://huggingface.co/<ORG>/<MODEL>",
            "baseModelDetails": {
                "checkpointFormat": "HUGGINGFACE",
                "worldSize": 1,
                "huggingfaceFiles": files,
            },
        },
    },
).raise_for_status()
print(f"Created model {MODEL_ID}")

# --- Step 2: Get a signed upload URL for each file ---
resp = requests.post(
    f"{BASE_URL}/accounts/{ACCOUNT_ID}/models/{MODEL_ID}:getUploadEndpoint",
    headers=HEADERS,
    json={"filenameToSize": file_sizes, "enableResumableUpload": False},
)
resp.raise_for_status()
upload_urls = resp.json()["filenameToSignedUrls"]

# --- Step 3: Upload each file to its signed URL ---
for filename, url in upload_urls.items():
    size = file_sizes[filename]
    with open(os.path.join(MODEL_PATH, filename), "rb") as f:
        requests.put(
            url,
            data=f,
            headers={
                "Content-Type": "application/octet-stream",
                "x-goog-content-length-range": f"{size},{size}",
            },
        ).raise_for_status()
    print(f"Uploaded {filename}")

# --- Step 4: Validate — poll until the model is READY ---
validate_url = f"{BASE_URL}/accounts/{ACCOUNT_ID}/models/{MODEL_ID}:validateUpload"
while True:
    resp = requests.get(validate_url, headers=HEADERS)
    if resp.status_code == 200:
        print("Model validated and ready to deploy!")
        break
    if "FAILED_PRECONDITION" in resp.text:  # files still landing
        print("Files still finalizing, retrying in 30s...")
        time.sleep(30)
        continue
    resp.raise_for_status()  # any other error is fatal
```

<Note>
  Set `huggingFaceUrl` if this uploaded custom base model should be considered for Fireworks managed training. Fireworks uses the Hugging Face URL to infer the training renderer and locate compatible training shapes. The tunability check runs asynchronously about every 30 minutes, so `Tunable: true` may take up to 30 minutes to appear after the URL is set.
</Note>

<Tip>
  Every step is safe to retry. `create` and `getUploadEndpoint` no-op if the model already exists (returning `ALREADY_EXISTS`), so an automated uploader that gets interrupted can simply re-run from the top and keep polling `validateUpload` until it succeeds.
</Tip>

## Troubleshooting: model stuck in `UPLOADING`

The most common cause is that `validateUpload` was never called — files transferring successfully does not move the model to `READY` on its own. Call the endpoint (and poll it):

```bash theme={null}
curl -X GET "https://api.fireworks.ai/v1/accounts/<ACCOUNT_ID>/models/<MODEL_ID>:validateUpload" \
  -H "Authorization: Bearer $FIREWORKS_API_KEY"
```

If it returns `FAILED_PRECONDITION`, files are still landing — wait and retry. If it keeps failing after the transfer should be complete, confirm that every [required file](/models/uploading-custom-models#required-files) was included.

## Next steps

1. **Verify**: `firectl model get accounts/<ACCOUNT_ID>/models/<MODEL_ID>` — look for `State: READY`.
2. **Deploy**: see the [Custom Models guide](/models/uploading-custom-models#deploying-your-model) for deployment instructions.
