This document provides the definitive specification for all API endpoints with comprehensive debug integration and honeypot bot detection. It covers both the public "Browse & Pay" journey and the admin-driven "Shareable Link" journey, detailing the purpose, requirements, security controls, and debug visibility for each step.
NEW Features in v3.5:
- Debug Integration: 9+ numbered security checks with correlation IDs
- Honeypot Detection: Advanced bot detection using emoji injection pattern
- Security Visibility: Comprehensive debug output for all security validations
- Performance Monitoring: Request duration and check timing analysis
This is the primary flow for a user who visits the website, browses tours, and decides to make a payment.
sequenceDiagram participant C as Browser (Client) participant S as Server (API) participant G as Zenpay Gateway Note over C,S: User browses site and clicks "Pay Now" on a tour page. C->>S: 1. GET /api/v1/tour/{id} S-->>C: Returns Tour Details<br/>**Sets `SESSION` & `XSRF-TOKEN` cookies** C->>S: 2. POST /api/v1/create-nonce S-->>C: Returns `{ "nonce": "..." }` C->>S: 3. POST /api/v1/payment/exchange-nonce S-->>C: Returns `{ "fingerprint": "..." }` Note over C,G: Client initializes Zenpay plugin with fingerprint. C->>G: 4. User completes payment via Zenpay UI G-->>S: 5. POST /api/v1/payment/callback S-->>G: 200 OK
| Endpoint | Method | Requirements | Security Controls | Used By | How & Why (Justification) |
|---|---|---|---|---|---|
GET /api/v1/tours | GET | • Query params: page, limit, featured (optional) | • HSTS, CSP Headers | Frontend | Tours List: Returns paginated list of tours (max 10/page). Security-neutral endpoint - no cookies set. Enables 1-call tour fetching vs 3 separate calls. |
GET /api/v1/tour/{id} | GET | Tour ID in path. | • HSTS, CSP Headers<br>• Cookie Seeding | Frontend | Entry Point: Establishes a secure, temporary session context for the browser by setting SESSION and XSRF-TOKEN cookies. |
POST /api/v1/create-nonce | POST | • X-XSRF-TOKEN Header<br>• Body: { tourId, cfToken, email_verify } | • CSRF Protection<br>• Bot Detection (Turnstile + Honeypot)<br>• Rate Limiting<br>• 9+ Security Checks with Debug | Frontend | Security Gate: Issues a 60-second, single-use "permission slip" (nonce) only after passing comprehensive security validation including honeypot bot detection. |
POST /api/v1/payment/exchange-nonce | POST | • X-Payment-Nonce Header<br>• Body: { apiKey, ... } | • Nonce Validation<br>• Atomic Consumption | Frontend | Fingerprint Generation: Securely consumes the nonce to generate the Zenpay fingerprint. Server injects secrets; they are never exposed. |
POST /api/v1/payment/callback | POST | Zenpay JSON body. | • Callback Authentication | Backend | Payment Confirmation: Securely verifies the transaction outcome by re-computing and matching Zenpay's ValidationCode. This is the definitive source of truth. |
This flow is for when an administrator generates a direct payment link to send to a specific customer.
sequenceDiagram participant A as Admin participant S as Server (API) participant C as Customer's Browser Note over A,S: Admin needs to create a direct payment link. A->>S: 1. POST /api/v1/admin/generate-pay-token S-->>A: Returns `{ "shareableUrl": "..." }` Note over A,C: Admin sends the URL to the customer. C->>S: 2. GET /api/v1/booking/{token} S-->>C: Returns Tour Details<br/>**Sets `SESSION` & `XSRF-TOKEN` cookies** Note over C: From here, the payment process is IDENTICAL to Flow 1. C->>S: 3. POST /api/v1/create-nonce S-->>C: `{ "nonce": "..." }` C->>S: 4. POST /api/v1/payment/exchange-nonce S-->>C: `{ "fingerprint": "..." }`
| Endpoint | Method | Requirements | Security Controls | Used By | How & Why (Justification) |
|---|---|---|---|---|---|
POST /api/v1/admin/generate-pay-token | POST | Authorization Header with Admin API Key. | • API Key Authentication | Backend/Admin Script | Link Creation: An admin-only, protected endpoint to create a secure, single-use token that forms the basis of a shareable link. |
GET /api/v1/booking/{token} | GET | Secure pay-token in path. | • Token Validation (single-use)<br>• Cookie Seeding | Frontend | Link Entry Point: Validates the one-time token from the URL and then establishes the same secure session context as the public flow by setting SESSION and XSRF-TOKEN cookies. |
Where is create-fingerprint? at what point are you creating the actual fingerprint thats needed for zp.init ?
Of course, Menethil. That is an excellent and critical question. I apologize if my previous summary was not clear enough on this point.
You are correct to ask where the fingerprint is created. Let's pinpoint it exactly.
The actual fingerprint needed for $.zpPayment().init() is created by the server during Step 3 of the "Browse & Pay" flow.
Specifically, it happens inside this endpoint call:
POST /api/v1/payment/exchange-nonce
Here is the sequence:
- Your frontend calls
POST /api/v1/create-nonceand gets anonceback. - Your frontend immediately calls
POST /api/v1/payment/exchange-nonce, sending thatnoncein the header. - The server receives this request. It validates the nonce, then securely adds its secret
usernameandpasswordto the other payment details you sent. It combines everything into the pipe-delimited string and creates theSHA3-512hash. This hash is the fingerprint. - The server's response to this call is a simple JSON object containing the fingerprint:
{ "fingerprint": "the_hash_value_goes_here" }. - Your frontend code then takes this
fingerprintfrom the response and uses it to initialize the Zenpay plugin.
In the table I provided, this is covered in the row for POST /api/v1/payment/exchange-nonce, under the "How & Why" column:
Fingerprint Generation: Securely consumes the nonce to generate the Zenpay fingerprint. Server injects secrets; they are never exposed.
You are right to want this clarified. The endpoint /api/v1/payment/exchange-nonce is where the server does the work of creating the fingerprint.
how is the frontend sending apikey, mode, paymentamount, merchantuniquepaymentid, tiomestamp to server, at what point, is that how its creating noce or something and exchanging it?
Of course, Menethil. That is the perfect question, and the distinction between the two API calls is the most important part of the entire security design. I will clarify it precisely.
The frontend sends those parameters (apiKey, paymentAmount, etc.) to the server during the second API call.
Here is the exact, step-by-step process:
First, when the user clicks "Pay Now", the frontend makes a call to POST /api/v1/create-nonce.
- Purpose: This call performs comprehensive security verification through 9+ numbered security checks. Its job is to get a "permission slip" (the nonce) only after passing all validations.
- Payload Sent to Server: The frontend sends security validation information:
{ "tourId": "tour_123", "cfToken": "cloudflare_turnstile_token", "email_verify": "🍯" }
- NEW: Honeypot Field - The
email_verifyfield contains the exact 🍯 emoji for human verification. Bots that fill this field with any other value receive fake nonces. - What is NOT sent: At this stage, the server does not need and the client does not send the
apiKey,paymentAmount, ortimestamp.
Security Validation Process (9+ Checks):
- Check1: CORS Origin Check - validates request origin
- Check2: CORS Validation Passed - ensures proper CORS headers
- Check3: User Agent Security Scan - detects suspicious user agent patterns
- Check4: Referer Validation - validates referer for sensitive endpoints
- Check5: Origin Validation - validates origin for sensitive endpoints
- Check6: Header Content Security Scan - scans headers for malicious content
- Check7: Request Size Validation - enforces 1MB request size limit
- Check8: Rate Limit Validation - IP-based token bucket algorithm
- Check9: Honeypot Bot Detection - validates 🍯 emoji for human verification
- CSRF Protection: X-XSRF-TOKEN header verification
- Turnstile Verification: Cloudflare bot detection with 90s caching
The server validates this request (checks CSRF, Turnstile, rate limits) and, if it's valid, sends back a nonce.
Now that the frontend has the valid nonce (the permission slip), it immediately makes the second API call to POST /api/v1/payment/exchange-nonce.
- Purpose: This call's job is to use the permission slip to get the final, valuable item (the fingerprint).
- Payload Sent to Server: This is when the frontend sends all the payment details:
{ "apiKey": "YOUR_PUBLIC_API_KEY", "mode": "0", "paymentAmount": "15000", "merchantUniquePaymentId": "booking-demo-abc-123", "timestamp": "2025-07-06T04:23:38" }
- What the Server Does: The server receives these details, validates the
noncefrom the header, adds its own secretusernameandpassword, and then creates the finalSHA3-512hash (the fingerprint). It then returns just the fingerprint to the client.
In short:
create-nonce= "Am I a legitimate user allowed to ask for a payment?" (Sends security validation info including honeypot).exchange-nonce= "Okay, I am legitimate. Here are the payment details; please create the fingerprint for me."
NEW: All endpoints now include comprehensive debug integration when DEBUG_MODE=true:
Debug Output Example:
🔍 DEBUG SESSION STARTED
Correlation ID: 550e8400-e29b-41d4-a716-446655440000
POST /api/v1/create-nonce
IP: 192.168.1.1
───────────────────────────────────────
Check1: ✅ CORS Origin Check
Check2: ✅ CORS Validation Passed
Check3: ✅ User Agent Security Scan
Check4: ✅ Referer Validation
Check5: ✅ Origin Validation
Check6: ✅ Header Content Security Scan
Check7: ✅ Request Size Validation
Check8: ✅ Rate Limit Validation
Check9: ✅ Honeypot Bot Detection
───────────────────────────────────────
🔒 SECURITY CHECKS SUMMARY
Total checks: 9
Passed: 9 | Failed: 0
Response: 200
Duration: 45ms
🔍 DEBUG SESSION ENDED
Advanced bot detection using emoji injection pattern:
Frontend Implementation:
// Frontend automatically injects honeypot field
const payload = {
tourId: selectedTour,
cfToken: turnstileResponse,
email_verify: "🍯" // Required for human verification
};
Response Types:
- Human User (Valid Honeypot):
{ "nonce": "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4", "expiresAt": "2025-07-06T13:28:40Z" }
- Bot Detected (Invalid Honeypot):
{ "nonce": "fake_1b2c3d4e5f6a1b2c3d4e5f6a1b2c", "expiresAt": "2025-07-06T13:28:40Z" }
Detection Logic:
- Field Missing: Suspicious (sophisticated bot possible) - logs warning but continues
- Wrong Value: Definite bot detected - returns fake nonce to waste bot resources
- Correct Emoji (🍯): Human verified - proceeds with real nonce generation
| Endpoint | Security Checks | Debug Integration | Honeypot Support |
|---|---|---|---|
GET /api/v1/tours | Security-neutral - HSTS/CSP headers only | Session tracking | N/A |
GET /api/v1/tour/{id} | Cookie seeding, headers | Session tracking | N/A |
POST /api/v1/create-nonce | 9+ checks + CSRF + Turnstile | Full debug output | ✅ Emoji validation |
POST /api/v1/payment/exchange-nonce | Nonce validation, atomic consumption | Session tracking | N/A |
POST /api/v1/payment/callback | ValidationCode verification | Session tracking | N/A |
POST /api/v1/admin/generate-pay-token | API key authentication | Session tracking | N/A |
GET /api/v1/booking/{token} | Token validation, cookie seeding | Session tracking | N/A |
# Security Configuration ZENPAY_USERNAME="zenpay_username" ZENPAY_PASSWORD="zenpay_password" TURNSTILE_SECRET_KEY="cloudflare_turnstile_secret" ADMIN_API_KEY="admin_api_key" # Debug Configuration (NEW) DEBUG_MODE=true # Enable comprehensive debug output LOG_LEVEL=INFO # Logging level # Server Configuration PORT=5000 # Server port
- Debug Overhead: Debug code only executes when
DEBUG_MODE=true - Memory Management: Automatic cleanup prevents debug session memory leaks
- Correlation Efficiency: UUID generation optimized for high throughput
- Security Check Optimization: Patterns compiled once, reused across requests