---
title: "Register a new machine (returns a single-use install secret)"
method: POST
path: "/api/add_new_machine/"
tags: ["Machines"]
---

# Register a new machine (returns a single-use install secret)

`POST /api/add_new_machine/`

## Request

- Base URL: `https://eyalsec.com`
- URL: `https://eyalsec.com/api/add_new_machine/`
- Auth: one of:
  - API key in header `X-API-Key`
  - API key in cookie `__Host-es2session`

Creates a machine row owned by the caller. It serves es-python and es-chromium; every other product is registered at POST /scanner/<product>/generate, which returns the machine's token and its install command in one response, and naming one here is a 422 that says where to go. Which fields apply depends on product: es-python (the default) takes either nothing (the build is detected on the host when its install runs: os_type and python_version are stored as auto and resolved by /install.sh from what the install command reports) or a distro+arch pair (os_type = distro_arch, validated against the supported targets) with a python_version that must be available for that target (422 otherwise; see GET /api/supported_python_versions/?os=); python_version=auto picks the host's own version at install. es-chromium takes the name alone. A new es-python machine gets machine-scope socket=on and file=on taint settings for each of the two the account has not set account-wide. You must hold the product you name (403 otherwise). Enforced atomically against the caller's machine limit, which is counted PER PRODUCT, so a full es-python allowance does not consume the es-chromium one (409 when at cap). Cookie callers must pass CSRF; API-key callers are exempt.

This is a **write**: a read-only API key is refused with 403.

## Response `200`

OK. For example:

```
{
  "Name": "web-01",
  "OsType": "auto",
  "Status": "created",
  "PublicID": "<public_id>",
  "PythonVersion": "auto",
  "SocketOnly": "false",
  "AgentKind": "python"
}

// product=browser omits the es-python-only fields:
{
  "Name": "test-browser",
  "OsType": "",
  "Status": "created",
  "PublicID": "<public_id>",
  "AgentKind": "browser"
}
```

- object

## Other responses

- `401`: The API key is missing, wrong, revoked or expired.
- `429`: A rate limit was hit, or the account is locked after wrong passwords. Retry-After gives the seconds to wait.
- `default`: An error. Check the status first; the body carries a short message, as JSON ({"error": "..."}) on most endpoints and as plain text on some. 400: malformed JSON, an invalid regex, an unreadable cursor or date, or an unknown value. 401: the API key is missing, wrong, revoked or expired. 403: a failed CSRF check, a read-only key trying to write, a product or feature not enabled on your account, a wrong password, or a write on an account limited to reading. 404: not found, including things that belong to another account. 409: conflict with the current state. 422: a field is missing or invalid. 429: a rate limit was hit, or the account is locked after wrong passwords. 500: something failed on our side.

---

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