# PerpsHub TP/SL Implementation

### Overview

The stop-loss/take-profit (SL/TP) system allows users to automatically close positions when the market price reaches specified trigger levels. The system continuously monitors mark prices and executes closes when conditions are met.

**Base URL Pattern:** `/v1/:symmId/:multiaccount`

All endpoints require the following path parameters:

* `symmId`: Network/chain identifier (e.g., '56a', '5000a', '42161a', '8453a', etc.)
* `multiaccount`: Ethereum address of the multi-account contract

***

### Endpoints

#### 1. Create Stop Loss / Take Profit

Create or update a stop-loss and/or take-profit order for a specific position.

**Endpoint:**

* `POST /v1/:symmId/:multiaccount/stop_loss`
* `POST /v1/:symmId/:multiaccount/stop-loss` (kebab-case alternative)

**Authentication:** Required (Bearer token)

**Request Body:**

```typescript
{
  userAddress: string        // Ethereum address of the user (0x...)
  accountAddress: string     // Ethereum address of the account/partyA (0x...)
  positionSide: 0 | 1       // 0 = LONG, 1 = SHORT
  symbolId: number          // Numeric symbol identifier
  requestedPrice: string    // Requested open price (decimal string)
  quoteId: number           // Quote ID (positive for filled trades, negative for pending instant opens)
  tpPrice: string           // Take profit trigger price (decimal string, can be empty)
  slPrice: string           // Stop loss trigger price (decimal string, can be empty)
  timestamp: number         // Request timestamp in milliseconds
}
```

**Validation Rules:**

* At least one of `tpPrice` or `slPrice` must be provided (non-empty)
* `tpPrice` and `slPrice` cannot be equal
* For LONG positions:
  * `tpPrice` must be ABOVE the current/estimated mark price
  * `slPrice` must be BELOW the current/estimated mark price
* For SHORT positions:
  * `tpPrice` must be BELOW the current/estimated mark price
  * `slPrice` must be ABOVE the current/estimated mark price

**Success Response (200 OK):**

```json
{
  "success": true,
  "statusMessage": "Stoploss created",
  "data": {
    "success": true,
    "statusMessage": "Stoploss created"
  }
}
```

**Error Responses:**

**400 Bad Request:**

```json
{
  "error": "Stoploss request must have either TP or SL"
}
```

```json
{
  "error": "Stoploss request cannot have TP and SL equal"
}
```

```json
{
  "error": "Take profit price is invalid"
}
```

```json
{
  "error": "Stop loss price is invalid"
}
```

```json
{
  "error": "Stop loss already exists for this trade"
}
```

```json
{
  "error": "Unsupported symbol"
}
```

**404 Not Found:**

```json
{
  "error": "Trade not found"
}
```

**Notes:**

* If a stop-loss already exists for the trade in PENDING status, the request will be rejected
* The system validates prices against the current mark price (for opened positions) or estimated fill price (for pending instant opens)
* Prices are validated with slippage considerations

**Example:**

```bash
curl -X POST \
  https://api.example.com/v1/42161a/0x1234...5678/stop-loss \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "userAddress": "0xabcd...ef01",
    "accountAddress": "0x1234...5678",
    "positionSide": 0,
    "symbolId": 123,
    "requestedPrice": "50000.5",
    "quoteId": 12345,
    "tpPrice": "55000",
    "slPrice": "48000",
    "timestamp": 1234567890000
  }'
```

***

#### 2. List Stop Losses / Take Profits

Retrieve stop-loss/take-profit orders for multiple quote IDs.

**Endpoint:**

* `POST /v1/:symmId/:multiaccount/list_sl`
* `POST /v1/:symmId/:multiaccount/list-sl-tp` (kebab-case alternative)

**Authentication:** Not required

**Request Body:**

```typescript
{
  quoteIds: number[]  // Array of quote IDs (minimum 1 item)
}
```

**Success Response (200 OK):**

```json
{
  "success": true,
  "statusMessage": "Stoplosses listed",
  "data": {
    "statusMessage": "Stoplosses listed",
    "success": true,
    "data": {
      "12345": {
        "symmId": "42161a",
        "quoteId": 12345,
        "userAddress": "0xabcd...ef01",
        "affiliate": "0x1234...5678",
        "partyA": "0x9876...5432",
        "tpPrice": "55000",
        "slPrice": "48000",
        "timestamp": 1234567890000,
        "status": "pending",
        "positionSide": 0,
        "lastCheckedAt": 1234567890000,
        "symbolName": "BTCUSDT"
      },
      "67890": {
        "symmId": "42161a",
        "quoteId": 67890,
        "userAddress": "0xabcd...ef01",
        "affiliate": "0x1234...5678",
        "partyA": "0x9876...5432",
        "tpPrice": null,
        "slPrice": "3200",
        "timestamp": 1234567891000,
        "status": "pending",
        "positionSide": 0,
        "lastCheckedAt": 1234567891000,
        "symbolName": "ETHUSDT"
      }
    }
  }
}
```

**Response Fields:**

