> For the complete documentation index, see [llms.txt](https://docs.m-xr.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.m-xr.com/marso-studio-api/getting-started/quick-start.md).

# Quick start

This guide generates a PBR material from one 3D mesh.

{% stepper %}
{% step %}

### Get an API key

Create a key in the Marso Studio dashboard. Set it as the environment variable `MARSO_API_KEY`.
{% endstep %}

{% step %}

### Upload the mesh

Call `POST /uploads` to get a presigned upload URL. Send the raw bytes to that URL. Poll `GET /uploads/{asset_id}` until the status is `ready`.
{% endstep %}

{% step %}

### Generate the material

Call `POST /pbr/execute/mesh` with the ready asset ID. Poll `GET /pbr/executions/{execution_id}` until the run reaches a terminal state. Then download each generated map.
{% endstep %}
{% endstepper %}

#### Full example

This script does all 3 steps. It needs Python 3.8 or later and the `requests` package. Give it the path to a `.usd` or `.glb` file.

```python
import os
import pathlib
import sys
import time

import requests

BASE_URL = "https://api.marso.ai/api/public/v1"
AUTH = {"Authorization": f"Bearer {os.environ['MARSO_API_KEY']}"}
TERMINAL = {"SUCCEEDED", "PARTIAL_SUCCEEDED", "FAILED"}


def upload_mesh(path):
    """Step 1. Mint a presigned URL, send the bytes, wait for validation."""
    data = path.read_bytes()
    mint = requests.post(
        f"{BASE_URL}/uploads",
        headers=AUTH,
        json={"filename": path.name, "size_bytes": len(data)},
        timeout=30,
    )
    mint.raise_for_status()
    upload = mint.json()

    # Send the returned headers verbatim. Each one is signed into the URL.
    requests.put(
        upload["upload_url"],
        headers=upload["headers"],
        data=data,
        timeout=300,
    ).raise_for_status()

    asset_id = upload["asset_id"]
    while True:
        poll = requests.get(
            f"{BASE_URL}/uploads/{asset_id}", headers=AUTH, timeout=30
        )
        poll.raise_for_status()
        status = poll.json()["status"]
        if status == "ready":
            return asset_id
        if status == "rejected":
            raise SystemExit(f"the file failed validation: {path.name}")
        time.sleep(2)


def generate_pbr(asset_id):
    """Steps 2 and 3. Submit the mesh, then poll until the run is terminal."""
    submit = requests.post(
        f"{BASE_URL}/pbr/execute/mesh",
        headers=AUTH,
        json={"asset_id": asset_id},
        timeout=30,
    )
    submit.raise_for_status()
    execution_id = submit.json()["execution_id"]

    while True:
        poll = requests.get(
            f"{BASE_URL}/pbr/executions/{execution_id}", headers=AUTH, timeout=30
        )
        poll.raise_for_status()
        execution = poll.json()
        if execution["status"] in TERMINAL:
            return execution
        time.sleep(5)


def main():
    execution = generate_pbr(upload_mesh(pathlib.Path(sys.argv[1])))
    if execution["status"] == "FAILED":
        raise SystemExit(f"the run failed: {execution['error']['message']}")

    # Each key is "<slot>/<pass>". Each value has a presigned download URL.
    for name, asset in execution["pbr_material_assets"].items():
        output = pathlib.Path(name.replace("/", "_"))
        output.write_bytes(requests.get(asset["download_url"], timeout=300).content)
        print(f"saved {output}")


if __name__ == "__main__":
    main()
```


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.m-xr.com/marso-studio-api/getting-started/quick-start.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
