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.
| Property | Benefit |
|---|---|
| Authenticity | Requests are cryptographically signed with your private key |
| Integrity | Any tampering with method, URL, or body invalidates the signature |
| Replay Protection | Timestamps 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
- Log in to the WickiePay Portal
- Navigate to Integrations > API Keys
- Click Add API Key
- Provide:
- Name — A descriptive identifier (e.g., "Production Server")
- Network Whitelist — Allowed IP addresses (use
0.0.0.0for 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:
| Component | Description |
|---|---|
@method | HTTP verb (POST, GET, PUT, DELETE) |
@target-uri | Full request URL |
content-digest | SHA-256 hash of the request body |
date | RFC 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
| Issue | Solution |
|---|---|
401 Unauthorized | Verify your Client ID is correct and the key is registered |
403 Forbidden | Check IP whitelist and role permissions |
| Signature mismatch | Ensure payload hasn't changed after signing |
| Expired request | Check server clock synchronization (NTP) |
Next Steps
Once authenticated, proceed to Create Account to set up your merchant tenant.