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

# Provisioning tokens

export const Framed = ({image, background, link, alt = "Framed content", borderWidth = "24px", outerRadius = "10px", innerRadius = "6px"}) => {
  const parseShorthand = value => {
    const values = String(value).trim().split(/\s+/);
    switch (values.length) {
      case 1:
        return [values[0], values[0], values[0], values[0]];
      case 2:
        return [values[0], values[1], values[0], values[1]];
      case 3:
        return [values[0], values[1], values[2], values[1]];
      default:
        return values.slice(0, 4);
    }
  };
  const isZero = v => parseFloat(v) === 0;
  const padding = parseShorthand(borderWidth);
  const outer = parseShorthand(outerRadius);
  const cornerMasks = [];
  if (isZero(padding[0]) && isZero(padding[3])) {
    cornerMasks.push(`radial-gradient(circle at 0% 0%, transparent ${outer[0]}, black ${outer[0]})`);
  }
  if (isZero(padding[0]) && isZero(padding[1])) {
    cornerMasks.push(`radial-gradient(circle at 100% 0%, transparent ${outer[1]}, black ${outer[1]})`);
  }
  if (isZero(padding[2]) && isZero(padding[1])) {
    cornerMasks.push(`radial-gradient(circle at 100% 100%, transparent ${outer[2]}, black ${outer[2]})`);
  }
  if (isZero(padding[2]) && isZero(padding[3])) {
    cornerMasks.push(`radial-gradient(circle at 0% 100%, transparent ${outer[3]}, black ${outer[3]})`);
  }
  const backgroundMask = cornerMasks.length > 0 ? cornerMasks.join(", ") : undefined;
  const innerImage = <img src={image} alt={alt} noZoom={link ? true : false} style={{
    display: "block",
    width: "100%",
    margin: 0,
    borderRadius: 0
  }} />;
  return <div style={{
    display: "inline-block",
    position: "relative",
    borderRadius: outerRadius,
    overflow: "hidden"
  }}>
            {}
            {background && <div style={{
    position: "absolute",
    inset: 0,
    backgroundImage: `url(${background})`,
    backgroundSize: "cover",
    maskImage: backgroundMask,
    WebkitMaskImage: backgroundMask,
    maskComposite: "intersect",
    WebkitMaskComposite: "source-in"
  }} />}
            {}
            <div style={{
    position: "relative",
    padding: borderWidth
  }}>
                <div style={{
    borderRadius: innerRadius,
    overflow: "hidden",
    lineHeight: 0
  }}>
                    {link ? <a href={link}>{innerImage}</a> : innerImage}
                </div>
            </div>
        </div>;
};

<Framed background="https://assets.mirurobotics.com/docs/v04/images/devices/background.jpeg" image="https://assets.mirurobotics.com/docs/v04/images/devices/provisioning/header:create-token.png" innerRadius="8px" outerRadius="12px" borderWidth="42px 38px 42px 38px" />

To programmatically provision devices, Miru offers provisioning tokens.

Provisioning tokens are only supported when installing `miru-agent` version `v0.9.0` or later. If installing a version that precedes `v0.9.0`, continue to use the [provisioning script](/learn/devices/provision/provisioning-script).

Unlike the dashboard, which requires manual interaction with the web interface for each device, provisioning tokens allow you to:

* **Provision multiple devices** without manual intervention
* **Integrate with existing infrastructure** management tools and workflows
* **Use in headless environments** where a web browser isn't available

## Install the `miru-agent` package

Before provisioning a device via provisioning tokens, you must first install the `miru-agent` package onto the target machine.

The recommended method is via `apt` (shown below). However, you can also manually download the package from GitHub. Visit the [agent installation](/developers/agent/install) documentation for more information.

