The REST API provides a modern HTTP-based interface for controlling **PolyscopeX** robots. It replaces the legacy Dashboard Server on new UR controllers.

> **PolyscopeX only**: This API is available exclusively on robots running PolyscopeX. For cobots with Polyscope, use the [Dashboard Server](/universal-robots/documentation/remote-commands).

## Quick Start

```csharp
using UnderAutomation.UniversalRobots;

var robot = new UR();

// Connect with REST API enabled
robot.Connect(new ConnectParameters("192.168.0.1")
{
    Rest = { Enable = true }
});

// Control the robot
robot.Rest.PowerOn();
robot.Rest.BrakeRelease();
robot.Rest.LoadProgram("my_program");
robot.Rest.Play();

// Get program state
var state = robot.Rest.GetProgramState();
Console.WriteLine($"State: {state.Value.State}"); // Playing, Stopped, Paused
```

## Standalone Client

Use `RestClient` independently from the main `UR` class:

```csharp
using UnderAutomation.UniversalRobots.Rest;

var client = new RestClient();
client.Enable("192.168.0.1");

client.PowerOn();
client.LoadProgram("my_program");
client.Play();

client.Disable();
```

### Enable Remote Mode

Your robot must be in **Remote** mode to accept commands. Toggle the switch at the top right of PolyscopeX:

> Default password is `operator`

![switch remote](/universal-robots/switch-remote-polyscopex.png)

## Connection Parameters

Configure the REST client via `RestConnectParameters`:

| Property | Type | Default | Description |
|----------|------|---------|-------------|
| `Enable` | `bool` | `false` | Enable REST API client |
| `Port` | `int` | `80` | HTTP port |
| `Version` | `RestApiVersion` | `Latest` | API version (`V1`, `Latest`) |
| `TimeoutMs` | `int` | `5000` | Request timeout in milliseconds |

```csharp
robot.Connect(new ConnectParameters("192.168.0.1")
{
    Rest = 
    { 
        Enable = true,
        Port = 80,
        Version = RestApiVersion.V1,
        TimeoutMs = 10000
    }
});
```

## Robot State Control

Control the robot's operational state:

### PowerOn

Power on the robot.

```csharp
RestApiResponse response = robot.Rest.PowerOn();
if (response.Succeed)
    Console.WriteLine("Robot powered on");
```

### PowerOff

Power off the robot.

```csharp
robot.Rest.PowerOff();
```

### BrakeRelease

Release the robot brakes after powering on.

```csharp
robot.Rest.PowerOn();
robot.Rest.BrakeRelease();
```

### UnlockProtectiveStop

Unlock the robot from a protective stop state.

```csharp
robot.Rest.UnlockProtectiveStop();
```

### RestartSafety

Restart the safety system.

```csharp
robot.Rest.RestartSafety();
```

### ChangeRobotState

Generic method to change robot state:

```csharp
robot.Rest.ChangeRobotState(RobotStateAction.POWER_ON);
robot.Rest.ChangeRobotState(RobotStateAction.BRAKE_RELEASE);
```

Available actions:
- `RobotStateAction.POWER_ON`
- `RobotStateAction.POWER_OFF`
- `RobotStateAction.BRAKE_RELEASE`
- `RobotStateAction.UNLOCK_PROTECTIVE_STOP`
- `RobotStateAction.RESTART_SAFETY`

## Program Control

Control program execution:

### LoadProgram

Load a program by name. The `.urp` extension is optional.

```csharp
robot.Rest.LoadProgram("my_program");
// or
robot.Rest.LoadProgram("my_program.urp");
```

### Play

Start playing the loaded program.

```csharp
robot.Rest.Play();
```

### Pause

Pause the running program.

```csharp
robot.Rest.Pause();
```

### Stop

Stop the running program.

```csharp
robot.Rest.Stop();
```

### Resume

Resume a paused program.

```csharp
robot.Rest.Resume();
```

### GetProgramState

Get the current program state.

```csharp
RestApiResponse<ProgramStateResponse> response = robot.Rest.GetProgramState();

if (response.Succeed)
{
    RestProgramState state = response.Value.State;
    // state: Playing, Stopped, Paused, Unknown
}
```

### ChangeProgramState

Generic method to change program state:

```csharp
robot.Rest.ChangeProgramState(ProgramStateAction.play);
robot.Rest.ChangeProgramState(ProgramStateAction.stop);
```

Available actions:
- `ProgramStateAction.play`
- `ProgramStateAction.pause`
- `ProgramStateAction.stop`
- `ProgramStateAction.resume`

## Response Handling

All methods return `RestApiResponse` or `RestApiResponse<T>`:

```csharp
RestApiResponse response = robot.Rest.PowerOn();

// Check success
if (response.Succeed)
{
    Console.WriteLine("Success");
}
else
{
    Console.WriteLine($"Error: {response.Message}");
    Console.WriteLine($"HTTP Status: {response.StatusCode}");
    Console.WriteLine($"Raw response: {response.RawResponse}");
}
```

| Property | Type | Description |
|----------|------|-------------|
| `Succeed` | `bool` | `true` if HTTP 200 OK |
| `StatusCode` | `HttpStatusCode` | HTTP status code |
| `Message` | `string` | Success message or error description |
| `RawResponse` | `string` | Raw JSON response body |
| `Value` | `T` | Typed response value (generic version only) |

## Error Handling

Handle errors using the `InternalErrorOccured` event:

```csharp
robot.Rest.InternalErrorOccured += (sender, e) =>
{
    Console.WriteLine($"REST API Error: {e.Message}");
    Console.WriteLine($"Exception: {e.Exception}");
};
```

## API Endpoints

The SDK maps to these PolyscopeX REST API endpoints:

| Method | SDK Method | Endpoint |
|--------|------------|----------|
| PUT | `ChangeRobotState()` | `/universal-robots/robot-api/robotstate/v1/state` |
| PUT | `LoadProgram()` | `/universal-robots/robot-api/program/v1/load` |
| PUT | `ChangeProgramState()` | `/universal-robots/robot-api/program/v1/state` |
| GET | `GetProgramState()` | `/universal-robots/robot-api/program/v1/state` |

## Migration from Dashboard Server

Migrating from legacy Dashboard Server to REST API:

```csharp
// Dashboard Server (CB-series / e-Series)
robot.Connect(new ConnectParameters("192.168.0.1")
{
    Dashboard = { Enable = true }
});
robot.Dashboard.PowerOn();
robot.Dashboard.LoadProgram("/programs/my_program.urp");
robot.Dashboard.Play();

// REST API (PolyscopeX)
robot.Connect(new ConnectParameters("192.168.0.1")
{
    Rest = { Enable = true }
});
robot.Rest.PowerOn();
robot.Rest.LoadProgram("my_program");
robot.Rest.Play();
```

Key differences:
- REST API uses HTTP (port 80) instead of TCP socket (port 29999)
- Program names don't require full path
- REST API returns structured `RestApiResponse` objects

## Properties

| Property | Type | Description |
|----------|------|-------------|
| `IP` | `string` | Robot IP address |
| `Port` | `int` | HTTP port |
| `Version` | `RestApiVersion` | API version |
| `TimeoutMs` | `int` | Request timeout |
| `Initialized` | `bool` | `true` if client is enabled |

```csharp
if (robot.Rest.Initialized)
{
    Console.WriteLine($"Connected to {robot.Rest.IP}:{robot.Rest.Port}");
}
```