> ## Documentation Index
> Fetch the complete documentation index at: https://docs.cdp.coinbase.com/llms.txt
> Use this file to discover all available pages before exploring further.

# INTX REST API Authentication

This page explains how to sign and authenticate International Exchange (INTX) REST API endpoints.

<Info>
  The INTX FIX API uses its own authentication scheme detailed in the [FIX Overview](/international-exchange/fix-api/fix-api-overview).
</Info>

## Generating an API Key

Certain API endpoints require authentication to access. To interact with these resources, you must create an API key via the Coinbase International Exchange website.

## Signing Requests

The INTX REST API requests must include an access signature header.

<Warning>
  * `CB-ACCESS-KEY`: The API key as a string
  * `CB-ACCESS-PASSPHRASE`: The Passphrase shown when creating the API key
  * `CB-ACCESS-SIGN`: The Base64-encoded signature
  * `CB-ACCESS-TIMESTAMP`: A timestamp for your request
</Warning>

### Selecting a Timestamp

The `CB-ACCESS-TIMESTAMP` header MUST be number of seconds since [Unix Epoch](http://en.wikipedia.org/wiki/Unix_time) in UTC. Decimal values are **not** allowed. Make sure to use an integer.

Your timestamp should be within 5 seconds of the API service time or your request is considered expired and will be rejected.

### Creating a Signature

The `CB-ACCESS-SIGN` header is generated by creating an HMAC-SHA-256 using the secret key on the prehash string `timestamp + method + requestPath + body` (where `+` represents string concatenation) and Base64-encode the output.

* `timestamp` is the same as the `CB-ACCESS-TIMESTAMP` header.

* `method` should be UPPER CASE, e.g., `GET` or `POST`.

* `requestPath` should only include the path of the API endpoint. Do NOT include the base URL or query parameters when creating the signature.

  **Valid requestPath example** to include in the string for hashing:

  ```
  /api/v1/portfolios/<YOUR_PORTFOLIO_ID_HERE>/positions
  ```

  **Invalid requestPath example**:

  ```
  api.international.coinbase.com/v1/portfolios/<PORTFOLIO_ID>/positions?portfolio=5189861793641175
  ```

* `body` is the request body string or omitted if there is no request body (typically for `GET` requests).

<Tip>
  Remember to Base64-encode the digest output before sending in the header. That is, the secret should not be Base64 encoded when using HMAC-SHA-256 to sign the request, but the entire resulting message.
</Tip>

## Code Samples

The following examples demonstrate how to sign a message by generating an HMAC signature, setting the headers, and making a GET request to the specified URL.

<CodeGroup>
  ```python lines wrap [expandable] theme={null}
  import json
  import hmac
  import hashlib
  import time
  import base64
  import requests
  import urllib.parse

  method = 'GET'
  url = 'url'
  secret_key = 'secret'
  timestamp = str(int(time.time()))
  passphrase = 'password'
  access_key = 'access_key'
  body = ''

  message = timestamp + method + urllib.parse.urlparse(url).path + str(body or '')
  hmac_key = base64.b64decode(secret_key)
  signature = hmac.new(hmac_key, message.encode('utf-8'), digestmod=hashlib.sha256).digest()
  signature_b64 = base64.b64encode(signature).decode()

  headers = {
      "CB-ACCESS-TIMESTAMP": timestamp,
      "CB-ACCESS-SIGN": signature_b64,
      "CB-ACCESS-PASSPHRASE": passphrase,
      "CB-ACCESS-KEY": access_key
  }

  response = requests.get(url, headers=headers)
  print(response.json())
  ```

  ```ruby lines wrap [expandable] theme={null}
  require 'json'
  require 'openssl'
  require 'base64'
  require 'net/http'
  require 'uri'

  method = 'GET'
  url = 'url'
  secret_key = 'secret'
  timestamp = Time.now.to_i.to_s
  passphrase = 'password'
  access_key = 'access_key'
  body = ''

  message = timestamp + method + URI.parse(url).path + (body || '').to_s
  hmac_key = Base64.decode64(secret_key)
  signature = OpenSSL::HMAC.digest('sha256', hmac_key, message.encode('utf-8'))
  signature_b64 = Base64.strict_encode64(signature)

  headers = {
    'CB-ACCESS-TIMESTAMP' => timestamp,
    'CB-ACCESS-SIGN' => signature_b64,
    'CB-ACCESS-PASSPHRASE' => passphrase,
    'CB-ACCESS-KEY' => access_key
  }

  uri = URI.parse(url)
  http = Net::HTTP.new(uri.host, uri.port)
  http.use_ssl = (uri.scheme == 'https')

  request = Net::HTTP::Get.new(uri.request_uri)
  headers.each { |key, value| request[key] = value }

  response = http.request(request)

  puts JSON.parse(response.body)
  ```

  ```js lines wrap [expandable] theme={null}
  const crypto = require('crypto');
  const axios = require('axios');
  const querystring = require('querystring');

  const method = 'GET';
  const url = 'url';
  const secret_key = 'secret';
  const timestamp = String(Math.floor(Date.now() / 1000));
  const passphrase = 'password';
  const access_key = 'access_key';
  const body = '';

  const message = timestamp + method + new URL(url).pathname + (body || '');
  const hmac_key = Buffer.from(secret_key, 'base64');
  const signature = crypto.createHmac('sha256', hmac_key).update(message).digest();
  const signature_b64 = signature.toString('base64');

  const headers = {
    'CB-ACCESS-TIMESTAMP': timestamp,
    'CB-ACCESS-SIGN': signature_b64,
    'CB-ACCESS-PASSPHRASE': passphrase,
    'CB-ACCESS-KEY': access_key
  };

  axios.get(url, { headers })
    .then(response => {
      console.log(response.data);
    })
    .catch(error => {
      console.error(error);
    });
  ```
</CodeGroup>
