API Integration Guide
Use this guide when you want to integrate the Paychtec APIs directly from your application backend.
Working with an LLM agent? Ask it to read this file first, then implement the backend API calls, payloads, webhook verification, retries, and order-state updates according to this guide.
Related integration guides:
- API integration guide:
https://docs.v2.paychtec.com/docs/INTEGRATION_API - SDK integration guide:
https://docs.v2.paychtec.com/docs/INTEGRATION_SDK
LLM Agent Prompt
Read the API integration guide at https://docs.v2.paychtec.com/docs/INTEGRATION_API and, if the checkout uses the JavaScript SDK, also read https://docs.v2.paychtec.com/docs/INTEGRATION_SDK. Build a merchant API integration only. Keep secret keys on the server, use the sandbox API first, send the payloads documented in the Payload Reference section, use order_details for order contents, do not invent customer_id values for POST /payments, add idempotency keys for retryable mutations, verify webhook signatures, and update order state from webhooks.
Scope
This guide is for merchants integrating payments into their own application.
Use merchant resources:
- Secret API keys for server-side API calls.
profile_idfor the merchant business profile used on payments.customer_id,payment_id,refund_id, and similar IDs for merchant-owned records.- Webhooks for final payment, refund, dispute, payout, and subscription state.
Environments
Use sandbox while building and testing:
https://api.sandbox.paychtec.com
Use production only after your integration has passed testing:
https://api.v2.paychtec.com
Sandbox keys usually start with snd_; production keys usually start with prd_. Never use production credentials for tests unless you intend to create real transactions.
Required Headers
Content-Type: application/json
api-key: snd_YOUR_API_KEYFor retryable POST, PUT, or DELETE requests, include a stable idempotency key:
X-Idempotency-Key: order_123_attempt_1Use the same idempotency key when retrying the same logical operation. Do not generate a new key for each retry.
Recommended Build Order
-
Create a server-side API client. Store the secret API key in server environment variables and centralize request headers, base URL selection, timeout handling, and response parsing.
-
Create or retrieve a customer. Use customers when you need saved payment methods, subscriptions, repeat purchases, or clean reconciliation. If you pass
customer_idtoPOST /payments, it must be an existing Paychtec customer ID returned by the Customers API. Do not invent a local customer ID and send it directly on a payment. -
Create a payment. Use
POST /payments. Sendamountin the smallest currency unit, the ISO currency code,profile_id, and your merchant metadata. For a simple one-off payment, omitcustomer_idand send customer details directly on the payment payload:email,name,phone, andphone_country_code. Useorder_detailsfor order contents. Do not senditems,line_items, orcart_items. -
Confirm the payment. Use
confirm: truein the create payload for a one-step flow, or callPOST /payments/:payment_id/confirmin a two-step flow. -
Handle redirects and next actions. Some methods require 3DS, wallet authorization, bank redirects, or asynchronous processing.
-
Verify webhooks. Webhooks should update local order and ledger state. Treat webhooks as the source of truth for asynchronous outcomes.
-
Capture, cancel, or refund. Capture manual payments after fulfillment, cancel abandoned authorizations, and refund settled payments with retry-safe
refund_idvalues.
Payload Reference
Common mistakes: Do not send items; use order_details. Do not invent customer_id. Do not expose secret API keys in the browser. Do not update final order state from the browser response alone; use webhooks as the source of truth.
Create Customer
POST /customers
Use this payload when creating a reusable customer profile.
{
"customer_id": "cus_acme_42",
"email": "customer@example.com",
"name": "Jane Customer",
"phone": "6502530000",
"phone_country_code": "+1",
"description": "Customer from checkout",
"address": {
"line1": "1600 Amphitheatre Parkway",
"city": "Mountain View",
"state": "CA",
"zip": "94043",
"country": "US",
"first_name": "Jane",
"last_name": "Customer"
},
"metadata": {
"internal_customer_id": "42"
}
}Important fields:
| Field | Required | Notes |
|---|---|---|
customer_id | No | Optional merchant-supplied customer identifier for POST /customers. Once created, use the returned Paychtec customer ID on future payment requests. |
email | No | Recommended for receipts, fraud checks, 3DS, subscriptions, and BNPL. |
address | No | Can be reused as default billing details. |
metadata | No | Store non-sensitive merchant references only. |
Create Payment
POST /payments
Use this one-step payload when your backend is allowed to send payment method details and should authorize immediately.
For a simple one-off payment, omit customer_id and provide email, name, phone, and phone_country_code directly on the payment payload.
Only send customer_id when you have first created or retrieved the customer through the Customers API and are passing the returned Paychtec customer ID.
Order contents must be sent as order_details; do not use items, line_items, or cart_items.
Include billing on the request that sends payment_method_data: on POST /payments for one-step confirmation, or on POST /payments/:payment_id/confirm for two-step confirmation.
{
"amount": 6540,
"currency": "USD",
"profile_id": "YOUR_PROFILE_ID",
"payment_id": "pay_order_123",
"confirm": true,
"capture_method": "automatic",
"authentication_type": "three_ds",
"return_url": "https://example.com/payment-return",
"email": "customer@example.com",
"name": "Jane Customer",
"phone": "6502530000",
"phone_country_code": "+1",
"payment_method": "card",
"payment_method_type": "credit",
"payment_method_data": {
"card": {
"card_number": "4242424242424242",
"card_exp_month": "12",
"card_exp_year": "2028",
"card_cvc": "123",
"card_holder_name": "Jane Customer"
}
},
"billing": {
"address": {
"line1": "1600 Amphitheatre Parkway",
"city": "Mountain View",
"state": "CA",
"zip": "94043",
"country": "US",
"first_name": "Jane",
"last_name": "Customer"
},
"phone": {
"number": "6502530000",
"country_code": "+1"
}
},
"browser_info": {
"ip_address": "203.0.113.42",
"user_agent": "Mozilla/5.0",
"accept_header": "text/html",
"language": "en-US",
"color_depth": 24,
"screen_height": 1080,
"screen_width": 1920,
"time_zone": -300,
"java_enabled": false,
"java_script_enabled": true
},
"order_details": [
{
"name": "Premium plan",
"quantity": 1,
"amount": 6540,
"currency": "USD"
}
],
"metadata": {
"order_id": "order_123",
"cart_id": "cart_456"
}
}Important fields:
| Field | Required | Notes |
|---|---|---|
amount | Yes | Smallest currency unit, such as cents for USD. |
currency | Yes | Three-letter ISO currency code. |
profile_id | Yes | Merchant business profile used for the payment. |
payment_id | No | Recommended for merchant-side reconciliation and idempotent retries. |
customer_id | No | Must be an existing Paychtec customer ID returned by the Customers API. Do not generate a local customer ID and send it directly to POST /payments. For one-off payments, omit this field and send customer details directly on the payment payload. |
confirm | No | Set true for one-step authorization; set false for two-step flow. |
email | Recommended | Customer email for receipts, fraud checks, 3DS, and asynchronous payment methods. |
name | Recommended | Customer name for payment risk checks. |
phone | Recommended | Customer phone number without country code. |
phone_country_code | Recommended | Phone country code, such as +1. |
payment_method | Conditional | Required when confirming in the same request. |
payment_method_type | Conditional | Required for many payment method categories. |
payment_method_data | Conditional | Required when confirming with direct payment details. |
billing | Yes | Required billing address and phone details for the payer. Include it on the request that sends payment_method_data. |
return_url | Conditional | Required for redirect, wallet, bank redirect, and hosted checkout flows. |
order_details | Recommended | Order contents for the payment. Use this field name; do not send items, line_items, or cart_items. |
browser_info | Recommended | Strongly recommended for card payments and 3DS. |
metadata | No | Store order references, not secrets or raw card data. |
If your flow needs customer_id, call POST /customers or GET /customers/:customer_id first, then pass the returned Paychtec customer ID to POST /payments.
Minimal One-Step Sandbox Payment
This example creates and confirms a card payment in one request without a reusable customer record.
curl -X POST 'https://api.sandbox.paychtec.com/payments' \ -H "Content-Type: application/json" \ -H "api-key: snd_YOUR_API_KEY" \ -H "X-Idempotency-Key: order_123_attempt_1" \ -d '{"amount": 6540,"currency": "USD","profile_id": "YOUR_PROFILE_ID","payment_id": "pay_order_123","confirm": true,"capture_method": "automatic","authentication_type": "three_ds","return_url": "https://example.com/payment-return","email": "customer@example.com","name": "Jane Customer","phone": "6502530000","phone_country_code": "+1","payment_method": "card","payment_method_type": "credit","payment_method_data": { "card": { "card_number": "4242424242424242", "card_exp_month": "12", "card_exp_year": "2028", "card_cvc": "123", "card_holder_name": "Jane Customer" }},"billing": { "address": { "line1": "1600 Amphitheatre Parkway", "city": "Mountain View", "state": "CA", "zip": "94043", "country": "US", "first_name": "Jane", "last_name": "Customer" }, "phone": { "number": "6502530000", "country_code": "+1" }},"order_details": [ { "name": "Premium plan", "quantity": 1, "amount": 6540, "currency": "USD" }],"metadata": { "order_id": "order_123"}}'Direct card API payloads can put PCI obligations on your application. If you do not intend to handle raw card data, use the SDK integration guide instead.
Create Payment For Later Confirmation
POST /payments
Use this payload when the payment will be confirmed separately.
Only include customer_id when it is an existing Paychtec customer ID returned by the Customers API.
{
"amount": 6540,
"currency": "USD",
"profile_id": "YOUR_PROFILE_ID",
"customer_id": "cus_acme_42",
"confirm": false,
"capture_method": "automatic",
"description": "Order #123",
"metadata": {
"order_id": "order_123"
}
}The response includes a payment_id. Use it with POST /payments/:payment_id/confirm.
Confirm Payment
POST /payments/:payment_id/confirm
Use this payload after creating a payment with confirm: false.
{
"payment_method": "card",
"payment_method_type": "credit",
"payment_method_data": {
"card": {
"card_number": "4242424242424242",
"card_exp_month": "12",
"card_exp_year": "2028",
"card_cvc": "123",
"card_holder_name": "Jane Customer"
}
},
"billing": {
"address": {
"line1": "1600 Amphitheatre Parkway",
"city": "Mountain View",
"state": "CA",
"zip": "94043",
"country": "US",
"first_name": "Jane",
"last_name": "Customer"
},
"phone": {
"number": "6502530000",
"country_code": "+1"
}
},
"return_url": "https://example.com/payment-return",
"browser_info": {
"ip_address": "203.0.113.42",
"user_agent": "Mozilla/5.0",
"accept_header": "text/html",
"language": "en-US",
"java_script_enabled": true
}
}Capture Payment
POST /payments/:payment_id/capture
Use this for payments created with capture_method: "manual".
{
"amount_to_capture": 6540,
"statement_descriptor_prefix": "ACME",
"statement_descriptor_suffix": "Order123"
}If you omit amount_to_capture, the API captures the capturable amount when supported by the payment state.
Cancel Payment
POST /payments/:payment_id/cancel
{
"cancellation_reason": "Customer requested cancellation"
}Create Refund
POST /refunds
{
"payment_id": "pay_order_123",
"refund_id": "refund_order_123_001",
"amount": 500,
"reason": "Customer requested refund",
"refund_type": "Instant",
"metadata": {
"order_id": "order_123",
"support_ticket": "ticket_789"
}
}Important fields:
| Field | Required | Notes |
|---|---|---|
payment_id | Yes | Payment to refund. |
refund_id | No | Recommended for retry-safe reconciliation. |
amount | No | Omit for full refund; send minor units for partial refund. |
reason | No | Keep this human-readable for operations teams. |
Create Payment Link
POST /payment_link
{
"amount": 5000,
"currency": "USD",
"description": "Invoice #1234",
"link_type": "one_time",
"expiry": "2024-12-31T23:59:59Z",
"customer_id": "cus_acme_42",
"send_email": true,
"email": "customer@example.com",
"capture_method": "automatic",
"authentication_type": "three_ds",
"require_customer_info": true,
"payment_link_config": {
"seller_name": "Acme Inc.",
"sdk_layout": "tabs",
"allowed_payment_method_types": ["card", "google_pay"]
}
}Create Subscription
POST /subscriptions/create
{
"customer_id": "cus_acme_42",
"item_price_id": "standard-plan-USD-Monthly",
"payment_details": {
"return_url": "https://example.com/subscription-return",
"authentication_type": "no_three_ds",
"capture_method": "automatic",
"setup_future_usage": "off_session"
},
"merchant_reference_id": "sub_order_123",
"plan_id": "pro_monthly"
}Subscription create requests also require the X-Profile-Id header. Subscription fields can vary by product configuration; align item_price_id, plan, coupon, billing, and shipping fields with your subscription setup.
Create Payout
POST /payouts/create
{
"amount": 5000,
"currency": "USD",
"customer_id": "cus_acme_42",
"payout_type": "bank",
"description": "Vendor payout",
"metadata": {
"vendor_id": "vendor_123"
}
}Payout availability depends on your account configuration.
Analytics Metrics
POST /analytics/v1/merchant/metrics/payments
{
"timeRange": {
"startTime": "2024-01-01T00:00:00Z",
"endTime": "2024-01-31T23:59:59Z"
},
"metrics": ["payment_count", "payment_success_rate", "payment_processed_amount"],
"source": "BATCH",
"delta": true,
"timeSeries": {
"granularity": "G_ONE_DAY"
},
"groupByNames": ["currency"],
"filters": {
"currency": ["USD"],
"status": ["succeeded"]
}
}Use the same pattern for refund and dispute analytics with their resource-specific metric paths.
Webhook Payload Shape
Your endpoint receives event payloads for payment, refund, dispute, payout, and subscription changes. Store and process them idempotently.
{
"merchant_id": "1234567890",
"event_id": "evt_1234567890",
"event_type": "payment_succeeded",
"content": {
"type": "payment_details",
"object": {
"payment_id": "pay_order_123",
"status": "succeeded",
"amount": 6540,
"currency": "USD",
"metadata": {
"order_id": "order_123"
}
}
},
"timestamp": "2024-01-22T10:20:00Z"
}Webhook payload fields can vary by event type. Verify the signature using the raw request body, process each event_id once, and retrieve the resource from the API if your system needs fields not included in the event.
X-Webhook-Signature-512 signs the exact raw request body with HMAC-SHA512. Do not verify against a parsed or reserialized JSON object.
For payment events, update local orders using content.object.payment_id or your own content.object.metadata.order_id.
Route Reference
Payments
| Purpose | Method | Path | Payload |
|---|---|---|---|
| Create payment | POST | /payments | Create Payment |
| List payments | POST | /payments/list | Filter body |
| Retrieve payment | GET | /payments/:payment_id | None |
| Update payment | POST | /payments/:payment_id | Payment update fields |
| Confirm payment | POST | /payments/:payment_id/confirm | Confirm Payment |
| Capture payment | POST | /payments/:payment_id/capture | Capture Payment |
| Cancel payment | POST | /payments/:payment_id/cancel | Cancel Payment |
| Approve review | POST | /payments/:payment_id/approve | Optional review fields |
| Reject review | POST | /payments/:payment_id/reject | Optional review fields |
Customers
| Purpose | Method | Path | Payload |
|---|---|---|---|
| Create customer | POST | /customers | Create Customer |
| List customers | GET | /customers/list | Query params |
| Retrieve customer | GET | /customers/:customer_id | None |
| Update customer | POST | /customers/:customer_id | Customer update fields |
| Delete customer | DELETE | /customers/:customer_id | None |
Refunds
| Purpose | Method | Path | Payload |
|---|---|---|---|
| Create refund | POST | /refunds | Create Refund |
| List refunds | POST | /refunds/list | Filter body |
| Retrieve refund | GET | /refunds/:refund_id | None |
| Update refund | POST | /refunds/:refund_id | Refund update fields |
Payment Links
| Purpose | Method | Path | Payload |
|---|---|---|---|
| Create payment link | POST | /payment_link | Create Payment Link |
| List payment links | POST | /payment_link/list | Filter body |
| Retrieve payment link | GET | /payment_link/:payment_link_id | None |
Other Merchant Routes
| Purpose | Method | Path |
|---|---|---|
| List business profiles | GET | /account/:merchant_id/business_profile |
| Create API key | POST | /api_keys/:merchant_id |
| List API keys | GET | /api_keys/:merchant_id/list |
| Retrieve API key | GET | /api_keys/:merchant_id/:key_id |
| Update API key | POST | /api_keys/:merchant_id/:key_id |
| Revoke API key | DELETE | /api_keys/:merchant_id/:key_id |
| List disputes | GET | /disputes/list |
| Retrieve dispute | GET | /disputes/:dispute_id |
| Accept dispute | POST | /disputes/accept/:dispute_id |
| Submit evidence | POST | /disputes/evidence |
| Retrieve evidence | GET | /disputes/evidence/:dispute_id |
| Delete evidence | DELETE | /disputes/evidence |
| Create payout | POST | /payouts/create |
| List payouts | POST | /payouts/list |
| Retrieve payout | GET | /payouts/:payout_id |
| Update payout | PUT | /payouts/:payout_id |
| Cancel payout | POST | /payouts/:payout_id/cancel |
| Fulfill payout | POST | /payouts/:payout_id/fulfill |
| Create subscription | POST | /subscriptions/create |
| Create and confirm subscription | POST | /subscriptions |
| Retrieve subscription | GET | /subscriptions/:subscription_id |
| Update subscription | PUT | /subscriptions/:subscription_id/update |
| Confirm subscription | POST | /subscriptions/:subscription_id/confirm |
| Pause subscription | POST | /subscriptions/:subscription_id/pause |
| Resume subscription | POST | /subscriptions/:subscription_id/resume |
| Cancel subscription | POST | /subscriptions/:subscription_id/cancel |
| Payment metrics | POST | /analytics/v1/merchant/metrics/payments |
| Refund metrics | POST | /analytics/v1/merchant/metrics/refunds |
| Dispute metrics | POST | /analytics/v1/merchant/metrics/disputes |
Response And Status Handling
Do not fulfill an order just because a create or confirm request returned successfully. Inspect the returned resource status and listen for webhooks.
Common handling:
succeeded: fulfill the order.requires_capture: capture later if manual capture was intended.requires_customer_action,requires_redirection, or similar action states: send the customer through the returned next action or redirect flow.processingorpending: wait for a webhook or retrieve the resource later.failed,cancelled, or terminal decline states: show a recoverable failure and allow a new payment attempt.
Webhook Requirements
Your webhook endpoint should:
- Accept POST requests.
- Read the raw request body for signature verification.
- Verify the
X-Webhook-Signature-512header before trusting signed payloads. The signature is an HMAC-SHA512 over the raw request body. - Process each
event_idonce. - Update local order, refund, dispute, payout, or subscription state.
- For payment events, update orders using
content.object.payment_idorcontent.object.metadata.order_id. - Retrieve the resource from the API if your system needs fields not included in the event.
- Return a fast 2xx response after the event is processed or durably queued.
Production Checklist
- Sandbox payments, refunds, and webhooks have been tested.
- Idempotency keys are used for retryable mutations.
- Secret keys are stored only on the server.
- Raw card data is never logged.
- Webhook signatures are verified.
- Duplicate webhook events do not duplicate fulfillment.
- Payment, refund, dispute, payout, and subscription statuses are stored in your system.
- Redirect and 3DS return flows are tested.
- Production API keys and production webhook endpoints are configured.
- A controlled production transaction has been tested before general launch.