API

PHP Integration Example

Overview

In this example we will build a bare bones exchange website in PHP using the fox.exchange API.

There is no styling applied, and of course the flow could be improved with dynamic JavaScript, better error handling and so on, but the point is to show the interaction with the API in its simplest way. Note that we assume a modern PHP version (5.6+).

At the end, we will have a page that works like this:

  • User goes to the page and sees a list of pairs they can trade
  • User selects a pair
  • User sees a page which shows the minimum and maximum amounts they can trade and is asked to enter the amount they want to trade
  • User enters the amount and clicks "Check Rate"
  • User sees the approximate amount they will receive at the end
  • User can decide to enter a different amount and check again, enter their wallet address (and optionally email) and click "Exchange Now" to create an order
  • User is asked to make the deposit to a certain address and sees a QR code
  • Page automatically refreshes and shows the status of the order (waiting for deposit, waiting for confirmations, trading, completed)

You can download the working example project with all PHP files here!

Walkthrough

Step 1

Let's start by creating a helper function to interact with the API. We will use this function throughout the rest of the code.

Create a file api.php with the following content:

<?php

// This is the sandbox API key - replace this with your real key once you got one!
define('FOX_API_KEY', 'DEADBEEFDEADBEEF');

function callFoxApi ($method, $path, $data = null) {
  $url = 'https://fox.exchange/api/cs' . $path;

  $curl = curl_init();

  try {
    $headers = [
      'X-API-Key: ' . FOX_API_KEY,
      // Note: If you are behind a reverse proxy/load balancer, this line may need to be changed
      'X-User-IP: ' . $_SERVER['REMOTE_ADDR'],
      'Accept: application/json'
    ];

    switch ($method) {
      case 'POST':
        curl_setopt($curl, CURLOPT_POST, 1);
        if ($data) {
          $headers[] = 'Content-Type: application/json';
          curl_setopt($curl, CURLOPT_POSTFIELDS, json_encode($data));
        }
        break;
      default:
        if ($data) {
          $url .= '?' . http_build_query($data);
        }
    }

    curl_setopt($curl, CURLOPT_URL, $url);
    curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);

    $rawResult = @curl_exec($curl);
    if (!$rawResult) {
      throw new Exception('Fox API request failed: ' . curl_error($curl));
    }
    $result = @json_decode($rawResult);
    if (!$result) {
      throw new Exception('Fox API request failed with non-JSON response: ' . $rawResult);
    }

    if (!$result->success) {
      $e = new Exception('Fox API request failed with server error: ' . $result->error);
      $e->foxErrorCode = $result->code;
      $e->foxErrorMessage = $result->error;
      throw $e;
    } else {
      return $result->data;
    }
  } finally {
    curl_close($curl);
  }
}

Note that at the top, the API key needs to be defined. You can start by using DEADBEEFDEADBEEF, which is the sandbox key. In the sandbox, rates will not be accurate, and orders will be fake and automatically progress and eventually complete, without real money involved.

Once you want to move to production, contact the fox.exchange support to receive a production API key. You can also join the affiliate program and connect your affiliate account with your API key to earn commission on the exchanges that your users do.

Now we have a function callFoxApi which can be called simply with the method and API path and, where applicable, data. For example, you could receive a list of coins using callFoxApi('GET', '/coins').

In case you are running this behind a reverse proxy or load balancer, the user's IP address may not be accessible in the variable $_SERVER['REMOTE_ADDR']. In that case, please research online how to get the real IP address of the end user in your scenario and modify the line that sets the X-User-IP header accordingly (often, it is $_SERVER['HTTP_X_FORWARDED_FOR']). Note that it is required to send the user's IP address, because parts of the service may be unavailable or available at different rates depending on the user's location. For compliance reasons, it is mandatory to send the real IP address in the X-User-IP header.

Step 2

Next, let's create the homepage on which we list the available pairs the user can trade.

Create a file index.php with the following content:

<?php require('./api.php'); ?>
<h1>Welcome to our exchange!</h1>
<h4>Please select which pair you want to trade:</h4>
<ol>
  <?php foreach (callFoxApi('POST', '/pairs') as $pair): ?>
    <?php if (!$pair->isActive) continue; ?>
    <li>
      <a href="rate.php?<?php echo htmlentities(http_build_query([
        'depositCoin' => $pair->depositCoin,
        'destinationCoin' => $pair->destinationCoin
      ])) ?>">
        Send <?php echo htmlentities($pair->depositCoin); ?>,
        receive <?php echo htmlentities($pair->destinationCoin); ?>
      </a>
    </li>
  <?php endforeach; ?>