* `symmId`: Network identifier
* `quoteId`: Quote/trade identifier
* `userAddress`: User's address
* `affiliate`: Affiliate/multiaccount address
* `partyA`: Account address (partyA)
* `tpPrice`: Take profit trigger price (null if not set)
* `slPrice`: Stop loss trigger price (null if not set)
* `timestamp`: Creation timestamp
* `status`: Order status (`"pending"`, `"processing"`, `"executed"`, `"cancelled"`)
* `positionSide`: 0 = LONG, 1 = SHORT
* `lastCheckedAt`: Last time the order was checked by the system
* `symbolName`: Trading symbol (e.g., "BTCUSDT")

**Error Response (400 Bad Request):**

```json
{
  "error": "Error message"
}
```

**Example:**

```bash
curl -X POST \
  https://api.example.com/v1/42161a/0x1234...5678/list-sl-tp \
  -H "Content-Type: application/json" \
  -d '{
    "quoteIds": [12345, 67890, 11111]
  }'
```

***

#### 3. Cancel Stop Loss / Take Profit

Cancel the stop-loss and/or take-profit for a specific quote.

**Endpoint:**

* `POST /v1/:symmId/:multiaccount/cancel_sl`
* `POST /v1/:symmId/:multiaccount/cancel-sl-tp` (kebab-case alternative)

**Authentication:** Required (Bearer token)

**Request Body:**

```typescript
{
  quoteId: number         // Quote ID to cancel
  cancelSl?: boolean     // Whether to cancel stop loss (optional, default: false)
  cancelTp?: boolean     // Whether to cancel take profit (optional, default: false)
}
```

**Validation Rules:**

* At least one of `cancelSl` or `cancelTp` must be `true`
* The stop-loss order must exist for the given quote
* The stop-loss order must be in `PENDING` status (cannot cancel processing/executed orders)

**Success Response (200 OK):**

When canceling both:

```json
{
  "success": true,
  "statusMessage": "Stop loss and take profit cancelled",
  "data": {
    "success": true,
    "statusMessage": "Stop loss and take profit cancelled"
  }
}
```

When canceling only stop loss:

```json
{
  "success": true,
  "statusMessage": "Stop loss cancelled",
  "data": {
    "success": true,
    "statusMessage": "Stop loss cancelled"
  }
}
```

When canceling only take profit:

```json
{
  "success": true,
  "statusMessage": "Take profit cancelled",
  "data": {
    "success": true,
    "statusMessage": "Take profit cancelled"
  }
}
```

**Error Responses:**

**400 Bad Request:**

```json
{
  "error": "Must cancel at least one of SL or TP"
}
```

```json
{
  "error": "Can only cancel pending stop loss orders"
}
```

```json
{
  "error": "Error while cancelling stop loss"
}
```

**404 Not Found:**

```json
{
  "error": "Stop loss not found for this quote"
}
```

**Notes:**

* If both `cancelSl` and `cancelTp` are true (or if canceling the only remaining one), the entire stop-loss document is removed
* If only one is canceled and the other remains, the document is updated with the remaining value
* Partial cancellation is supported: you can cancel just SL or just TP while keeping the other active

**Example:**

Cancel both SL and TP:

```bash
curl -X POST \
  https://api.example.com/v1/42161a/0x1234...5678/cancel-sl-tp \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "quoteId": 12345,
    "cancelSl": true,
    "cancelTp": true
  }'
```

Cancel only stop loss:

```bash
curl -X POST \
  https://api.example.com/v1/42161a/0x1234...5678/cancel-sl-tp \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "quoteId": 12345,
    "cancelSl": true,
    "cancelTp": false
  }'
```

***

#### Stop Loss States

| Status       | Description                                   |
| ------------ | --------------------------------------------- |
| `PENDING`    | Order is active and being monitored           |
| `PROCESSING` | Trigger conditions met, execution in progress |
| `EXECUTED`   | Order successfully executed                   |
| `CANCELLED`  | Order cancelled by user                       |

### Authentication

Endpoints marked as requiring authentication must include a Bearer token in the Authorization header:

```
Authorization: Bearer YOUR_ACCESS_TOKEN
```

To obtain an access token, use the login endpoints:

* `POST /v1/:symmId/:multiaccount/login` (for EVM wallets)
* `POST /v1/:symmId/:multiaccount/tac-login` (for TON wallets)

***

### Common Error Codes

| HTTP Status | Error Message                  | Description                                |
| ----------- | ------------------------------ | ------------------------------------------ |
| 400         | Invalid symmId                 | The symmId path parameter is not valid     |
| 400         | Validation error               | Request body validation failed             |
| 401         | Invalid or missing credentials | Authentication token is missing or invalid |
| 404         | Trade not found                | The specified quote ID does not exist      |
| 404         | Stop loss not found            | No stop-loss order exists for the quote    |
| 500         | Internal server error          | Unexpected server error                    |


---

# Agent Instructions: 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:

```
GET https://docs.symm.io/api-endpoints-and-deployments/solver-addresses-and-endpoints/perps-hub/perpshub-tp-sl-implementation.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
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.
