API Docs
API ReferenceSDK Integration Guide

SDK Integration Guide

Use this guide when you want to integrate checkout with the JavaScript SDK. The SDK flow is recommended when you do not want raw card data to touch your application.

Working with an LLM agent? Ask it to read this file first, then implement the server endpoint that creates a payment, the frontend SDK checkout, webhook verification, retries, and status handling according to this guide.

Related integration guides:

LLM Agent Prompt

Read the SDK integration guide at https://docs.v2.paychtec.com/docs/INTEGRATION_SDK and the API integration guide at https://docs.v2.paychtec.com/docs/INTEGRATION_API. Build a merchant SDK integration using the JavaScript SDK. Keep secret keys on the server, use publishable keys in the browser, create payments server-side with confirm=false, pass client_secret to the frontend, confirm payments with the JavaScript SDK, verify webhooks, and update order state from webhook events.

SDK Flow

  1. Your server creates a payment with confirm: false.
  2. Your server returns client_secret and payment_id to your frontend.
  3. Your frontend initializes the SDK with a publishable key.
  4. The SDK renders payment UI and collects payment details.
  5. The SDK confirms the payment and handles required customer actions.
  6. Your webhook endpoint receives final status updates.
  7. Your server fulfills the order only after a successful status is confirmed.

Environments

Use sandbox while building and testing:

https://api.sandbox.paychtec.com

Use production only after testing:

https://api.v2.paychtec.com

Use the SDK host for browser SDK assets:

https://sdk.paychtec.com

Keys

Use secret keys only on your server:

api-key: snd_YOUR_SECRET_API_KEY

Use publishable keys only in the browser:

pk_snd_YOUR_PUBLISHABLE_KEY

Never expose a secret API key in JavaScript sent to the browser.

Server Payload Reference

Create SDK Payment

Your server must create a payment before the SDK can render checkout.

POST /payments

{
  "amount": 5000,
  "currency": "USD",
  "profile_id": "YOUR_PROFILE_ID",
  "customer_id": "cus_acme_42",
  "confirm": false,
  "capture_method": "automatic",
  "description": "Order #123",
  "return_url": "https://example.com/payment-return",
  "metadata": {
    "order_id": "order_123",
    "cart_id": "cart_456"
  }
}

Response fields your server should return to the frontend:

{
  "payment_id": "pay_1234567890abcdef",
  "client_secret": "pay_123_secret_abcdef",
  "status": "requires_payment_method"
}

Important fields:

FieldRequiredNotes
amountYesSmallest currency unit.
currencyYesThree-letter ISO currency code.
profile_idYesMerchant business profile for this payment.
confirmYesUse false; the SDK confirms the payment after collecting details.
customer_idNoRecommended for saved payment methods or repeat customers.
return_urlRecommendedRequired for redirect and 3DS flows.
metadataNoStore order/cart references only.

Example Server Endpoint

app.post('/create-payment', async (req, res) => {
  const { amount, currency, orderId, customerId } = req.body;

  const response = await fetch(`${process.env.API_BASE_URL}/payments`, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'api-key': process.env.SECRET_API_KEY,
      'X-Idempotency-Key': `payment_${orderId}`,
    },
    body: JSON.stringify({
      amount,
      currency,
      profile_id: process.env.PROFILE_ID,
      customer_id: customerId,
      confirm: false,
      return_url: `${process.env.APP_URL}/payment/return`,
      metadata: {
        order_id: orderId,
      },
    }),
  });

  const payment = await response.json();

  if (!response.ok) {
    return res.status(response.status).json(payment);
  }

  res.json({
    paymentId: payment.payment_id,
    clientSecret: payment.client_secret,
  });
});

JavaScript SDK Integration

Load The SDK

Use the SDK URL for your environment.

Production SDK script URL:

<script src="https://sdk.paychtec.com/HyperLoader.js"></script>

For sandbox, use the sandbox SDK host:

<script src="https://sdk.sandbox.paychtec.com/web/0.127.0/v1/HyperLoader.js"></script>

HTML

<form id="payment-form">
  <div id="payment-element"></div>
  <button type="submit" id="submit-button">Pay</button>
  <div id="error-message" role="alert"></div>
</form>

Client Script

const hyper = Hyper('pk_snd_YOUR_PUBLISHABLE_KEY');

const { clientSecret, paymentId } = await fetch('/create-payment', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    amount: 5000,
    currency: 'USD',
    orderId: 'order_123',
    customerId: 'cus_acme_42',
  }),
}).then((response) => response.json());

const unifiedCheckout = hyper.widgets({
  clientSecret,
  appearance: {
    variables: {
      colorPrimary: '#41175e',
      borderRadius: '8px',
    },
  },
});

const paymentElement = unifiedCheckout.create('payment');
paymentElement.mount('#payment-element');

document.getElementById('payment-form').addEventListener('submit', async (event) => {
  event.preventDefault();

  const { error, status } = await hyper.confirmPayment({
    elements: unifiedCheckout,
    confirmParams: {
      return_url: `${window.location.origin}/payment/return?payment_id=${paymentId}`,
    },
  });

  if (error) {
    document.getElementById('error-message').textContent = error.message;
    return;
  }

  if (status) {
    // Show a pending state and wait for your webhook/order status endpoint.
  }
});

Return URL Handling

Your return_url page should:

  • Read the payment_id from the URL or from your stored order session.
  • Show a processing state first.
  • Ask your backend for the latest order or payment status.
  • Avoid fulfilling from browser-only state.
  • Let your webhook handler perform final fulfillment.

Webhook Payload Shape

The SDK confirms the payment in the browser, but your server should still rely on webhooks for final state.

{
  "merchant_id": "1234567890",
  "event_id": "evt_1234567890",
  "event_type": "payment_succeeded",
  "content": {
    "type": "payment_details",
    "object": {
      "payment_id": "pay_1234567890abcdef",
      "status": "succeeded",
      "amount": 5000,
      "currency": "USD",
      "metadata": {
        "order_id": "order_123"
      }
    }
  },
  "timestamp": "2024-01-22T10:20:00Z"
}

Webhook handling requirements:

  • Read the raw body.
  • Verify the signature.
  • Process each event once.
  • Update your order by content.object.payment_id or content.object.metadata.order_id.
  • Fulfill only after a successful terminal status.
  • Return a fast 2xx response after durable processing or enqueueing.

Status Handling

The SDK may return an immediate error, a redirect, or an intermediate status. Your application should:

  • Show inline validation and payment errors from the SDK.
  • Redirect or wait when the SDK starts 3DS or another customer action.
  • Show an order-processing page after confirmation.
  • Poll your backend only as a backup; webhooks should perform final state updates.
  • Fulfill from server-side state, not browser-only state.

Production Checklist

  • Server creates payments with confirm: false.
  • Server returns only client_secret and safe public data to the browser.
  • Secret API key is never exposed to frontend code.
  • Publishable key is used for SDK initialization.
  • Idempotency key is used when creating the payment.
  • SDK is loaded from the correct environment host.
  • return_url is configured and tested.
  • Webhook signatures are verified.
  • Duplicate webhook events do not duplicate fulfillment.
  • Order state is stored server-side.
  • Sandbox card, 3DS, redirect, failure, refund, and webhook flows are tested.