⚔ AI Battle

ChatGPT vs Claude: Write API Documentation for a Payment Processing Endpoint

The Prompt
Write comprehensive API documentation for a POST /payments/charge endpoint. The endpoint accepts a JSON body with amount (integer, cents), currency (ISO 4217), customer_id (UUID), payment_method_id (UUID), idempotency_key (string), and optional metadata (object). It returns a charge object with id, status (pending/succeeded/failed), amount, currency, created_at, and failure_reason (nullable). Include authentication, rate limits, error codes, a request example, a response example, and a webhook event description for charge.succeeded and charge.failed.
GPT-4o GPT-4o
# POST /payments/charge ## Overview The `/payments/charge` endpoint allows you to create a new payment charge against a customer's stored payment method. This endpoint processes the payment and returns a charge object representing the transaction. ## Authentication All API requests must include your API key in the `Authorization` header: ``` Authorization: Bearer sk_live_your_api_key_here ``` ## Rate Limits - **Live mode:** 100 requests per second - **Test mode:** 50 requests per second Exceeding these limits will result in a `429 Too Many Requests` response. ## Request ### Headers | Header | Required | Description | |--------|----------|-------------| | `Authorization` | Yes | Bearer token with your API key | | `Content-Type` | Yes | Must be `application/json` | | `Idempotency-Key` | Recommended | Unique key to prevent duplicate charges | ### Body Parameters | Parameter | Type | Required | Description | |-----------|------|----------|-------------| | `amount` | integer | Yes | The charge amount in the smallest currency unit (e.g., cents for USD). Must be a positive integer. | | `currency` | string | Yes | Three-letter ISO 4217 currency code (e.g., `usd`, `eur`). | | `customer_id` | string (UUID) | Yes | The unique identifier of the customer being charged. | | `payment_method_id` | string (UUID) | Yes | The unique identifier of the payment method to charge. | | `idempotency_key` | string | Yes | A unique string to ensure idempotent processing of the request. | | `metadata` | object | No | A set of key-value pairs for storing additional information about the charge. | ### Example Request ```bash curl -X POST https://api.example.com/v1/payments/charge \ -H "Authorization: Bearer sk_live_your_api_key_here" \ -H "Content-Type: application/json" \ -d '{ "amount": 2500, "currency": "usd", "customer_id": "cus_a1b2c3d4-e5f6-7890-abcd-ef1234567890", "payment_method_id": "pm_12345678-abcd-efgh-ijkl-9876543210ab", "idempotency_key": "charge_abc123_20240115", "metadata": { "order_id": "ORD-2024-001", "description": "Pro Plan - Monthly Subscription" } }' ``` ## Response ### Success Response (200 OK) ```json { "id": "ch_1234567890abcdef", "object": "charge", "status": "succeeded", "amount": 2500, "currency": "usd", "customer_id": "cus_a1b2c3d4-e5f6-7890-abcd-ef1234567890", "payment_method_id": "pm_12345678-abcd-efgh-ijkl-9876543210ab", "created_at": "2024-01-15T10:30:00Z", "failure_reason": null, "metadata": { "order_id": "ORD-2024-001", "description": "Pro Plan - Monthly Subscription" } } ``` ### Error Responses | Status Code | Error Code | Description | |-------------|------------|-------------| | `400` | `invalid_amount` | The amount must be a positive integer. | | `400` | `invalid_currency` | The currency code is not a valid ISO 4217 code. | | `401` | `unauthorized` | Invalid or missing API key. | | `402` | `card_declined` | The payment method was declined. | | `404` | `customer_not_found` | No customer found with the provided ID. | | `404` | `payment_method_not_found` | No payment method found with the provided ID. | | `409` | `duplicate_idempotency_key` | A request with this idempotency key has already been processed. | | `429` | `rate_limit_exceeded` | Too many requests. Please retry after the time indicated in the `Retry-After` header. | ## Webhooks ### charge.succeeded Sent when a charge is successfully processed. ```json { "event": "charge.succeeded", "data": { "id": "ch_1234567890abcdef", "status": "succeeded", "amount": 2500, "currency": "usd", "customer_id": "cus_a1b2c3d4-e5f6-7890-abcd-ef1234567890", "created_at": "2024-01-15T10:30:00Z" } } ``` ### charge.failed Sent when a charge attempt fails. ```json { "event": "charge.failed", "data": { "id": "ch_1234567890abcdef", "status": "failed", "amount": 2500, "currency": "usd", "customer_id": "cus_a1b2c3d4-e5f6-7890-abcd-ef1234567890", "created_at": "2024-01-15T10:30:00Z", "failure_reason": "insufficient_funds" } } ``` ## Notes - Charges are processed asynchronously. A `pending` status indicates the charge is still being processed. - Use the `idempotency_key` to safely retry failed requests without creating duplicate charges. - Metadata keys and values must be strings. Maximum 20 key-value pairs per charge. - All amounts are in the smallest currency unit to avoid floating-point issues.
Claude Opus 4.6 GPT-4o
# POST /payments/charge Create a charge against a customer's stored payment method. **Base URL:** `https://api.example.com/v1` --- ## Authentication Include your API key as a Bearer token. Use `sk_test_` keys in test mode and `sk_live_` keys in production — test keys never hit real payment networks. ``` Authorization: Bearer sk_live_4eC39HqLyjWDarjtT1zdp7dc ``` ## Rate limits | Environment | Limit | Burst | |---|---|---| | Live | 100 req/s | 150 req/s for 10s | | Test | 25 req/s | 50 req/s for 10s | When rate-limited, the response includes a `Retry-After` header (seconds). Back off accordingly — do not retry in a tight loop. --- ## Request ```http POST /v1/payments/charge Content-Type: application/json Authorization: Bearer sk_live_4eC39HqLyjWDarjtT1zdp7dc ``` ### Parameters | Field | Type | Required | Description | |---|---|---|---| | `amount` | `integer` | ✓ | Amount in smallest currency unit (e.g., `2500` = $25.00 USD). Must be ≥ 50. | | `currency` | `string` | ✓ | Lowercase [ISO 4217](https://en.wikipedia.org/wiki/ISO_4217) code. We support 135 currencies — see [supported currencies](/docs/currencies). | | `customer_id` | `string<uuid>` | ✓ | The customer to charge. Must have at least one verified payment method. | | `payment_method_id` | `string<uuid>` | ✓ | Must belong to the specified customer. | | `idempotency_key` | `string` | ✓ | Unique per-request key (max 255 chars). We store keys for 24 hours — retries within that window return the original response without reprocessing. | | `metadata` | `object` | — | Up to 20 key-value pairs. Keys max 40 chars, values max 500 chars. Not used in processing — purely for your records. | > **⚠️ Amount is in cents, not dollars.** Passing `25` charges $0.25, not $25.00. This is the most common integration mistake. ### Example ```bash curl -X POST https://api.example.com/v1/payments/charge \ -H "Authorization: Bearer sk_live_4eC39HqLyjWDarjtT1zdp7dc" \ -H "Content-Type: application/json" \ -d '{ "amount": 2500, "currency": "usd", "customer_id": "f47ac10b-58cc-4372-a567-0e02b2c3d479", "payment_method_id": "7c9e6679-7425-40de-944b-e07fc1f90ae7", "idempotency_key": "ord_8v3kQ9_charge_1", "metadata": { "order_id": "ord_8v3kQ9", "line_items": "3" } }' ``` --- ## Response ### Charge object | Field | Type | Description | |---|---|---| | `id` | `string` | Unique charge identifier. Starts with `ch_`. | | `status` | `string` | One of: `pending`, `succeeded`, `failed`. | | `amount` | `integer` | Confirmed amount in smallest currency unit. | | `currency` | `string` | ISO 4217 currency code. | | `created_at` | `string<datetime>` | ISO 8601 timestamp. | | `failure_reason` | `string\|null` | `null` unless `status` is `failed`. See [failure codes](#failure-codes). | | `metadata` | `object` | The metadata you sent. | ### 200 — Charge created ```json { "id": "ch_2kF8xLmN4qRs", "status": "pending", "amount": 2500, "currency": "usd", "created_at": "2026-06-09T14:22:08Z", "failure_reason": null, "metadata": { "order_id": "ord_8v3kQ9", "line_items": "3" } } ``` Note: A `200` with `status: "pending"` means the charge was accepted, not completed. Listen for webhooks to confirm the outcome. ### Error codes | HTTP | Code | What went wrong | |---|---|---| | 400 | `invalid_amount` | Amount is missing, negative, or below the 50-cent minimum. | | 400 | `invalid_currency` | Not a recognized ISO 4217 code. | | 400 | `payment_method_mismatch` | The payment method doesn't belong to this customer. | | 401 | `authentication_failed` | API key is missing, expired, or invalid. | | 402 | `card_declined` | Issuer declined. Check `failure_reason` for specifics: `insufficient_funds`, `lost_card`, `expired_card`, etc. | | 404 | `customer_not_found` | No customer with this ID. | | 404 | `payment_method_not_found` | No payment method with this ID. | | 409 | `idempotency_conflict` | Same key was used with different parameters. | | 422 | `currency_not_supported` | We don't support this currency for the customer's payment method type. | | 429 | `rate_limited` | Back off per `Retry-After` header. | | 500 | `processing_error` | Something broke on our end. Safe to retry with the same idempotency key. | --- ## Webhooks We send webhook events when a charge reaches a terminal state. Both events use the same payload shape. ### `charge.succeeded` ```json { "id": "evt_9xK3mPq", "type": "charge.succeeded", "created_at": "2026-06-09T14:22:11Z", "data": { "id": "ch_2kF8xLmN4qRs", "status": "succeeded", "amount": 2500, "currency": "usd", "customer_id": "f47ac10b-58cc-4372-a567-0e02b2c3d479", "payment_method_id": "7c9e6679-7425-40de-944b-e07fc1f90ae7", "created_at": "2026-06-09T14:22:08Z", "failure_reason": null } } ``` ### `charge.failed` ```json { "id": "evt_4nB7rWx", "type": "charge.failed", "created_at": "2026-06-09T14:22:14Z", "data": { "id": "ch_2kF8xLmN4qRs", "status": "failed", "amount": 2500, "currency": "usd", "customer_id": "f47ac10b-58cc-4372-a567-0e02b2c3d479", "payment_method_id": "7c9e6679-7425-40de-944b-e07fc1f90ae7", "created_at": "2026-06-09T14:22:08Z", "failure_reason": "insufficient_funds" } } ``` ### Webhook best practices 1. **Verify signatures.** Every webhook includes an `X-Signature-256` header. Validate it before processing — see [webhook security](/docs/webhooks/security). 2. **Respond with 2xx quickly.** We time out after 10 seconds and retry up to 5 times with exponential backoff. 3. **Handle duplicates.** Use `evt_` IDs to deduplicate. We guarantee at-least-once delivery, not exactly-once. 4. **Don't trust webhooks alone for critical flows.** Always reconcile with a GET /payments/charges/{id} call if money movement depends on it.
🔍 Analysis
Claude's API documentation is meaningfully better in three ways that matter to developers actually integrating this endpoint: 1. Practical warnings that prevent real bugs. Claude includes a callout box warning that amount is in cents, not dollars — "the most common integration mistake." GPT mentions the smallest currency unit in the parameter description but doesn't flag it as a gotcha. Any payment API developer will tell you this one warning box saves more support tickets than the entire rest of the page. 2. More complete error handling. Claude documents 11 error codes including `payment_method_mismatch` (payment method doesn't belong to this customer), `currency_not_supported`, `idempotency_conflict` (same key, different params — distinct from duplicate), and `processing_error` with retry guidance. GPT covers 8 codes and misses edge cases that developers will actually hit in production. 3. Better webhook documentation. Claude includes webhook best practices (signature verification, timeout handling, deduplication, reconciliation). GPT provides the payload structure but none of the integration guidance that prevents webhook-related bugs. Claude's note about not trusting webhooks alone for critical money flows is the kind of advice that prevents real production incidents. Where GPT holds its own: GPT's documentation is clean, well-organized, and covers all the basics correctly. The table formatting is solid, the examples work, and a developer could successfully integrate from GPT's docs alone. It's competent API documentation — it just reads like it was written by someone who documented the endpoint without having debugged integrations against it. Claude's docs read like they were written by someone who's seen the support tickets.

Run your own battle

Compare GPT-4o, Claude Opus 4.6 and more AI models side-by-side with any prompt — free.

Try NailedIt.ai →