> ## Documentation Index
> Fetch the complete documentation index at: https://developers.pcibooking.net/llms.txt
> Use this file to discover all available pages before exploring further.

# Authentication

> PCI Booking API authentication methods: API key, access token, and temporary session token with code samples

PCI Booking supports three authentication methods. Each builds on the API key and serves a different purpose.

## API Key

Your API key is the foundation of all authentication. It grants unlimited, repeatable access and is used for most API calls. Pass it using either header format:

```bash theme={null}
# Option 1: Authorization header (most common)
Authorization: APIKEY your-api-key

# Option 2: Custom header
x-pcibooking-api-key: your-api-key
```

Both are equivalent. Use the API key for all server-to-server calls: processing payments, managing tokens, configuring credentials, querying data, and more.

<Warning>
  Keep your API key secret. Never expose it in client-side code, public repositories, or logs. If a request originates from a browser or any client-facing context, use a Session Token or Access Token instead.
</Warning>

## Session Token

A Session Token is generated from your API key via an API call. It is valid for **5 minutes** and can be used for **any API call** during that time.

Generate a session token:

```bash theme={null}
curl -X POST https://service.pcibooking.net/api/payments/paycard/tempsession \
  -H "Authorization: APIKEY your-api-key"
```

Response:

```text theme={null}
33b245a015cf4d10a3ca885e7f4c5600
```

Use it as a query parameter on subsequent requests:

```text theme={null}
<base_url>?sessionToken=YOUR_SESSION_TOKEN
```

Session tokens are commonly used for browser-facing operations like the hosted card entry form, card display, and sFTP tokenization.

## Access Token

An Access Token is generated **locally** using your API key and PCI Booking's SSL certificate. Unlike the session token, no API call is needed to create it. It is valid for a **configurable duration (1 to 60 minutes)** and is **single-use only**.

### How it works

