Skip to content
Last updated

Trusted Server Connection

Choose the server-to-server connection option that fits your environment. Mutual TLS (mTLS) is designed for issuers that cannot use stable public egress addresses for source-IP allowlisting.

Connection options

For each environment, choose one network-access path:

  • Source-IP allowlist: connect to the standard API hostname from approved public egress IP addresses or CIDR ranges.
  • mTLS: connect to the dedicated mTLS hostname and present an issuer client certificate during the TLS handshake.

These are separate connection paths. An mTLS request is not made to the source-IP-allowlisted hostname, and a client certificate is not sent to that hostname. In both cases, the same Omni endpoints, request bodies, and entity API token apply.

Choose the correct base URL

Use the base URL that matches both the environment and the network-access path you selected.

EnvironmentSource-IP allowlist URLmTLS URL
Sandboxhttps://sandbox.percents.comhttps://mtls.test.percents.com
Productionhttps://prod.percents.comhttps://mtls.prod.percents.com

The mTLS host uses the standard HTTPS port (443). Do not replace only part of a URL or route mTLS traffic through the standard host: select the complete base URL from this table.

How server-to-server mTLS works

Ordinary HTTPS verifies the Percents server to your client. With mTLS, your client also presents a certificate during the TLS handshake. Percents verifies that certificate before the API request is processed. This provides a second, cryptographic proof that the calling server holds the corresponding private key.

The mTLS certificate is a network-access credential, not an API authorization credential. Continue to send your entity-owned API token with every request:

Authorization: token <token-id>:<token-secret>

The client certificate and API token must both belong to the same entity. Percents then resolves that entity's issuer association and checks the issuer's API permissions. A valid certificate does not replace an API token or grant additional issuer access.

For background on the protocol and deployment model, see RFC 8446, the TLS 1.3 specification and the OWASP Transport Layer Security Cheat Sheet.

Quickstart

1. Generate a private key and CSR

Generate the keypair in your own controlled environment. The private key must remain there: Percents never receives or returns a private key. A certificate signing request (CSR) contains the public key and certificate-subject information needed to issue a certificate; it is not a private key. Attach the CSR file to your request through the agreed secure channel.

This OpenSSL command generates a 2048-bit RSA private key and a CSR. Replace the example common name with an identifier meaningful to your integration team.

umask 077

openssl req -new -newkey rsa:2048 -nodes \
  -keyout percents-omni-client.key \
  -out percents-omni-client.csr \
  -subj '/CN=issuer-omni-client'

chmod 600 percents-omni-client.key

Keep these files as follows:

  • percents-omni-client.key — Keep private in your key-management system. It proves your client controls the certificate; Percents never receives or returns it.
  • percents-omni-client.csr — Attach it to the request sent through the agreed secure channel. It requests a client certificate and contains the public key and subject information, not a private key.
  • percents-omni-client.crt — Keep it with the private key after Percents returns it through the agreed secure channel. It is the signed public client certificate your HTTP client presents, not a private key.

2. Send the request to Percents

Send the following to your assigned Percents account manager for each environment you want to enable:

  • issuer and program name;
  • environment: sandbox or production;
  • attach the percents-omni-client.csr file through the agreed secure channel;
  • the name and contact details of the technical owner; and
  • a change-request or support-ticket reference, if your organization uses one.

Do not include the private key, API token, webhook signing token, or live cardholder data. The CSR is appropriate to attach through the agreed secure channel because it is not a private key; use that approved transfer path for the signed certificate as well.

Percents returns the signed PEM client certificate through the agreed secure channel after the request is approved. Percents separately confirms when the certificate is active and ready for connection testing. Do not expect mTLS requests to succeed until you receive that readiness confirmation. Percents never returns a private key. Save the certificate as percents-omni-client.crt beside the private key in your approved secret or key-management system. Percents also confirms the applicable mTLS base URL from the table above. Your existing sandbox and production API tokens remain separate and continue to be required.

3. Inspect the returned certificate

Before deployment, confirm the returned certificate is readable and that its public key matches the private key you generated:

openssl x509 -in percents-omni-client.crt -noout -subject -issuer -dates

openssl x509 -in percents-omni-client.crt -pubkey -noout | openssl sha256
openssl pkey -in percents-omni-client.key -pubout | openssl sha256

The two SHA-256 values from the final two commands must match. If they do not, stop and contact your account manager; do not deploy the certificate.

4. Make a sandbox request

Use the sandbox mTLS URL, your client certificate, your private key, and the sandbox API token:

export PERCENTS_API_BASE='https://mtls.test.percents.com'
export PERCENTS_API_TOKEN='tok_your_id:api_your_secret'

curl --fail-with-body \
  --cert percents-omni-client.crt \
  --key percents-omni-client.key \
  --header "Authorization: token ${PERCENTS_API_TOKEN}" \
  "${PERCENTS_API_BASE}/api/v1/omni/merchant"

After the sandbox request succeeds, use the separate production certificate, private key, API token, and https://mtls.prod.percents.com base URL for production. Do not reuse sandbox credentials in production.

Application examples

Each example makes the same authenticated Omni request over mTLS. Replace the placeholders with values managed by your deployment environment; do not hard-code credentials or certificate paths in application source.

import fs from 'node:fs';
import https from 'node:https';

const options = {
  hostname: 'mtls.test.percents.com',
  path: '/api/v1/omni/merchant',
  method: 'GET',
  cert: fs.readFileSync(process.env.PERCENTS_MTLS_CERT_PATH),
  key: fs.readFileSync(process.env.PERCENTS_MTLS_KEY_PATH),
  headers: { Authorization: `token ${process.env.PERCENTS_API_TOKEN}` },
};

const response = await new Promise((resolve, reject) => {
  const request = https.request(options, (result) => {
    let body = '';
    result.setEncoding('utf8');
    result.on('data', (chunk) => { body += chunk; });
    result.on('end', () => resolve({ status: result.statusCode, body }));
  });

  request.on('error', reject);
  request.end();
});

if (response.status < 200 || response.status >= 300) {
  throw new Error(`Percents request failed: ${response.status}`);
}

const merchants = JSON.parse(response.body);

Troubleshooting

What you seeLikely cause and next action
TLS handshake fails before an HTTP responseThe client certificate was not presented, is expired or revoked, is not trusted for this connection, or does not match the private key. Confirm the certificate/key pair and contact Percents if the issue persists.
401 UnauthorizedThe API token is missing, malformed, or invalid. Verify the Authorization: token ... header and the environment-specific token.
403 ForbiddenThe certificate and API token do not represent the same entity, the certificate is no longer active, or the requested API capability is not enabled. Contact Percents with the timestamp and any response request identifier.
A request works on the standard host but not the mTLS hostConfirm that you are using the mTLS URL for the correct environment and that the HTTP client is configured to present the certificate and private key.

Never send private keys, API tokens, or webhook signing tokens in an error report. Share the environment, timestamp, requested path, certificate subject or fingerprint, and any response request identifier with your account manager instead.

Rotate or revoke a certificate

Rotate before certificate expiry and after any relevant key-management policy change. Generate a new keypair and CSR for every rotation; do not reuse the existing private key. Send the new CSR and identify the certificate being replaced to your account manager. After Percents confirms the new certificate is ready, deploy it and verify a request before retiring the old keypair from your systems.

If a private key may be compromised, or an integration is being decommissioned, contact your account manager immediately and request revocation. Include the environment and certificate subject or fingerprint, but never include the private key. Treat a revoked certificate as unusable and deploy a replacement before resuming mTLS traffic.