Skip to main content

API Authentication

WickiePay uses RSA-based HTTP Message Signatures (RFC 9421) to authenticate API requests. This cryptographic approach provides strong security beyond TLS transport protection.

How It Works

Every API request is signed with your private RSA key. The server verifies the signature using your registered public key.

PropertyBenefit
AuthenticityRequests are cryptographically signed with your private key
IntegrityAny tampering with method, URL, or body invalidates the signature
Replay ProtectionTimestamps prevent resubmission of old requests

Step 1: Generate RSA Key Pair

# Generate private key
openssl genrsa -out api-client-key.pem 2048

# Extract public key
openssl rsa -in api-client-key.pem -pubout -out api-client-public-key.pem
Keep Your Private Key Secure

Never share your private key. Only upload the public key to the WickiePay portal. Store the private key securely on your server.

Step 2: Register Public Key

  1. Log in to the WickiePay Portal
  2. Navigate to Integrations > API Keys
  3. Click Add API Key
  4. Provide:
    • Name — A descriptive identifier (e.g., "Production Server")
    • Network Whitelist — Allowed IP addresses (use 0.0.0.0 for all during testing)
    • Public Key — Paste the contents of api-client-public-key.pem
    • Role — Assign permissions for this key

Step 3: Obtain Client ID

After registering your key, copy the Client ID from the API Keys section. You'll need this to identify which key signed each request.

Signature Components

Each request must include these signed components:

ComponentDescription
@methodHTTP verb (POST, GET, PUT, DELETE)
@target-uriFull request URL
content-digestSHA-256 hash of the request body
dateRFC 7231 formatted timestamp

Required Headers

Date: Tue, 27 May 2025 10:21:54 GMT
Content-Type: application/json
Content-Digest: sha-256=:W6ph5Mm5Pz8GgiULbPgzG37mj9g=:
Signature-Input: sig=("@method" "@target-uri" "content-digest" "date");created=1716792114;keyid="your-client-id";alg="rsa-v1_5-sha256"
Signature: sig=:MEUCIQDn...==:

Code Example

Java

import java.security.*;
import java.util.*;

public class HttpSigner {
private final PrivateKey privateKey;
private final String clientId;

public HttpSigner(String base64PrivateKey, String clientId) {
this.privateKey = loadPrivateKey(base64PrivateKey);
this.clientId = clientId;
}

public Map<String, String> buildHeaders(String url, String payload, String method) {
// 1. Generate SHA-256 digest of payload
String digest = generateDigest(payload);

// 2. Create signature base string
String signatureBase = buildSignatureBase(method, url, digest);

// 3. Sign with RSA-SHA256
String signature = sign(signatureBase);

// 4. Return required headers
Map<String, String> headers = new HashMap<>();
headers.put("Date", formatRfc7231Date());
headers.put("Content-Digest", "sha-256=:" + digest + ":");
headers.put("Signature-Input", buildSignatureInput());
headers.put("Signature", "sig=:" + signature + ":");
return headers;
}
}

Python

import hashlib
import base64
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import padding

def sign_request(private_key_pem, client_id, method, url, body):
# Load private key
private_key = serialization.load_pem_private_key(private_key_pem, password=None)

# Generate content digest
digest = hashlib.sha256(body.encode()).digest()
content_digest = f"sha-256=:{base64.b64encode(digest).decode()}:"

# Build signature base
signature_base = f'"@method": {method}\n"@target-uri": {url}\n"content-digest": {content_digest}'

# Sign
signature = private_key.sign(
signature_base.encode(),
padding.PKCS1v15(),
hashes.SHA256()
)

return {
"Content-Digest": content_digest,
"Signature": f"sig=:{base64.b64encode(signature).decode()}:",
"Signature-Input": f'sig=("@method" "@target-uri" "content-digest" "date");keyid="{client_id}";alg="rsa-v1_5-sha256"'
}

Troubleshooting

IssueSolution
401 UnauthorizedVerify your Client ID is correct and the key is registered
403 ForbiddenCheck IP whitelist and role permissions
Signature mismatchEnsure payload hasn't changed after signing
Expired requestCheck server clock synchronization (NTP)

Next Steps

Once authenticated, proceed to Create Account to set up your merchant tenant.