</ol>

Here, we use the POST /pairs endpoint to get a list of pairs. We then list the active ones and link to the next page which we will create now.

This is how it looks so far:

Screenshot 1

Step 3

Create a file rate.php with the following content:

<?php require('./api.php'); ?>
<h1>
  Exchange <?php echo htmlentities($_REQUEST['depositCoin']); ?>
  to <?php echo htmlentities($_REQUEST['destinationCoin']); ?>
</h1>
<?php
  $rate = null;
  try {
    $rate = callFoxApi('POST', '/rate', [
      'depositCoin' => $_REQUEST['depositCoin'],
      'destinationCoin' => $_REQUEST['destinationCoin'],
      'depositCoinAmount' => isset($_REQUEST['depositCoinAmount']) ?
        $_REQUEST['depositCoinAmount'] :
        null
    ]);
  } catch (Exception $e) {
    if (isset($e->foxErrorMessage)) {
      ?>
        <h3>Error: <?php echo htmlentities($e->foxErrorMessage); ?></h3>
      <?php
    } else {
      throw $e;
    }
  }
?>
<form>
  <strong>Input amount:</strong>
  <input
    type="number"
    name="depositCoinAmount"
    value="<?php if (isset($_REQUEST['depositCoinAmount']))
      echo htmlentities($_REQUEST['depositCoinAmount']); ?>"
    min="<?php if ($rate) echo htmlentities($rate->limitMinDepositCoin); ?>"
    max="<?php if ($rate) echo htmlentities($rate->limitMaxDepositCoin); ?>"
    step="0.00000001"
    required
  >
  <?php echo htmlentities($_REQUEST['depositCoin']); ?>
  <br>
  <?php if ($rate): ?>
    <strong>Limits:</strong>
    <?php echo htmlentities($rate->limitMinDepositCoin); ?>
    to <?php echo htmlentities($rate->limitMaxDepositCoin); ?>
    <?php echo htmlentities($_REQUEST['depositCoin']); ?>
    <br>
  <?php endif; ?>
  <input
    type="hidden"
    name="depositCoin"
    value="<?php echo htmlentities($_REQUEST['depositCoin']) ?>"
  >
  <input
    type="hidden"
    name="destinationCoin"
    value="<?php echo htmlentities($_REQUEST['destinationCoin']) ?>"
  >
  <input type="submit" value="Check Rate">
</form>

<?php if ($rate && $rate->destinationCoinAmount): ?>
  <hr>
  <form method="post" action="exchange.php">
    <strong>
      Approximate amount you will receive for
      <?php echo htmlentities($_REQUEST['depositCoinAmount']); ?>
      <?php echo htmlentities($_REQUEST['depositCoin']); ?>
      :
    </strong>
    <?php echo htmlentities($rate->destinationCoinAmount); ?>
    <?php echo htmlentities($_REQUEST['destinationCoin']); ?>
    <br>
    <strong>
      Your <?php echo htmlentities($_REQUEST['destinationCoin']); ?> wallet address:
    </strong>
    <input type="text" name="destinationAddress" required>
    <br>
    <strong>Your email address (optional)</strong>
    <input type="email" name="userEmail">
    <br>
    <input
      type="hidden"
      name="depositCoin"
      value="<?php echo htmlentities($_REQUEST['depositCoin']) ?>"
    >
    <input
      type="hidden"
      name="destinationCoin"
      value="<?php echo htmlentities($_REQUEST['destinationCoin']) ?>"
    >
    <input
      type="hidden"
      name="depositCoinAmount"
      value="<?php echo htmlentities($_REQUEST['depositCoinAmount']) ?>"
    >
    <input type="submit" value="Exchange Now">
  </form>
<?php endif; ?>

<hr>
<a href="index.php">Choose different pair</a>

This is the most complex file in this example, but we can break down its operation to the following:

  • depositCoin and destinationCoin are sent as query parameters in the URL.
  • The script will query the rate and limits using POST /rate.
  • A form is displayed to the user where they can set the amount in the source currency that they want to exchange. The exchange limits are shown below.
  • When the user clicks "Check Rate", the page is reloaded with an additional depositCoinAmount query parameter that's also sent to the API.
  • When a rate was returned, an additional section is displayed to the user with the approximate destination coin amount and a form to enter the wallet address and email and submit the order.