<Steps>
  <Step title="Set up">
    Set up Miru's `apt` repository.

    ```bash theme={null}
    # ensure the appropriate dependencies are installed
    sudo apt-get update
    sudo apt-get install -y ca-certificates curl gnupg

    # add Miru's signing key
    sudo install -m 0755 -d /etc/apt/keyrings
    curl -fsSL https://packages.mirurobotics.com/apt/miru.gpg -o /tmp/miru.gpg.armor
    sudo gpg --dearmor -o /etc/apt/keyrings/miru-archive-keyring.gpg /tmp/miru.gpg.armor
    rm /tmp/miru.gpg.armor
    sudo chmod a+r /etc/apt/keyrings/miru-archive-keyring.gpg

    # add the repository to your sources list
    sudo tee /etc/apt/sources.list.d/miru.sources > /dev/null <<EOF
    Types: deb
    URIs: https://packages.mirurobotics.com/apt
    Suites: stable
    Components: main
    Architectures: $(dpkg --print-architecture)
    Signed-By: /etc/apt/keyrings/miru-archive-keyring.gpg
    EOF
    ```
  </Step>

  <Step title="Install">
    After configuring the `apt` repository, install the agent.

    ```bash theme={null}
    sudo apt-get update
    sudo apt-get install miru-agent
    ```

    <Tip>
      Install a specific version with `sudo apt-get install miru-agent=<version>` (e.g. `0.7.0`, `0.8.0`, etc.).
    </Tip>
  </Step>
</Steps>

## Create a provisioning token

Provisioning tokens are created via the [Platform API](/references/platform-api/2026-05-06/endpoints/provisioning-tokens/create) endpoint using [API keys](/admin/apikeys).

**Create the API key**

If you don't have an API key, follow the instructions for [creating an API key](/admin/apikeys#create-an-api-key). The API key requires the `devices:provision` and `provisioning_tokens:write` scopes.

**Create the token**

Once you have an API key, you can create a token using the following code samples. Keep in mind that tokens are short-lived (expire in 5 minutes) and one-time use only.

<CodeGroup>
  ```bash bash theme={null}
  export MIRU_API_KEY=<api-key>

  curl --request POST \
    --url https://api.mirurobotics.com/beta/provisioning_tokens \
    --header 'Miru-Version: 2026-05-06.rainier' \
    --header "X-API-Key: $MIRU_API_KEY"
  ```

  ```python python theme={null}
  import os
  from miru_platform_sdk import Miru

  client = Miru(
      api_key=os.environ.get("MIRU_API_KEY"), 
  )
  provisioning_token = client.provisioning_tokens.create()
  # access token via provisioning_token.token
  ```
</CodeGroup>

## Provision the device

After retrieving the provisioning token, run the following command. Make sure to replace `<token>` with the actual token.

```bash theme={null}
sudo -u miru MIRU_PROVISIONING_TOKEN=<token> \
  /usr/sbin/miru-agent provision
```

The command can be broken into the following components:

* `sudo -u miru` sets the command to run as the `miru` user.
* `MIRU_PROVISIONING_TOKEN=<token>` authenticates the request.
* `/usr/sbin/miru-agent provision` executes the `miru-agent` binary with the `provision` command.

Provisioning performs the following actions:

1. **Creates the device** - creates a new device in the Miru dashboard (if a device with the provided name doesn't already exist).
2. **Provisions the device** - registers the agent with the Miru control plane.

### Troubleshooting

If the machine you're provisioning on has already been provisioned, the provisioning command is treated as a no-op and exits successfully.

To reassociate the machine with an existing Miru device, follow the [reprovisioning](/learn/devices/provision/reprovision) documentation.

To provision the machine as a brand new Miru device (never been provisioned in Miru before), first [uninstall](/developers/agent/install#uninstall) the `miru-agent` package before continuing with the provisioning process.

### Arguments

The provision command supports the following parameters to tune your installation:

<ParamField path="--device-name" type="string">
  The name of the device in the Miru dashboard; defaults to `$HOSTNAME`.

  Default: `$HOSTNAME`
</ParamField>

## Verify installation

To verify the agent was successfully installed and provisioned, navigate to the [Devices page](https://app.mirurobotics.com/devices). You should see your device listed with the status `Activating` before transitioning to `Online`.

<Info>
  The transition from `Activating` to `Online` may take up to 10 seconds, depending on your network connection.
</Info>