1. [Download PCI Booking's SSL certificate](/getting-started/download-ssl-certificate) from `https://service.pcibooking.net/api`
2. Run the generation script locally (see code samples below)
3. The script encrypts your API key + a unique ID + expiration time using the certificate's public key
4. The output is your access token

Pass it as a query parameter:

```text theme={null}
<base_url>?accessToken=YOUR_ACCESS_TOKEN
```

### Code Samples

<Tabs>
  <Tab title="C#">
    ```csharp theme={null}
    using System;

    namespace CreateAccessToken
    {
        class Program
        {
            private static string[] helpLines = 
            { 
                "Usage: CreateAccessToken.exe <Certificate file path> <API Key> <Absolute time>",
                "Certificate file path: .cer as downloaded from https://service.pcibooking.net/api",
                "API Key: As generated in your PCI Booking account",
                "Absolute time: local time in format HH:MM:ss (up to 1 hour from now), e.g: 18:20:34"
            };

            static void Main(string[] args)
            {
                if (args.Length != 3)
                    Usage("Invalid number of arguments; expected 3");

                // read certificate
                System.Security.Cryptography.X509Certificates.X509Certificate2 cert = null;
                try
                {
                    cert = new System.Security.Cryptography.X509Certificates.X509Certificate2(args[0]);
                }
                catch (Exception ex)
                {
                    Usage("Cannot load certificate file: " + args[0] + " Error: " + ex.Message);
                }

                // read time and convert to absolute date time in UTC
                DateTime expectedExpirationLocalTime;
                if (!DateTime.TryParse(args[2], out expectedExpirationLocalTime))
                {
                    Usage("Invalid expected time: " + args[2]);
                }
                TimeSpan expiresIn = expectedExpirationLocalTime.Subtract(DateTime.Now);
                if (expiresIn > TimeSpan.FromHours(1) || expiresIn < TimeSpan.Zero)
                {
                    Usage(string.Format("Invalid expected time [{0}]. Should be up to one hour ahead ", args[2]));
                }
                DateTime expectedExpirationUTC = expectedExpirationLocalTime.ToUniversalTime();

                // Generate a guid
                string guid = Guid.NewGuid().ToString().Replace("-", "");

                // Construct data block: APIKey#GUID#ExpirationUTC
                string dataBlock = string.Format("{0}#{1}#{2}", args[1], guid, expectedExpirationUTC.ToString("o"));

                // encode and encrypt with certificate public key
                byte[] clearBytes = System.Text.Encoding.UTF8.GetBytes(dataBlock);
                System.Security.Cryptography.RSACryptoServiceProvider rsaCryptoServiceProvider = 
                    (System.Security.Cryptography.RSACryptoServiceProvider)cert.PublicKey.Key;
                byte[] encryptedBytes = rsaCryptoServiceProvider.Encrypt(clearBytes, false);

                // convert to hex string
                string accessToken = string.Concat(Array.ConvertAll(encryptedBytes, b => b.ToString("X2")));
                Console.WriteLine(accessToken);
            }

            private static void Usage(string message = "")
            {
                if (!string.IsNullOrEmpty(message))
                    Console.WriteLine(message);
                foreach (var line in helpLines)
                    Console.WriteLine(line);
                Environment.Exit(0);
            }
        }
    }
    ```
  </Tab>

  <Tab title="Java">
    ```java theme={null}
    import java.io.*;
    import java.security.cert.Certificate;
    import java.security.cert.CertificateFactory;
    import java.text.SimpleDateFormat;
    import java.text.DateFormat;
    import java.util.Calendar;
    import java.util.Date;
    import java.util.TimeZone;
    import java.util.UUID;
    import javax.crypto.Cipher;

    public class CreateAccessToken {

        private static final String[] helpLines = {
            "Usage: CreateAccessToken <Certificate file path> <API Key> <Absolute time>",
            "Certificate file path: .cer as downloaded from https://service.pcibooking.net/api",
            "API Key: As generated in your PCI Booking account",
            "Absolute time: local time in format HH:MM:ss (up to 1 hour from now), e.g: 18:20:34"
        };

        public static void main(String[] args) {
            if (args.length != 3) {
                Usage("Invalid number of arguments; expected 3");
            }

            Certificate cert = null;
            try {
                InputStream fis = new FileInputStream(args[0]);
                BufferedInputStream bis = new BufferedInputStream(fis);
                CertificateFactory cf = CertificateFactory.getInstance("X.509");
                cert = cf.generateCertificate(bis);
            } catch (Exception ex) {
                Usage("Cannot load certificate file: " + args[0] + " Error: " + ex);
            }

            Date expectedExpirationLocalTime = null;
            Date date = new Date();
            SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
            String cDate = formatter.format(date);
            formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            try {
                expectedExpirationLocalTime = formatter.parse(cDate + " " + args[2]);
            } catch (Exception ex) {
                Usage("Invalid expected time: " + args[2] + " Error: " + ex);
            }

            Calendar cal = Calendar.getInstance();
            long expiresIn = expectedExpirationLocalTime.getTime() - cal.getTime().getTime();
            if (expiresIn > 3600000 || expiresIn < 0) {
                Usage("Invalid expected time [" + args[2] + "]. Should be up to one hour ahead ");
            }

            formatter.setTimeZone(TimeZone.getTimeZone("UTC"));
            DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
            df.setTimeZone(TimeZone.getTimeZone("UTC"));
            String asISO8601 = df.format(expectedExpirationLocalTime);

            String guid = UUID.randomUUID().toString().replace("-", "");
            String dataBlock = String.format("%1$s#%2$s#%3$s", args[1], guid, asISO8601);

            byte[] clearBytes = null;
            try {
                clearBytes = dataBlock.getBytes("UTF-8");
            } catch (Exception ex) {
                Usage("Cannot encode to UTF8: Error: " + ex);
            }

            byte[] encryptedBytes = null;
            try {
                final Cipher cipher = Cipher.getInstance("RSA");
                cipher.init(Cipher.ENCRYPT_MODE, cert.getPublicKey());
                encryptedBytes = cipher.doFinal(clearBytes);
            } catch (Exception ex) {
                Usage("Cannot encrypt: Error: " + ex);
            }

            String accessToken = byteArrayToHex(encryptedBytes);
            System.out.println(accessToken);
        }

        private static void Usage(String message) {
            if (!message.isEmpty()) System.out.println(message);
            for (String line : helpLines) System.out.println(line);
            System.exit(0);
        }

        private static String byteArrayToHex(byte[] a) {
            StringBuilder sb = new StringBuilder(a.length * 2);
            for (byte b : a) sb.append(String.format("%02X", b & 0xff));
            return sb.toString();
        }
    }
    ```
  </Tab>

  <Tab title="PHP">
    ```php theme={null}
    <?php

    require('vendor/autoload.php');

    class CreateAccessToken
    {
        private $certificate;
        private $apiKey;
        private $expirationTime;

        public function __construct($certificate, $apiKey, DateTime $expirationTime)
        {
            $this->certificate = $certificate;
            $this->apiKey = $apiKey;
            $this->expirationTime = $expirationTime;
        }

        public function createToken()
        {
            $cert = openssl_get_publickey($this->certificate);

            $this->expirationTime->setTimeZone(new DateTimeZone('UTC'));
            $expirationAsISO8601 = $this->expirationTime->format(DateTime::ISO8601);
            $guid = $this->generateUUID();
            $dataBlock = sprintf('%s#%s#%s', $this->apiKey, $guid, $expirationAsISO8601);

            openssl_public_encrypt($dataBlock, $encryptedData, $cert);
            $encryptedDataHex = strtoupper(bin2hex($encryptedData));

            return $encryptedDataHex;
        }

        private function generateUUID()
        {
            return str_replace('-', '', Ramsey\Uuid\Uuid::uuid4());
        }
    }
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    import binascii
    import uuid
    import pytz

    from cryptography.hazmat.backends import default_backend
    from cryptography.hazmat.primitives.asymmetric import padding
    from cryptography.x509 import load_pem_x509_certificate


    def create_access_token(cert_file, api_key, expiration_time):
        cert = load_pem_x509_certificate(cert_file.read(), default_backend())
        public_key = cert.public_key()

        try:
            expiration_time = pytz.utc.localize(expiration_time)
        except ValueError:
            pass

        expiration_string = expiration_time.isoformat()
        data_block = '{}#{}#{}'.format(api_key, uuid.uuid4(), expiration_string)
        ciphertext = public_key.encrypt(data_block, padding.PKCS1v15())

        return binascii.hexlify(ciphertext)


    def main():
        import datetime
        import sys

        if len(sys.argv) != 4:
            print("Usage: {} cert_file api_key expiration_timestamp".format(sys.argv[0]))
            exit(1)

        with open(sys.argv[1], "rb") as cert_file:
            expiration_time = datetime.datetime.fromtimestamp(int(sys.argv[3]))
            print(create_access_token(cert_file, sys.argv[2], expiration_time))


    if __name__ == '__main__':
        main()
    ```
  </Tab>
</Tabs>

## Comparison

|                   | API Key                    | Session Token                                        | Access Token                                       |
| ----------------- | -------------------------- | ---------------------------------------------------- | -------------------------------------------------- |
| **How to create** | Provided with your account | API call using your API key                          | Generated locally using API key + SSL certificate  |
| **Lifetime**      | Permanent (until rotated)  | 5 minutes                                            | 1 to 60 minutes (configurable)                     |
| **Reuse**         | Unlimited                  | Unlimited (within lifetime)                          | Single use                                         |
| **Passed via**    | HTTP header                | `?sessionToken=` query parameter                     | `?accessToken=` query parameter                    |
| **Best for**      | Server-to-server calls     | Browser-facing operations (card forms, card display) | Delegated single operations with controlled expiry |

## Which should I use?

* **Server-to-server calls** (processing payments, managing tokens, configuring settings): use the **API key**
* **Browser-facing operations** (card entry form iframe, card display): use a **Session Token** or **Access Token**. Your API key must never be exposed to the browser.
* **Need precise control over expiry and single-use guarantees**: use an **Access Token**
* **Quick integration for browser operations**: use a **Session Token** (simpler, just one API call)

## Related

* [Create an Account](/getting-started/create-account) - Get your API keys and portal access
* [Quickstart](/start-here/quickstart) - End-to-end integration walkthrough
* [Testing and Going Live](/getting-started/testing-and-going-live) - Move from sandbox to production
* [API Conventions](/reference/api-conventions) - Request formats, headers, and common patterns
