Encrypted Payload Creation
All API v1 endpoints require encrypted payloads using XSalsa20-Poly1305 (NaCl SecretBox). This page provides working code examples for different languages.
Encryption Format
The encrypted payload format is:
base64( 0x02 + nonce(24 bytes) + ciphertext )- 0x02 — format version byte
- nonce — 24 random bytes (XSalsa20 nonce)
- ciphertext — encrypted data with Poly1305 MAC
- Key derivation — SHA256(api_secret)
Request Code Samples
Python
import base64
import hashlib
import os
import json
from nacl.secret import SecretBox
FORMAT_VERSION_NACL = 0x02
class SayferWebNacl:
def __init__(self, password: str):
if len(password) < 8:
raise ValueError("Password is too short")
self.password = password.encode()
key = hashlib.sha256(self.password).digest()
self._box = SecretBox(key)
def encrypt(self, data: str | bytes) -> str:
"""Encrypt string or bytes. Returns base64 encoded result."""
if isinstance(data, str):
data = data.encode()
nonce = os.urandom(SecretBox.NONCE_SIZE) # 24 bytes
ciphertext = self._box.encrypt(data, nonce).ciphertext
# Format: version_byte + nonce + ciphertext
combined = bytes([FORMAT_VERSION_NACL]) + nonce + ciphertext
return base64.b64encode(combined).decode()
def decrypt(self, key_field: str) -> str:
"""Decrypt base64 encoded string."""
combined = base64.b64decode(key_field)
if combined[0] == FORMAT_VERSION_NACL:
nonce = combined[1:25]
ciphertext = combined[25:]
plaintext = self._box.decrypt(ciphertext, nonce)
return plaintext.decode()
else:
raise ValueError("Unsupported format")
# Usage example
if __name__ == "__main__":
api_secret = "your_api_secret_key_here"
sayfer = SayferWebNacl(api_secret)
# Create payload
payload = {
"request_timestamp": 1700000000000000,
"card_id": "card_abc123"
}
# Encrypt
encrypted = sayfer.encrypt(json.dumps(payload))
print(f"Encrypted: {encrypted}")
# Decrypt
decrypted = json.loads(sayfer.decrypt(encrypted))
print(f"Decrypted: {decrypted}")Dependencies
| Language | Package | Install Command |
|---|---|---|
| Python | pynacl | pip install pynacl |
| Go | golang.org/x/crypto | go get golang.org/x/crypto/nacl/secretbox |
| JavaScript | tweetnacl | npm install tweetnacl |
| TypeScript | tweetnacl | npm install tweetnacl @types/tweetnacl |
Payload Structure
Every encrypted payload must include request_timestamp for replay protection:
{
"request_timestamp": 1700000000000000, // Unix timestamp in microseconds
"card_id": "card_abc123", // Your request fields...
// ... other fields
}The timestamp must be within 30 seconds of the server time to prevent replay attacks.