When the user first sees this page, it looks like this:

Screenshot 2

After the user entered an amount and clicked "Check Rate", they see this:

Screenshot 3

Step 4

The order creation is done in exchange.php. Let's create this file now with the following content:

<?php

require('./api.php');

try {
  $order = callFoxApi('POST', '/order', [
    'depositCoin' => $_REQUEST['depositCoin'],
    'destinationCoin' => $_REQUEST['destinationCoin'],
    'depositCoinAmount' => $_REQUEST['depositCoinAmount'],
    'destinationAddress' => [
      'address' => $_REQUEST['destinationAddress'],
      'tag' => null
    ],
    'userEmail' => $_REQUEST['userEmail'] ?: null
  ]);

  header('Location: status.php?' . http_build_query(['orderId' => $order->orderId]));
} catch (Exception $e) {
  if (isset($e->foxErrorMessage)) {
    ?>
      <h3>Error: <?php echo htmlentities($e->foxErrorMessage); ?></h3>
      Please go back in your browser to try again!
    <?php
  } else {
    throw $e;
  }
}

That one is simple. We just send all the necessary parameters to the POST /order endpoint. Note that the address consists of two fields, address and tag, but the tag is currently unused, that's why we send null. It will become relevant once fox.exchange will support currencies that require a payment ID, such as Monero.

Once the order was successfully created, we redirect the user to the status.php page with the order ID as parameter.

Step 5

Create a file status.php with the following content:

<?php require('./api.php'); ?>
<?php $order = callFoxApi('GET', '/order/' . urlencode($_REQUEST['orderId'])); ?>
<meta http-equiv="refresh" content="10; URL=<?php echo htmlentities($_SERVER['REQUEST_URI']) ?>">
<h1>Order Status</h1>
<strong>Your order ID is: <code><?php echo htmlentities($order->orderId); ?></code></strong>
<?php if ($order->status === 'no_deposit'): ?>
  <h2>Waiting for your deposit...</h2>
  Please send
  <strong>
    <?php echo htmlentities($order->depositCoinAmount); ?>
    <?php echo htmlentities($order->depositCoin); ?>
  </strong>
  to address
  <strong><?php echo htmlentities($order->exchangeAddress->address); ?></strong>
  to continue!
  <br>
  <img src="<?php echo htmlentities($order->qrCodeUrl); ?>">
<?php elseif ($order->status === 'confirming'): ?>
  <h2>Waiting for confirmations...</h2>
<?php elseif ($order->status === 'exchanging'): ?>
  <h2>Trading your coins now...</h2>
<?php elseif ($order->status === 'sending'): ?>
  <h2>Initiating transfer of your coins...</h2>
<?php elseif ($order->status === 'complete'): ?>
  <h2>Your exchange completed!</h2>
  You received
  <strong>
    <?php echo htmlentities($order->destinationCoinAmount); ?>
    <?php echo htmlentities($order->destinationCoin); ?>
  </strong>
  in exchange of your
  <strong>
    <?php echo htmlentities($order->depositCoinAmount); ?>
    <?php echo htmlentities($order->depositCoin); ?>
  </strong>
  !
  <br>
  The money is on the way to your wallet, the transaction ID is:
  <strong><?php echo htmlentities($order->outputTransactionHash); ?></strong>
<?php elseif ($order->status === 'timeout'): ?>
  <h2>Your order expired! Please go back and create a new one.</h2>
<?php else: ?>
  <h2>A problem occured with your order! Support has been notified.</h2>
<?php endif; ?>

<hr>
<a href="index.php">New transaction</a>

Although this file may look a bit long, it is actually very straight forward. We query the order status from the GET /order/:orderId endpoint and display it to the user. Every 10 seconds, the page is automatically refreshed using the refresh meta tag.

While we are waiting for the deposit (status no_deposit), we show instructions to the user about how much funds they need to send to which address. Additionally, a QR code is displayed which they can use with their mobile wallets instead of manually typing the amount and address.

Screenshot 4

After the deposit was received, we just display a line with info about what's currently happening (e.g. "Waiting for confirmations"). Once the exchange was completed (status complete), we show the user how much money they received and what the transaction ID on the blockchain is.

Screenshot 5

That's it, we now have a working fox.exchange integration - users can go to our page and exchange their coins!


Back to documentation overview