PhoenixPerpetualsDocs API v1
Get an API key

Get started

Quickstart⁠.

From nothing to a protected order on a sandbox account in five minutes, in the language you use.

View as Markdown

On this page
  1. Create a sandbox key
  2. Put the key in your environment
  3. Install an SDK
  4. List your accounts
  5. Place an order with its exits
  6. What you just did
  7. Where to go next

You will create a sandbox key, read your accounts, and place a limit order with its stop loss and take profit held on our servers. Everything here runs on paper money: nothing touches your evaluation or funded accounts.

  1. Create a sandbox key

    In your dashboard, open Developers and choose Create API key. Pick Sandbox, then Read and trade, and give the key a name you will recognise, like the bot that will use it.

    Sandbox keys need no email code. Your first one also opens a sandbox account of $100,000 for you, so there is something to trade on straight away.

  2. Put the key in your environment

    Every SDK and every example in these docs reads the key from PHOENIXPERPS_API_KEY. Keeping it out of your code means it never ends up in a repository.

    export PHOENIXPERPS_API_KEY="ppk_test_..."
  3. Install an SDK

    Pick your language once: every sample on every page of these docs follows it.

    # curl is all you need; skip this step
    pip install phoenixperps
    npm install @phoenixperps/sdk
    dotnet add package PhoenixPerps.Sdk
    go get github.com/phoenixperps/sdk/go
    implementation("com.phoenixperpsfunding:phoenixperps-sdk:1.0.0")
    cargo add phoenixperps
    composer require phoenixperps/sdk
  4. List your accounts

    The key decides the host: a ppk_test_ key works on the sandbox host only, so the SDKs pick it for you. With curl, use the sandbox host.

    curl https://sandbox-api.phoenixperpsfunding.com/v1/accounts \
      -H "Authorization: Bearer $PHOENIXPERPS_API_KEY"
    from phoenixperps import PhoenixPerps
    
    client = PhoenixPerps()  # reads PHOENIXPERPS_API_KEY
    
    for account in client.accounts.list():
        print(account.id, account.status, account.equity)
    import { PhoenixPerps } from "@phoenixperps/sdk";
    
    const client = new PhoenixPerps(); // reads PHOENIXPERPS_API_KEY
    
    for await (const account of client.accounts.list()) {
      console.log(account.id, account.status, account.equity);
    }
    using PhoenixPerps;
    
    var client = new PhoenixPerpsClient(); // reads PHOENIXPERPS_API_KEY
    
    await foreach (var account in client.Accounts.ListAsync())
    {
        Console.WriteLine($"{account.Id} {account.Status} {account.Equity}");
    }
    client, err := phoenixperps.NewClient() // reads PHOENIXPERPS_API_KEY
    if err != nil {
    	log.Fatal(err)
    }
    for account, err := range client.Accounts.List(context.Background(), nil) {
    	if err != nil {
    		log.Fatal(err)
    	}
    	fmt.Println(account.ID, account.Status, account.Equity)
    }
    var client = PhoenixPerpsClient.builder().build(); // reads PHOENIXPERPS_API_KEY
    
    for (var account : client.accounts().list()) {
        System.out.println(account.id() + " " + account.status() + " " + account.equity());
    }
    let client = phoenixperps::Client::builder().build()?; // reads PHOENIXPERPS_API_KEY
    
    let mut accounts = client.accounts().list(Default::default());
    while let Some(account) = accounts.next().await {
        let account = account?;
        println!("{} {} {}", account.id, account.status, account.equity);
    }
    $client = new PhoenixPerps\Client(); // reads PHOENIXPERPS_API_KEY
    
    foreach ($client->accounts->list() as $account) {
        echo $account->id, ' ', $account->status, ' ', $account->equity, PHP_EOL;
    }

    You get your sandbox account, named like SANDBOX-00042-001. That name is its id in every path.

  5. Place an order with its exits

    This buys 0.010 BTC with a limit at 62,500, a take profit at 64,000 and a stop loss at 61,800. The exits wait on our servers as reduce-only orders: they protect the position even if your bot stops.

    curl -X POST https://sandbox-api.phoenixperpsfunding.com/v1/accounts/SANDBOX-00042-001/orders \
      -H "Authorization: Bearer $PHOENIXPERPS_API_KEY" \
      -H "Idempotency-Key: $(uuidgen)" \
      -H "Content-Type: application/json" \
      -d '{
        "market": "BTC-USD",
        "side": "buy",
        "type": "limit",
        "size": "0.010",
        "limit_price": "62500.00",
        "take_profit": { "price": "64000.00" },
        "stop_loss": { "price": "61800.00" }
      }'
    order = client.orders.create(
        account_id="SANDBOX-00042-001",
        market="BTC-USD",
        side="buy",
        type="limit",
        size="0.010",
        limit_price="62500.00",
        take_profit={"price": "64000.00"},
        stop_loss={"price": "61800.00"},
    )
    print(order.id, order.status)  # ord_01JAB7Q8XK... working
    const order = await client.orders.create({
      account_id: "SANDBOX-00042-001",
      market: "BTC-USD",
      side: "buy",
      type: "limit",
      size: "0.010",
      limit_price: "62500.00",
      take_profit: { price: "64000.00" },
      stop_loss: { price: "61800.00" },
    });
    console.log(order.id, order.status); // ord_01JAB7Q8XK... working
    var order = await client.Orders.CreateAsync(new CreateOrderParams
    {
        AccountId = "SANDBOX-00042-001",
        Market = "BTC-USD",
        Side = "buy",
        Type = "limit",
        Size = 0.010m,
        LimitPrice = 62500.00m,
        TakeProfit = new TakeProfit { Price = 64000.00m },
        StopLoss = new StopLoss { Price = 61800.00m },
    });
    Console.WriteLine($"{order.Id} {order.Status}");
    order, err := client.Orders.Create(context.Background(), &phoenixperps.CreateOrderParams{
    	AccountID:  "SANDBOX-00042-001",
    	Market:     "BTC-USD",
    	Side:       "buy",
    	Type:       "limit",
    	Size:       "0.010",
    	LimitPrice: "62500.00",
    	TakeProfit: &phoenixperps.TakeProfit{Price: "64000.00"},
    	StopLoss:   &phoenixperps.StopLoss{Price: "61800.00"},
    })
    if err != nil {
    	log.Fatal(err)
    }
    fmt.Println(order.ID, order.Status)
    var order = client.orders().create(CreateOrderParams.builder()
        .accountId("SANDBOX-00042-001")
        .market("BTC-USD")
        .side("buy")
        .type("limit")
        .size(new BigDecimal("0.010"))
        .limitPrice(new BigDecimal("62500.00"))
        .takeProfit(TakeProfit.builder().price(new BigDecimal("64000.00")).build())
        .stopLoss(StopLoss.builder().price(new BigDecimal("61800.00")).build())
        .build());
    System.out.println(order.id() + " " + order.status());
    let order = client.orders().create(CreateOrderParams {
        account_id: "SANDBOX-00042-001".into(),
        market: "BTC-USD".into(),
        side: "buy".into(),
        r#type: "limit".into(),
        size: Some(dec!(0.010)),
        limit_price: Some(dec!(62500.00)),
        take_profit: Some(TakeProfit { price: dec!(64000.00), ..Default::default() }),
        stop_loss: Some(StopLoss { price: dec!(61800.00), ..Default::default() }),
        ..Default::default()
    }).await?;
    println!("{} {}", order.id, order.status);
    $order = $client->orders->create([
        'account_id' => 'SANDBOX-00042-001',
        'market' => 'BTC-USD',
        'side' => 'buy',
        'type' => 'limit',
        'size' => '0.010',
        'limit_price' => '62500.00',
        'take_profit' => ['price' => '64000.00'],
        'stop_loss' => ['price' => '61800.00'],
    ]);
    echo $order->id, ' ', $order->status, PHP_EOL;

    The SDKs send an Idempotency-Key for you and reuse it if they retry, so a dropped connection never places the order twice. With curl, send your own.

What you just did#

You traded through the same engine, with the same prices and the same rules as your real accounts, on a sandbox account that will never count towards a payout. When your bot behaves, create a live key and change nothing else: the SDKs move to the live host by themselves.

Where to go next#

Guides, endpoints, fields and error codes.