Security & best practices
Follow these practices to keep your API key and integration secure.
API key security
- Server-side only — Call the CardPlusPay API from your backend (e.g. PHP, Node, Python). Never embed the API key in frontend JavaScript, mobile app binaries, or public repositories.
- Store in environment or secrets — Use environment variables (e.g.
CARDPLUSPAY_API_KEY) or a secrets manager. Do not hardcode the key or commit it to version control. - Rotate if compromised — If the key may have been exposed, generate a new key in API Keys in the CardPlusPay Dashboard and update your application; disable or delete the old key.
- Limit access — Restrict who can view or copy API keys in your team. Use separate keys per environment (e.g. production vs test) if you use multiple keys.
HTTPS and requests
- Always use HTTPS — All requests must go to
https://api.cardpluspay.com. Do not send the API key or sensitive data over plain HTTP. - Validate responses — Check
successin the response envelope before trustingdata. Handle errors and timeouts in your code. - Idempotency — For
POST /orders, send a unique, stableIdempotency-Keyper purchase attempt (UUID recommended). Retries with the same key and body replay the original response. Use a new key only when starting a genuinely new purchase. - Purchase request timeout — Set your HTTP client timeout to at least 90 seconds for
POST /orders(180 seconds recommended for some SKUs). If the connection drops before you receive a response, retry with the same idempotency key rather than creating a duplicate order. - Pending orders — HTTP 200 with
status: pendingmeans fulfillment is in progress. PollGET /orders/{id}if you do not use webhooks; do not refund based on elapsed time alone.
Webhook signatures
- HTTPS only — Your receiver URL must use HTTPS. CardPlusPay POSTs to that URL; it is not an inbound CardPlusPay API path.
- Signing secret — Shown once when you first save a webhook URL or rotate the secret. Verify
X-Webhook-Signatureas HMAC-SHA256 of the raw JSON body. Reject timestamps older than 5 minutes (X-Webhook-Timestamp). - Idempotency — Treat
id/X-Webhook-Idas unique; retries reuse the same id. - No codes in webhooks — Fetch codes with
GET /orders/{id}afterorder.completed. See order webhooks.
Rate limits
Each API key is limited to a number of requests per 60-second window. Dashboard-generated keys typically allow 100 requests per minute. CardPlusPay may raise the cap for a key. All /v1 routes on that key share the same budget (catalog, purchase, poll, challenge). If request signing is on, a 401 from a missing or invalid challenge/signature does not use that budget; GET /v1/challenge does.
Successful responses include X-RateLimit-Limit and X-RateLimit-Remaining. When the cap is exceeded, the API returns HTTP 429 with the standard envelope:
{
"success": false,
"message": "Too many requests. Retry later.",
"data": {
"retry_after": 12
}
}
Headers include Retry-After, X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset. Wait at least retry_after seconds (or honour Retry-After) before retrying; use backoff or a queue if you send bursts. Polling GET /orders/{id} counts toward the same limit as POST /orders.
Data handling
- Gift card codes are sensitive. Transmit them only over HTTPS and store them securely. Do not log full codes.
- Buyer account fields (
fieldson direct top-up orders) are personal data. CardPlusPay does not echo them in API responses — store them securely in your application and comply with your privacy policy. - When passing customer email or order data to the API, ensure you comply with your privacy policy and applicable laws.