Prompt Details
Model
(claude-4-6-opus)
Token size
1,003
Example input
[APPLICATION_TYPE]: FinTech payment processing platform
[API_STYLE]: REST
[PROJECT_SCALE]: Enterprise
[SECURITY_LEVEL]: Regulatory-compliant (PCI-DSS)
[PRIMARY_CONSUMERS]: Mobile apps + third-party merchant integrations
Example output
I'll create this as a comprehensive document. Let me first check the relevant skill.Now I'll create the comprehensive blueprint as a markdown document.Here's your complete API architecture blueprint. It covers all ten sections tailored to a PCI-DSS-compliant FinTech payment processor at enterprise scale, with concrete endpoint paths, JSON payloads, numeric rate limits, and an implementation sequence showing dependencies. The tokenization-at-the-edge decision and cursor-based pagination are the two choices that most directly shape the rest of the architecture.
# FinTech Payment Processing Platform β API Architecture Blueprint
**Application Type:** FinTech Payment Processing
**API Style:** REST
**Project Scale:** Enterprise
**Security Level:** Regulatory-compliant (PCI-DSS)
**Primary Consumers:** Mobile apps + Third-party merchant integrations
---
## 1. API Design Vision
### Core Goal
Provide a secure, PCI-DSS-compliant payment processing API that enables merchants to accept, manage, and reconcile payments across channels while maintaining sub-second authorization latency and full auditability of every data access.
### Performance Targets
| Metric | Target |
|---|---|
| Authorization latency (p95) | < 350 ms |
| Non-transactional reads (p95) | < 120 ms |
| Throughput (sustained) | 15,000 RPS per region |
| Throughput (burst) | 40,000 RPS for 30 s windows |
| Availability | 99.99 % (β€ 52.6 min downtime/year) |
| Webhook delivery (first attempt) | < 5 s after event |
### Architecture Style Justification
REST is selected over GraphQL for the following reasons:
- **PCI auditing**: Each endpoint maps to a discrete permission, simplifying scope-based access control and audit logging per PCI-DSS Requirement 7 and 10.
- **Cacheability**: GET responses carry standard HTTP caching headers, critical for high-read endpoints like `/merchants` and `/plans`.
- **Merchant adoption**: REST is universally understood; third-party integrators expect standard HTTP verbs and status codes, reducing onboarding friction.
- **Tradeoff accepted**: Clients may over-fetch on some endpoints. This is mitigated with sparse fieldsets (`?fields=id,amount,status`) rather than introducing GraphQL complexity into the Cardholder Data Environment (CDE).
### Governance Standards
- **Naming**: `snake_case` for all JSON fields. Plural nouns for collection URIs.
- **URI pattern**: `/v{major}/{resource}/{id}/{sub-resource}`
- **Payload rules**: All timestamps in ISO 8601 UTC (`2026-04-11T14:30:00Z`). Monetary amounts as integers in the smallest currency unit (cents, pence). Currency as ISO 4217 code. No floating-point currency values anywhere.
- **Idempotency**: All POST endpoints accept an `Idempotency-Key` header (UUID v4). Keys are stored for 48 hours.
---
## 2. Resource Modeling Layer
### Core Resources
#### Payment
| Attribute | Type | Required | Description |
|---|---|---|---|
| `id` | string (UUID) | auto | Unique payment identifier |
| `merchant_id` | string (UUID) | yes | Owning merchant |
| `amount` | integer | yes | Amount in smallest currency unit |
| `currency` | string (ISO 4217) | yes | Three-letter currency code |
| `status` | enum | auto | `pending`, `authorized`, `captured`, `failed`, `cancelled`, `refunded` |
| `payment_method_id` | string (UUID) | yes | Tokenized payment method reference |
| `description` | string | no | Merchant-provided description |
| `metadata` | object | no | Arbitrary key-value pairs (max 50 keys, 500 chars per value) |
| `idempotency_key` | string (UUID) | yes | Client-supplied idempotency key |
| `created_at` | string (ISO 8601) | auto | Creation timestamp |
| `captured_at` | string (ISO 8601) | auto | Capture timestamp |
#### Merchant
| Attribute | Type | Required | Description |
|---|---|---|---|
| `id` | string (UUID) | auto | Unique merchant identifier |
| `business_name` | string | yes | Legal business name |
| `mcc` | string | yes | Merchant Category Code |
| `country` | string (ISO 3166-1) | yes | Country of incorporation |
| `status` | enum | auto | `pending_review`, `active`, `suspended`, `terminated` |
| `settlement_currency` | string (ISO 4217) | yes | Preferred settlement currency |
| `webhook_url` | string (URL) | no | Endpoint for event delivery |
| `created_at` | string (ISO 8601) | auto | Creation timestamp |
#### Payment Method (Tokenized)
| Attribute | Type | Required | Description |
|---|---|---|---|
| `id` | string (UUID) | auto | Token representing the instrument |
| `customer_id` | string (UUID) | yes | Owning customer |
| `type` | enum | yes | `card`, `bank_account`, `wallet` |
| `last_four` | string | auto | Last four digits |
| `exp_month` | integer | conditional | Card expiry month (cards only) |
| `exp_year` | integer | conditional | Card expiry year (cards only) |
| `brand` | string | auto | `visa`, `mastercard`, `amex` |
| `fingerprint` | string | auto | Unique hash for deduplication |
| `created_at` | string (ISO 8601) | auto | Creation timestamp |
> **PCI note**: Raw PAN is never stored or returned. The `payment_methods` resource represents a tokenized reference only. Tokenization occurs at the edge (client SDK or PCI-compliant vault).
#### Refund
| Attribute | Type | Required | Description |
|---|---|---|---|
| `id` | string (UUID) | auto | Unique refund identifier |
| `payment_id` | string (UUID) | yes | Original payment |
| `amount` | integer | yes | Refund amount (partial or full) |
| `reason` | enum | no | `duplicate`, `fraudulent`, `customer_request`, `other` |
| `status` | enum | auto | `pending`, `succeeded`, `failed` |
| `created_at` | string (ISO 8601) | auto | Creation timestamp |
#### Dispute
| Attribute | Type | Required | Description |
|---|---|---|---|
| `id` | string (UUID) | auto | Unique dispute identifier |
| `payment_id` | string (UUID) | auto | Disputed payment |
| `amount` | integer | auto | Disputed amount |
| `reason` | enum | auto | `fraudulent`, `product_not_received`, `unrecognized`, `other` |
| `status` | enum | auto | `needs_response`, `under_review`, `won`, `lost` |
| `evidence_due_by` | string (ISO 8601) | auto | Evidence submission deadline |
| `created_at` | string (ISO 8601) | auto | Creation timestamp |
#### Customer
| Attribute | Type | Required | Description |
|---|---|---|---|
| `id` | string (UUID) | auto | Unique customer identifier |
| `merchant_id` | string (UUID) | yes | Owning merchant |
| `email` | string | no | Customer email |
| `name` | string | no | Customer name |
| `metadata` | object | no | Arbitrary key-value pairs |
| `created_at` | string (ISO 8601) | auto | Creation timestamp |
### Resource Relationships
```
Merchant 1 ββββ * Payment
Merchant 1 ββββ * Customer
Customer 1 ββββ * PaymentMethod
Payment 1 ββββ * Refund
Payment 1 ββββ * Dispute
Payment * ββββ 1 PaymentMethod
```
### URI Structure
| Resource | Example Path |
|---|---|
| Payments | `/v1/payments`, `/v1/payments/{payment_id}` |
| Merchants | `/v1/merchants`, `/v1/merchants/{merchant_id}` |
| Customers | `/v1/customers`, `/v1/customers/{customer_id}` |
| Payment Methods | `/v1/customers/{customer_id}/payment_methods/{pm_id}` |
| Refunds | `/v1/payments/{payment_id}/refunds/{refund_id}` |
| Disputes | `/v1/disputes`, `/v1/disputes/{dispute_id}` |
### HTTP Methods per Endpoint
| Endpoint | GET | POST | PATCH | DELETE |
|---|---|---|---|---|
| `/v1/payments` | List | Create | β | β |
| `/v1/payments/{id}` | Retrieve | β | β | β |
| `/v1/payments/{id}/capture` | β | Capture | β | β |
| `/v1/payments/{id}/cancel` | β | Cancel | β | β |
| `/v1/payments/{id}/refunds` | List | Create | β | β |
| `/v1/merchants` | List | Create | β | β |
| `/v1/merchants/{id}` | Retrieve | β | Update | β |
| `/v1/customers` | List | Create | β | β |
| `/v1/customers/{id}` | Retrieve | β | Update | Delete |
| `/v1/customers/{id}/payment_methods` | List | Create | β | β |
| `/v1/customers/{id}/payment_methods/{id}` | Retrieve | β | β | Detach |
| `/v1/disputes` | List | β | β | β |
| `/v1/disputes/{id}` | Retrieve | β | β | β |
| `/v1/disputes/{id}/evidence` | β | Submit | β | β |
---
## 3. Endpoint Design Layer
### Standard Response Envelope
Every response uses this envelope:
```json
{
"object": "payment",
"id": "pay_8a3b2c1d",
"data": { ... },
"livemode": true,
"created_at": "2026-04-11T14:30:00Z"
}
```
Collection responses:
```json
{
"object": "list",
"data": [ ... ],
"has_more": true,
"next_cursor": "crs_eyJpZCI6InBheV8wMDEifQ",
"total_count": 1482
}
```
### Create Payment β `POST /v1/payments`
**Request:**
```json
{
"amount": 15000,
"currency": "usd",
"payment_method_id": "pm_4f2e8a9b",
"customer_id": "cus_7d1c3e4f",
"capture": false,
"description": "Order #9281",
"metadata": {
"order_id": "9281",
"sku": "WIDGET-PRO"
}
}
```
**Headers:**
```
Authorization: Bearer sk_live_...
Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000
Content-Type: application/json
```
**Response (201 Created):**
```json
{
"object": "payment",
"id": "pay_8a3b2c1d",
"amount": 15000,
"currency": "usd",
"status": "authorized",
"payment_method_id": "pm_4f2e8a9b",
"customer_id": "cus_7d1c3e4f",
"capture": false,
"description": "Order #9281",
"metadata": { "order_id": "9281", "sku": "WIDGET-PRO" },
"livemode": true,
"created_at": "2026-04-11T14:30:00Z"
}
```
### Capture Payment β `POST /v1/payments/{id}/capture`
**Request:**
```json
{
"amount": 12000
}
```
`amount` is optional; omit to capture full authorized amount. Partial capture is supported once.
**Response (200 OK):**
```json
{
"object": "payment",
"id": "pay_8a3b2c1d",
"amount": 15000,
"amount_captured": 12000,
"status": "captured",
"captured_at": "2026-04-11T14:35:12Z",
"..."
}
```
### Create Refund β `POST /v1/payments/{id}/refunds`
**Request:**
```json
{
"amount": 5000,
"reason": "customer_request"
}
```
**Response (201 Created):**
```json
{
"object": "refund",
"id": "ref_2b4c6d8e",
"payment_id": "pay_8a3b2c1d",
"amount": 5000,
"status": "pending",
"reason": "customer_request",
"created_at": "2026-04-11T15:00:00Z"
}
```
### Pagination β Cursor-based
Cursor pagination is used over offset because:
- Payment tables grow to billions of rows; offset scans become O(n).
- Cursor guarantees consistency when new payments arrive during traversal.
**Request:** `GET /v1/payments?limit=25&starting_after=crs_eyJpZCI6InBheV8wMDEifQ`
**Parameters:**
| Param | Type | Default | Max |
|---|---|---|---|
| `limit` | integer | 25 | 100 |
| `starting_after` | string | β | Opaque cursor |
| `ending_before` | string | β | Opaque cursor (reverse) |
| `created_gte` | ISO 8601 | β | Filter |
| `created_lte` | ISO 8601 | β | Filter |
| `status` | enum | β | Filter |
### Filtering and Sorting
```
GET /v1/payments?status=captured¤cy=usd&created_gte=2026-04-01T00:00:00Z&sort=-created_at
```
Sort parameter: prefix `-` for descending. Allowed sort fields: `created_at`, `amount`.
### Sparse Fieldsets
```
GET /v1/payments/pay_8a3b2c1d?fields=id,amount,status,created_at
```
### Bulk Endpoint β Batch Payment Creation
`POST /v1/payments/batch`
```json
{
"payments": [
{ "amount": 5000, "currency": "usd", "payment_method_id": "pm_a1", "idempotency_key": "..." },
{ "amount": 8000, "currency": "eur", "payment_method_id": "pm_b2", "idempotency_key": "..." }
]
}
```
- Maximum 100 items per batch.
- Maximum payload size: 1 MB.
- Returns `207 Multi-Status` with per-item results.
- Each item is independently idempotent.
### Webhook Events
`POST` to the merchant's registered `webhook_url`.
**Payload:**
```json
{
"id": "evt_9f8e7d6c",
"object": "event",
"type": "payment.captured",
"created_at": "2026-04-11T14:35:12Z",
"data": {
"object": { "...payment object..." }
},
"api_version": "2026-04-01"
}
```
**Event types:** `payment.authorized`, `payment.captured`, `payment.failed`, `payment.cancelled`, `refund.created`, `refund.succeeded`, `refund.failed`, `dispute.created`, `dispute.updated`, `dispute.closed`.
**Retry policy:**
| Attempt | Delay |
|---|---|
| 1 | Immediate |
| 2 | 5 minutes |
| 3 | 30 minutes |
| 4 | 2 hours |
| 5 | 24 hours |
Delivery is considered failed after 5 attempts or a non-2xx response. Merchants can replay events via `POST /v1/events/{id}/retry`.
**Webhook Signature:**
```
Paymint-Signature: t=1712844912,v1=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bd
```
HMAC-SHA256 of `{timestamp}.{raw_body}` using the merchant's webhook signing secret.
---
## 4. Authentication & Authorization
### Authentication Method β OAuth 2.0 + API Keys
PCI-DSS Requirement 8 mandates unique identification and strong authentication. The platform uses a dual scheme:
- **Server-to-server (merchant backends):** Secret API keys (`sk_live_...`, `sk_test_...`), transmitted via `Authorization: Bearer` header over TLS 1.2+.
- **Client-side (mobile SDKs):** Publishable keys (`pk_live_...`) restricted to tokenization endpoints only. These keys cannot initiate payments.
- **Partner/platform integrations:** OAuth 2.0 Authorization Code flow with PKCE, issuing scoped access tokens.
### Implementation Steps
1. Merchant generates API key pair in the dashboard. Secret keys are hashed (Argon2id) before storage; only the prefix `sk_live_...1a2b` is stored in cleartext for identification.
2. Every request includes `Authorization: Bearer sk_live_...`.
3. The API gateway validates the key, resolves the `merchant_id`, and attaches it to the request context.
4. For OAuth partners: standard `/oauth/authorize` β `/oauth/token` flow. Tokens are JWTs signed with RS256, audience-restricted to the payments API.
### Authorization Model β Scope Matrix
| Scope | Payments | Refunds | Disputes | Customers | Payment Methods | Merchants |
|---|---|---|---|---|---|---|
| `payments:read` | R | β | β | β | β | β |
| `payments:write` | RW | β | β | β | β | β |
| `refunds:write` | β | RW | β | β | β | β |
| `disputes:read` | β | β | R | β | β | β |
| `disputes:write` | β | β | RW | β | β | β |
| `customers:read` | β | β | β | R | R | β |
| `customers:write` | β | β | β | RW | RW | β |
| `merchant:admin` | RW | RW | RW | RW | RW | RW |
All API keys are bound to a `merchant_id`. A key can only access its own merchant's resources. Platform-level keys (for the payment platform operator) use a separate `platform:admin` scope.
### Token Lifecycle
| Parameter | Value |
|---|---|
| Access token TTL | 30 minutes |
| Refresh token TTL | 90 days |
| Refresh token rotation | Enabled (old token revoked on use) |
| API key expiration | None (manually revoked) |
| Revocation endpoint | `POST /v1/oauth/revoke` |
| Token storage | Redis cluster with encryption at rest |
---
## 5. Versioning & Evolution Strategy
### Approach β Date-based Versioning in Header
```
Paymint-Version: 2026-04-01
```
**Justification:** Date-based versions (like Stripe's model) allow the platform to ship changes continuously. Each merchant is pinned to their onboarding API version. They upgrade explicitly. URI path versioning (`/v1/`) is used only for major breaking changes (rare, planned on multi-year cycles).
**Example URIs:**
- Current: `GET /v1/payments/pay_8a3b2c1d` with header `Paymint-Version: 2026-04-01`
- Legacy: Same URI, header `Paymint-Version: 2025-09-15`
### Deprecation Timeline
1. **Announcement**: 12 months before sunset. Deprecation notice in API response headers.
2. **Sunset header**: `Sunset: Sat, 01 Apr 2027 00:00:00 GMT` on all responses using deprecated version.
3. **Dashboard warning**: Active alerts for merchants on deprecated versions.
4. **Brownout**: 2 months before sunset, 1-hour brownouts on deprecated version (return `410 Gone`) to encourage migration.
5. **Removal**: Version returns `410 Gone` permanently.
### Backward Compatibility Contract
- Additive changes (new fields, new endpoints, new enum values) are non-breaking.
- Removing fields, renaming fields, changing types, or altering default behavior requires a new version.
- Webhooks include `api_version` so merchants can parse payloads according to their pinned version.
---
## 6. Error Handling & Validation
### Error Response Format
```json
{
"error": {
"type": "invalid_request_error",
"code": "amount_too_small",
"message": "The payment amount must be at least 50 cents.",
"param": "amount",
"doc_url": "https://docs.paymint.com/errors/amount_too_small",
"request_id": "req_7f8e9d0c1b2a"
}
}
```
### Error Types
| Type | Description |
|---|---|
| `invalid_request_error` | Malformed request, missing/invalid params |
| `authentication_error` | Invalid or missing API key |
| `authorization_error` | Valid key but insufficient scope |
| `card_error` | Issuer declined the transaction |
| `idempotency_error` | Idempotency key reused with different params |
| `rate_limit_error` | Too many requests |
| `api_error` | Internal server error |
### HTTP Status Code Map
| Status | Scenario |
|---|---|
| 200 | Success (update, action) |
| 201 | Resource created |
| 207 | Batch: mixed results |
| 400 | Validation failure |
| 401 | Missing or invalid authentication |
| 403 | Insufficient scope / forbidden |
| 404 | Resource not found |
| 409 | Idempotency conflict |
| 422 | Semantically invalid (e.g., refund > captured amount) |
| 429 | Rate limited |
| 500 | Internal error |
| 503 | Service temporarily unavailable |
### Input Validation β Example Rejected Payloads
**Missing required field:**
```json
// Request
{ "currency": "usd", "payment_method_id": "pm_4f2e8a9b" }
// Response (400)
{
"error": {
"type": "invalid_request_error",
"code": "parameter_missing",
"message": "Required parameter 'amount' is missing.",
"param": "amount"
}
}
```
**Invalid currency:**
```json
// Request
{ "amount": 5000, "currency": "xxx", "payment_method_id": "pm_4f2e8a9b" }
// Response (400)
{
"error": {
"type": "invalid_request_error",
"code": "invalid_currency",
"message": "'xxx' is not a supported currency. See docs for supported currencies.",
"param": "currency"
}
}
```
**Semantic error β refund exceeds capture:**
```json
// POST /v1/payments/pay_8a3b2c1d/refunds
{ "amount": 99999 }
// Response (422)
{
"error": {
"type": "invalid_request_error",
"code": "refund_exceeds_capture",
"message": "Refund amount (99999) exceeds the captured amount (12000).",
"param": "amount"
}
}
```
### Retry-After Guidance
When a 429 response is returned:
```
HTTP/1.1 429 Too Many Requests
Retry-After: 2
X-RateLimit-Reset: 1712845200
```
Clients should implement exponential backoff with jitter in addition to honoring `Retry-After`.
---
## 7. Rate Limiting & Throttling
### Rate Limit Tiers
| Consumer Type | Requests/sec | Requests/min | Daily Quota | Burst (10s window) |
|---|---|---|---|---|
| Production merchant (live key) | 100 | 4,000 | 1,000,000 | 500 |
| Test/sandbox (test key) | 25 | 1,000 | 100,000 | 100 |
| OAuth partner (per-merchant) | 50 | 2,000 | 500,000 | 250 |
| Mobile SDK (publishable key) | 10 | 200 | 50,000 | 30 |
| Platform admin | 200 | 8,000 | Unlimited | 1,000 |
Enterprise merchants may negotiate higher limits.
### Algorithm β Token Bucket with Sliding Window
Token bucket is used because:
- Allows controlled bursts (critical during checkout spikes).
- Simple to implement in Redis with atomic Lua scripts.
- Sliding window counter as secondary check prevents sustained abuse at bucket boundaries.
### Overage Behavior
1. Return `429 Too Many Requests` with `Retry-After` header.
2. Continue counting requests against the window (no penalty accumulation).
3. If a client sustains 10x their limit for > 60 seconds, temporarily block the key for 5 minutes and alert the merchant dashboard.
4. Persistent abuse triggers a manual review and possible key suspension.
### Rate Limit Response Headers
```
HTTP/1.1 200 OK
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 73
X-RateLimit-Reset: 1712845200
X-RateLimit-Policy: 100;w=1
```
---
## 8. Caching & Performance Optimization
### Caching Layers
| Layer | Resource | TTL | Strategy |
|---|---|---|---|
| CDN (Cloudflare / AWS CloudFront) | OpenAPI spec, SDK assets | 24 h | `Cache-Control: public, max-age=86400` |
| API Gateway (in-memory) | Merchant config, MCC data | 5 min | `private, max-age=300` |
| Application (Redis) | Payment status (read-after-write) | 30 s | Write-through |
| Application (Redis) | Customer records | 2 min | Cache-aside |
| Never cached | Payment creation/capture, refunds, tokenization | β | `Cache-Control: no-store` |
**PCI constraint:** Responses containing PAN fragments, CVV, or authentication data are never cached at any layer. Payment method responses (tokenized) use `no-store` at the CDN level.
### ETag-based Invalidation
```
GET /v1/merchants/mch_123
β ETag: "a1b2c3d4"
GET /v1/merchants/mch_123
If-None-Match: "a1b2c3d4"
β 304 Not Modified
```
ETags are computed as SHA-256 of the serialized resource + `updated_at` timestamp.
### Response Compression
- `gzip` and `br` (Brotli) supported. Brotli preferred for mobile clients (15-20% smaller than gzip).
- `Accept-Encoding: br, gzip` negotiation at the gateway.
- Minimum response size for compression: 1 KB.
### Query Optimization Patterns
- **Payment lookups:** Composite index on `(merchant_id, created_at DESC)` for list queries with date filtering. Covering index on `(merchant_id, status)` for status filtering.
- **Idempotency checks:** Hash index on `(merchant_id, idempotency_key)` with 48-hour TTL in Redis for fast duplicate detection before hitting the database.
- **Read replicas:** All GET endpoints route to read replicas. POST/PATCH route to the primary. Payment status reads within 2 seconds of a write route to the primary (read-your-writes consistency).
- **Connection pooling:** PgBouncer in transaction mode, 200 connections per application pod.
---
## 9. Security Hardening
### Input Sanitization Checklist
- Reject payloads > 256 KB (batch endpoints: 1 MB).
- Validate Content-Type is exactly `application/json`.
- Parse JSON strictly: no duplicate keys, no comments, no trailing commas.
- String fields: enforce maximum lengths per schema. Reject null bytes, control characters.
- `metadata` keys: alphanumeric + underscore only, max 40 characters. Values: max 500 characters, HTML-escaped on output.
- Amount fields: integer only, must be β₯ 50 (minimum charge) and β€ 99999999 (maximum charge).
- Reject unknown top-level fields (strict schema validation).
- URL fields (e.g., `webhook_url`): must be HTTPS, validated against SSRF (no private IPs, no localhost).
### CORS Policy
```
Access-Control-Allow-Origin: https://merchant-dashboard.paymint.com
Access-Control-Allow-Methods: GET, POST, PATCH, DELETE, OPTIONS
Access-Control-Allow-Headers: Authorization, Content-Type, Idempotency-Key, Paymint-Version
Access-Control-Max-Age: 7200
Access-Control-Expose-Headers: X-Request-Id, X-RateLimit-Limit, X-RateLimit-Remaining
```
- The API itself does not serve browser-originated requests from arbitrary origins. CORS is restricted to the merchant dashboard SPA.
- Mobile SDKs and merchant backends communicate server-to-server; CORS is irrelevant.
- Publishable-key tokenization endpoint allows `*.paymint.com` origins only.
### Encryption
| Context | Standard |
|---|---|
| In transit | TLS 1.2+ mandatory. TLS 1.3 preferred. HSTS with `max-age=31536000; includeSubDomains; preload`. |
| At rest (database) | AES-256-GCM with AWS KMS-managed keys. Per-merchant envelope encryption for PAN vault. |
| At rest (logs) | PAN/CVV never logged. Sensitive fields masked in all log sinks. |
| Key management | HSM-backed (AWS CloudHSM or equivalent) per PCI-DSS Requirement 3.5. Key rotation every 12 months. |
### Audit Logging Schema
Every API request produces an immutable audit log entry per PCI-DSS Requirement 10.
```json
{
"timestamp": "2026-04-11T14:30:00.123Z",
"request_id": "req_7f8e9d0c1b2a",
"merchant_id": "mch_3a4b5c6d",
"api_key_prefix": "sk_live_...1a2b",
"method": "POST",
"path": "/v1/payments",
"status_code": 201,
"ip_address": "203.0.113.42",
"user_agent": "MerchantApp/2.1.0",
"latency_ms": 287,
"resource_id": "pay_8a3b2c1d",
"scopes_used": ["payments:write"],
"idempotency_key": "550e8400-...",
"risk_signals": {
"ip_country": "US",
"velocity_flag": false
}
}
```
Logs are shipped to an append-only store (e.g., S3 with Object Lock) with 7-year retention per PCI-DSS Requirement 10.7.
### Compliance Requirements (PCI-DSS Mapped)
| PCI Requirement | Implementation |
|---|---|
| Req 1 β Network segmentation | CDE isolated in separate VPC. API gateway in DMZ. No direct database access from public internet. |
| Req 2 β Secure defaults | No default credentials. All services hardened per CIS benchmarks. |
| Req 3 β Protect stored data | PAN tokenized immediately. Encrypted at rest with KMS. No CVV stored post-authorization. |
| Req 4 β Encrypt transmission | TLS 1.2+ enforced. Certificate pinning in mobile SDKs. |
| Req 6 β Secure development | SAST/DAST in CI/CD. Dependency scanning. Quarterly penetration testing. |
| Req 7 β Restrict access | Scope-based authorization. Principle of least privilege. |
| Req 8 β Identify users | Unique API keys per merchant. OAuth tokens per partner. MFA on dashboard. |
| Req 10 β Track access | Immutable audit logs for all CDE access. SIEM alerting. |
| Req 11 β Test security | ASV scans quarterly. Annual PCI audit. Bug bounty program. |
| Req 12 β Security policy | Incident response plan. Employee security training. Vendor risk management. |
---
## 10. Monitoring, Documentation & API Health
### Monitoring Stack
| Layer | Tool | Purpose |
|---|---|---|
| Metrics | Datadog | Latency percentiles, error rates, throughput per endpoint, per merchant |
| Logging | Datadog Logs / ELK | Structured JSON logs from all services, correlated by `request_id` |
| Tracing | Datadog APM / Jaeger | Distributed traces across gateway β service β database β card network |
| Alerting | PagerDuty + Datadog Monitors | P95 latency > 500ms, error rate > 1%, payment success rate < 95% |
| Uptime | Synthetic checks (Datadog Synthetics) | Probe `/health` and `/v1/payments` every 30s from 5 regions |
| Fraud / anomaly | Custom ML pipeline + Datadog Anomaly Detection | Unusual spike in declines, velocity anomalies per merchant |
### Health Check Endpoints
**Liveness β `GET /healthz`**
Returns `200 OK` if the process is running. No dependency checks.
```json
{ "status": "ok" }
```
**Readiness β `GET /readyz`**
Returns `200 OK` only if all critical dependencies are reachable.
```json
{
"status": "ready",
"checks": {
"database": "ok",
"redis": "ok",
"card_network_gateway": "ok",
"vault": "ok"
}
}
```
Returns `503` if any check fails.
### OpenAPI 3.x Specification Outline
```yaml
openapi: 3.1.0
info:
title: Paymint Payment Processing API
version: "2026-04-01"
description: PCI-DSS compliant payment processing.
servers:
- url: https://api.paymint.com/v1
description: Production
- url: https://sandbox.paymint.com/v1
description: Sandbox
security:
- BearerAuth: []
paths:
/payments:
get:
summary: List payments
parameters:
- $ref: '#/components/parameters/Limit'
- $ref: '#/components/parameters/StartingAfter'
- $ref: '#/components/parameters/StatusFilter'
responses:
'200':
$ref: '#/components/responses/PaymentList'
post:
summary: Create a payment
requestBody:
$ref: '#/components/requestBodies/CreatePayment'
responses:
'201':
$ref: '#/components/responses/Payment'
/payments/{id}:
get:
summary: Retrieve a payment
/payments/{id}/capture:
post:
summary: Capture an authorized payment
/payments/{id}/refunds:
get:
summary: List refunds for a payment
post:
summary: Create a refund
components:
securitySchemes:
BearerAuth:
type: http
scheme: bearer
schemas:
Payment:
type: object
properties:
id: { type: string }
amount: { type: integer }
currency: { type: string }
status: { type: string, enum: [pending, authorized, captured, failed, cancelled, refunded] }
```
Full specification maintained in a version-controlled `openapi.yaml`, auto-published to the developer portal on every merge to `main`.
### Developer Onboarding
**Sandbox:** Fully functional sandbox at `sandbox.paymint.com` using test keys (`sk_test_...`). Simulated card numbers (e.g., `4242424242424242` for success, `4000000000000002` for decline). No real card network calls.
**SDK stubs:** Official SDKs in Python, Node.js, Ruby, Go, Java, and Swift/Kotlin for mobile. Each SDK wraps authentication, idempotency key injection, automatic retries with backoff, and webhook signature verification.
**Quickstart guide:**
1. Create a sandbox account β receive `sk_test_...` and `pk_test_...`.
2. Tokenize a test card via the client SDK with the publishable key.
3. Create a payment server-side: `POST /v1/payments` with the token.
4. Capture the payment: `POST /v1/payments/{id}/capture`.
5. Register a webhook URL and verify signature.
6. When ready, request production access (KYC review, PCI SAQ-A or AOC submission).
---
## Final Summary
### Most Critical Design Decision
**Tokenization at the edge.** Raw card numbers never reach the API; they are tokenized in the client SDK or a PCI-compliant vault before the merchant's server sees them. This decision reduces the merchant's PCI scope from SAQ-D to SAQ-A, which is the single biggest factor in merchant adoption and platform liability reduction.
### Biggest Architectural Risk & Mitigation
**Card network latency variability.** Authorization calls to Visa/Mastercard networks can spike to 2-5 seconds under load or during network incidents, blowing through the 350ms p95 target. Mitigation: circuit breaker per network with a 3-second timeout, fallback to queued authorization with merchant notification, and pre-authorized hold patterns for repeat customers.
### Top Optimization Priority
**Idempotency check performance.** Every payment creation hits the idempotency store before proceeding. At 15,000 RPS, this is the hottest path. Redis Cluster with hash-slot-local Lua scripts keeps this at < 1ms. If Redis fails, the system falls back to a database unique constraint (slower but correct).
### Implementation Sequence
```
Phase 1 (Foundation):
Β§4 Auth & Authorization β Β§9 Security Hardening β Β§2 Resource Modeling
Phase 2 (Core API):
Β§3 Endpoint Design β Β§6 Error Handling β Β§5 Versioning
Phase 3 (Resilience):
Β§7 Rate Limiting β Β§8 Caching
Phase 4 (Operations):
Β§10 Monitoring & Documentation β Sandbox launch β SDK release
Dependencies:
Β§4 blocks everything (no API without auth).
Β§9 runs in parallel with Β§2 (infrastructure + schema simultaneously).
Β§3 depends on Β§2 (endpoints need resources defined).
Β§7 depends on Β§4 (rate limits are per API key tier).
Β§8 depends on Β§3 (cache what's been built).
Β§10 runs continuously but formal launch after Β§8.
```
By purchasing this prompt, you agree to our terms of service
CLAUDE-4-6-OPUS
π Stop guessing your API architecture β get it right the first time!
This blueprint gives you the clarity and confidence to build APIs that scale, stay secure, and delight developers.
βͺοΈ Save weeks of planning and design decisions
βͺοΈ Avoid costly architectural mistakes
βͺοΈ Ship with a clear, actionable roadmap
βͺοΈ Impress stakeholders with professional documentation
From your first MVP to enterprise-grade systems β one prompt, one complete plan.
π Instructions and tips included.
...more
Added 3 weeks ago
