> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.ninjatrader.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.ninjatrader.com/_mcp/server.

# Cancel Tradovate Subscription

POST https://demo.tradovateapi.com/v1/user/canceltradovatesubscription
Content-Type: application/json

### Cancel a Tradovate Trader membership plan.

**Available to:** All authenticated users

**Environments:** Live

**[Rate Limit](/api/authentication#request-rate-limits-and-time-penalties):** No endpoint-specific limit

Cancels a user's Tradovate Trader membership subscription. Identify the subscription with `tradovateSubscriptionId` (the integer entity ID). Optionally provide a `cancelReason` for record-keeping, and set `expire` to control whether the subscription is canceled immediately or allowed to lapse at the end of its current period.

This is a Live-only endpoint; calling it on Demo returns an environment error directing you to the Live host. The request is forwarded to the license service, which performs the cancellation and returns the result.

On success, the response returns the updated `tradovateSubscription` with an empty `errorText`. On a handled failure, the response carries a non-empty `errorText` (and may include an `errorCode`) describing the problem.

**Common Failure Scenarios**

- The endpoint is called on Demo rather than Live (returns an environment error).
- The `tradovateSubscriptionId` doesn't exist or isn't accessible to the caller.
- The license service is unavailable or returns an error during cancellation.
- The access token is missing or invalid (returns `HTTP 401`).

**Error Messages**

| `errorText` | Trigger |
|-------------|---------|
| `"This endpoint should be called on live.tradovateapi.com"` | The request was sent to the Demo host. |
| Non-empty `errorText` | The request failed; the field describes the reason. |

Reference: https://docs.ninjatrader.com/api/rest-api-endpoints/users/cancel-tradovate-subscription

## OpenAPI Specification

```yaml
openapi: 3.1.0
info:
  title: public
  version: 1.0.0
paths:
  /user/canceltradovatesubscription:
    post:
      operationId: cancelTradovateSubscription
      summary: Cancel Tradovate Subscription
      description: >-
        ### Cancel a Tradovate Trader membership plan.


        **Available to:** All authenticated users


        **Environments:** Live


        **[Rate
        Limit](/api/authentication#request-rate-limits-and-time-penalties):** No
        endpoint-specific limit


        Cancels a user's Tradovate Trader membership subscription. Identify the
        subscription with `tradovateSubscriptionId` (the integer entity ID).
        Optionally provide a `cancelReason` for record-keeping, and set `expire`
        to control whether the subscription is canceled immediately or allowed
        to lapse at the end of its current period.


        This is a Live-only endpoint; calling it on Demo returns an environment
        error directing you to the Live host. The request is forwarded to the
        license service, which performs the cancellation and returns the result.


        On success, the response returns the updated `tradovateSubscription`
        with an empty `errorText`. On a handled failure, the response carries a
        non-empty `errorText` (and may include an `errorCode`) describing the
        problem.


        **Common Failure Scenarios**


        - The endpoint is called on Demo rather than Live (returns an
        environment error).

        - The `tradovateSubscriptionId` doesn't exist or isn't accessible to the
        caller.

        - The license service is unavailable or returns an error during
        cancellation.

        - The access token is missing or invalid (returns `HTTP 401`).


        **Error Messages**


        | `errorText` | Trigger |

        |-------------|---------|

        | `"This endpoint should be called on live.tradovateapi.com"` | The
        request was sent to the Demo host. |

        | Non-empty `errorText` | The request failed; the field describes the
        reason. |
      tags:
        - Users
      parameters:
        - name: Authorization
          in: header
          description: Bearer authentication
          required: true
          schema:
            type: string
      responses:
        '200':
          description: TradovateSubscriptionResponse
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TradovateSubscriptionResponse'
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CancelTradovateSubscription'
servers:
  - url: https://demo.tradovateapi.com/v1
    description: Demo
  - url: https://live.tradovateapi.com/v1
    description: Live
components:
  schemas:
    CancelTradovateSubscription:
      type: object
      properties:
        tradovateSubscriptionId:
          type: integer
          format: int64
        cancelReason:
          type: string
        expire:
          type: boolean
      required:
        - tradovateSubscriptionId
      title: CancelTradovateSubscription
    TradovateSubscriptionResponseErrorCode:
      type: string
      enum:
        - ConflictWithExisting
        - DowngradeNotAllowed
        - IncompatibleCMEMarketDataSubscriptionPlans
        - IncorrectPaymentMethod
        - InsufficientFunds
        - PaymentProviderError
        - PlanDiscontinued
        - SingleTrialOnly
        - Success
        - UnknownError
      description: >-
        ConflictWithExisting, DowngradeNotAllowed,
        IncompatibleCMEMarketDataSubscriptionPlans, IncorrectPaymentMethod,
        InsufficientFunds, PaymentProviderError, PlanDiscontinued,
        SingleTrialOnly, Success, UnknownError
      title: TradovateSubscriptionResponseErrorCode
    TradeDate:
      type: object
      properties:
        year:
          type: integer
        month:
          type: integer
        day:
          type: integer
      required:
        - year
        - month
        - day
      title: TradeDate
    TradovateSubscription:
      type: object
      properties:
        id:
          type: integer
          format: int64
        userId:
          type: integer
          format: int64
        timestamp:
          type: string
          format: date-time
        planPrice:
          type: number
          format: double
        cashBalanceLogId:
          type: integer
          format: int64
        accountId:
          type: integer
          format: int64
        tradovateSubscriptionPlanId:
          type: integer
          format: int64
        startDate:
          $ref: '#/components/schemas/TradeDate'
        expirationDate:
          $ref: '#/components/schemas/TradeDate'
        paidAmount:
          type: number
          format: double
        cancelledRenewal:
          type: boolean
        cancelReason:
          type: string
      required:
        - userId
        - timestamp
        - planPrice
        - tradovateSubscriptionPlanId
        - startDate
        - expirationDate
        - paidAmount
      title: TradovateSubscription
    TradovateSubscriptionResponse:
      type: object
      properties:
        errorText:
          type: string
          description: Non-empty if the request failed
        errorCode:
          $ref: '#/components/schemas/TradovateSubscriptionResponseErrorCode'
          description: >-
            ConflictWithExisting, DowngradeNotAllowed,
            IncompatibleCMEMarketDataSubscriptionPlans, IncorrectPaymentMethod,
            InsufficientFunds, PaymentProviderError, PlanDiscontinued,
            SingleTrialOnly, Success, UnknownError
        tradovateSubscription:
          $ref: '#/components/schemas/TradovateSubscription'
      title: TradovateSubscriptionResponse
  securitySchemes:
    bearer_access_token:
      type: http
      scheme: bearer

```

## Examples



**Request**

```json
{
  "tradovateSubscriptionId": 1
}
```

**Response**

```json
{
  "errorText": "string",
  "errorCode": "ConflictWithExisting",
  "tradovateSubscription": {
    "userId": 1,
    "timestamp": "2024-01-15T09:30:00Z",
    "planPrice": 1.1,
    "tradovateSubscriptionPlanId": 1,
    "startDate": {
      "year": 1,
      "month": 1,
      "day": 1
    },
    "expirationDate": {
      "year": 1,
      "month": 1,
      "day": 1
    },
    "paidAmount": 1.1,
    "id": 1,
    "cashBalanceLogId": 1,
    "accountId": 1,
    "cancelledRenewal": true,
    "cancelReason": "string"
  }
}
```

**SDK Code**

```python
import requests

url = "https://demo.tradovateapi.com/v1/user/canceltradovatesubscription"

payload = { "tradovateSubscriptionId": 1 }
headers = {
    "Authorization": "Bearer <token>",
    "Content-Type": "application/json"
}

response = requests.post(url, json=payload, headers=headers)

print(response.json())
```

```javascript
const url = 'https://demo.tradovateapi.com/v1/user/canceltradovatesubscription';
const options = {
  method: 'POST',
  headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
  body: '{"tradovateSubscriptionId":1}'
};

try {
  const response = await fetch(url, options);
  const data = await response.json();
  console.log(data);
} catch (error) {
  console.error(error);
}
```

```go
package main

import (
	"fmt"
	"strings"
	"net/http"
	"io"
)

func main() {

	url := "https://demo.tradovateapi.com/v1/user/canceltradovatesubscription"

	payload := strings.NewReader("{\n  \"tradovateSubscriptionId\": 1\n}")

	req, _ := http.NewRequest("POST", url, payload)

	req.Header.Add("Authorization", "Bearer <token>")
	req.Header.Add("Content-Type", "application/json")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := io.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}
```

```ruby
require 'uri'
require 'net/http'

url = URI("https://demo.tradovateapi.com/v1/user/canceltradovatesubscription")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n  \"tradovateSubscriptionId\": 1\n}"

response = http.request(request)
puts response.read_body
```

```java
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;

HttpResponse<String> response = Unirest.post("https://demo.tradovateapi.com/v1/user/canceltradovatesubscription")
  .header("Authorization", "Bearer <token>")
  .header("Content-Type", "application/json")
  .body("{\n  \"tradovateSubscriptionId\": 1\n}")
  .asString();
```

```php
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('POST', 'https://demo.tradovateapi.com/v1/user/canceltradovatesubscription', [
  'body' => '{
  "tradovateSubscriptionId": 1
}',
  'headers' => [
    'Authorization' => 'Bearer <token>',
    'Content-Type' => 'application/json',
  ],
]);

echo $response->getBody();
```

```csharp
using RestSharp;

var client = new RestClient("https://demo.tradovateapi.com/v1/user/canceltradovatesubscription");
var request = new RestRequest(Method.POST);
request.AddHeader("Authorization", "Bearer <token>");
request.AddHeader("Content-Type", "application/json");
request.AddParameter("application/json", "{\n  \"tradovateSubscriptionId\": 1\n}", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
```

```swift
import Foundation

let headers = [
  "Authorization": "Bearer <token>",
  "Content-Type": "application/json"
]
let parameters = ["tradovateSubscriptionId": 1] as [String : Any]

let postData = JSONSerialization.data(withJSONObject: parameters, options: [])

let request = NSMutableURLRequest(url: NSURL(string: "https://demo.tradovateapi.com/v1/user/canceltradovatesubscription")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers
request.httpBody = postData as Data

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error as Any)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
```