# Hyperswitch Prism - LLM Context Document This document provides complete context for integrating the Hyperswitch Prism SDK. It is optimized for AI assistants and LLMs to generate accurate payment integration code. --- ## PRIMARY USE CASE: Integrating an Existing Connector > **Most users of this SDK want to integrate a payment processor (connector) that is already implemented in Prism.** > > Examples: "I need to integrate Stripe", "I need to integrate Adyen", "I need to integrate PayPal" ### Your Integration Workflow ``` START HERE — You want to integrate a connector (e.g., Stripe, Adyen, PayPal) │ ▼ STEP 0 ──► FETCH the Generated API Reference FIRST │ URL: https://raw.githubusercontent.com/juspay/hyperswitch-prism/main/docs-generated/llms.txt │ This contains the master index of ALL 81+ connectors │ Find YOUR connector in the list — it has direct links to docs and examples │ ▼ STEP 1 ──► Read your connector's specific documentation (linked in the index) │ Each connector doc has: authentication, required fields, scenarios, examples │ ▼ STEP 2 ──► Run Field Probe for your connector × flow × payment-method │ Command: npx hyperswitch-prism probe --connector --flow │ This reveals REQUIRED fields. TypeScript types alone are insufficient. │ ▼ STEP 3 ──► Read Connector Example (Section 2 of this doc) for patterns │ Use exact field names and structures from the example. │ Do NOT invent field names from TypeScript types. │ ▼ STEP 4 ──► Apply Integration Rules (Section 3) │ Critical: Status codes are numbers, not strings. │ ▼ STEP 5 ──► Write code following the patterns exactly ``` --- ## DOCUMENT STRUCTURE - SECTION 0: AI Integration Protocol (Mandatory Reading) - SECTION 1: Field Probe Tool Usage - SECTION 2: Connector-Specific Examples - SECTION 3: Integration Rules & Constraints - SECTION 4: SDK Installation - SECTION 5: Configuration Reference - SECTION 6: Architecture Overview - SECTION 7: Service Client Reference - SECTION 8: Platform Support - SECTION 9: Pre-Deployment Checklist --- ## SECTION 0 — AI INTEGRATION PROTOCOL (Mandatory Reading) ### What You Need to Know Before Writing Code **Prism already implements 81+ connectors.** Your job is NOT to implement a connector — it is to **configure and call** the existing connector implementation correctly. **The Most Common Mistake:** Developers try to write integration code by looking at TypeScript types. This fails because: 1. Types don't show which fields are **required** vs optional for each connector 2. Each connector has different authentication patterns 3. Each connector has different required fields for the same flow **The Solution:** 1. **Start with the Generated API Reference** — find your connector there 2. **Use Field Probe** — discover required fields dynamically 3. **Copy from working examples** — don't invent field names ### Critical Rules (Violations Cause Runtime Errors) | Violation | Result | |-----------|--------| | Skip Field Probe | `IntegrationError: MISSING_REQUIRED_FIELD` at runtime | | Ignore Connector Examples | Type mismatches, wrong config format, silent failures | | Compare status to string | Comparison always returns `false` | | Use PaymentStatus for refunds | Wrong status interpretation (value 4 = AUTH_PENDING vs REFUND_SUCCESS) | ### System Prompt Template When helping users with Hyperswitch Prism: ``` 1. ALWAYS run field probe first: npx hyperswitch-prism probe --connector --flow 2. Use Section 2 connector examples as the source of truth for request structure 3. Never compare response.status to strings. Always use numeric values (e.g., status === 8) 4. Field Probe output overrides TypeScript types - trust the probe, not the IDE 5. For refunds, use RefundStatus enum; for authorize/capture/void, use PaymentStatus enum ``` --- ## SECTION 1 — FIELD PROBE TOOL ### What It Does The field-probe CLI discovers required fields, types, and sample payloads for every connector × flow × payment-method combination WITHOUT making HTTP calls. ### Commands ```bash # Basic usage - discover fields for connector + flow + payment method npx hyperswitch-prism probe --connector stripe --flow authorize --payment-method card # Discover all supported flows for a connector npx hyperswitch-prism probe --connector adyen --all-flows # JSON output for programmatic parsing npx hyperswitch-prism probe --connector stripe --flow authorize --payment-method card --json ``` ### Sample Output ```json { "connector": "stripe", "flow": "authorize", "paymentMethod": "Card", "status": "supported", "fields": { "merchant_transaction_id": { "required": true, "type": "string" }, "amount.minor_amount": { "required": true, "type": "int64" }, "amount.currency": { "required": true, "type": "Currency enum" }, "capture_method": { "required": true, "type": "CaptureMethod enum" }, "payment_method.card.card_number": { "required": true, "type": "SecretString" }, "payment_method.card.card_exp_month": { "required": true, "type": "SecretString" }, "payment_method.card.card_exp_year": { "required": true, "type": "SecretString" }, "payment_method.card.card_cvc": { "required": true, "type": "SecretString" }, "browser_info": { "required": false, "type": "BrowserInfo object" }, "auth_type": { "required": false, "type": "AuthenticationType enum" } }, "sample": { "url": "https://api.stripe.com/v1/payment_intents", "method": "POST", "body": "amount=1000¤cy=usd&..." } } ``` ### Connector-Specific Requirements Summary ``` ┌─────────────┬───────────┬─────────────────────────────────────────────────┐ │ Connector │ Flow │ Extra Required Fields │ ├─────────────┼───────────┼─────────────────────────────────────────────────┤ │ stripe │ authorize │ None (base fields only) │ │ stripe │ capture │ connectorTransactionId │ │ stripe │ refund │ connectorTransactionId, refundAmount, reason │ │ stripe │ void │ connectorTransactionId │ ├─────────────┼───────────┼─────────────────────────────────────────────────┤ │ adyen │ authorize │ browserInfo (ALWAYS), merchantAccount (config) │ │ adyen │ refund │ reason must be enum: OTHER|RETURN|DUPLICATE| │ │ │ │ FRAUD|CUSTOMER_REQUEST (NOT free-text) │ ├─────────────┼───────────┼─────────────────────────────────────────────────┤ │ paypal │ authorize │ clientId + clientSecret (SignatureKey config) │ │ cybersource │ authorize │ browserInfo required for 3DS flows │ └─────────────┴───────────┴─────────────────────────────────────────────────┘ ``` --- ## SECTION 2 — CONNECTOR EXAMPLES (Copy-Paste Ready) ### 2.1 Stripe #### Node.js - Complete Flow ```typescript import { PaymentClient, types, IntegrationError, ConnectorError, NetworkError } from 'hyperswitch-prism'; // CONFIGURATION const client = new PaymentClient({ connectorConfig: { stripe: { apiKey: { value: process.env.STRIPE_API_KEY! } } } }); // AUTHORIZE (manual capture - hold funds) const authResult = await client.authorize({ merchantTransactionId: 'txn_001', amount: { minorAmount: 1000, currency: types.Currency.USD }, captureMethod: types.CaptureMethod.MANUAL, paymentMethod: { card: { cardNumber: { value: '4111111111111111' }, cardExpMonth: { value: '12' }, cardExpYear: { value: '2027' }, cardCvc: { value: '123' }, cardHolderName: { value: 'Jane Doe' } } }, address: { billingAddress: {} }, authType: types.AuthenticationType.NO_THREE_DS, testMode: true }); // STATUS CHECK: status is NUMBER, not string if (authResult.status === types.PaymentStatus.AUTHORIZED) { // === 6 console.log('Authorized:', authResult.connectorTransactionId); } // CAPTURE const captureResult = await client.capture({ merchantCaptureId: 'cap_001', connectorTransactionId: authResult.connectorTransactionId!, // Use ! or check first amountToCapture: { minorAmount: 1000, currency: types.Currency.USD }, testMode: true }); // captureResult.status === types.PaymentStatus.CHARGED (8) // REFUND const refundResult = await client.refund({ merchantRefundId: 'ref_001', connectorTransactionId: authResult.connectorTransactionId!, refundAmount: { minorAmount: 500, currency: types.Currency.USD }, reason: 'RETURN', // Stripe accepts free-text testMode: true }); // refundResult.status === types.RefundStatus.REFUND_SUCCESS (4) // NOTE: Use RefundStatus enum, NOT PaymentStatus // VOID const voidResult = await client.void({ merchantVoidId: 'void_001', connectorTransactionId: authResult.connectorTransactionId!, cancellationReason: 'Customer cancelled', testMode: true }); // voidResult.status === types.PaymentStatus.VOIDED (11) // AUTO-CAPTURE (one-step) const autoResult = await client.authorize({ merchantTransactionId: 'txn_002', amount: { minorAmount: 2000, currency: types.Currency.USD }, captureMethod: types.CaptureMethod.AUTOMATIC, // Key difference paymentMethod: { card: { cardNumber: { value: '4111111111111111' }, cardExpMonth: { value: '12' }, cardExpYear: { value: '2027' }, cardCvc: { value: '123' } } }, testMode: true }); // autoResult.status === types.PaymentStatus.CHARGED (8) immediately ``` #### Python - Stripe ```python from payments import PaymentClient, SecretString from payments.generated import sdk_config_pb2, payment_pb2 import os cfg = sdk_config_pb2.ConnectorConfig() cfg.connector_config.CopyFrom(payment_pb2.ConnectorSpecificConfig( stripe=payment_pb2.StripeConfig( api_key=SecretString(value=os.environ["STRIPE_API_KEY"]) ) )) client = PaymentClient(cfg) request = payment_pb2.PaymentServiceAuthorizeRequest( merchant_transaction_id="txn_001", amount=payment_pb2.MinorUnit(minor_amount=1000, currency=payment_pb2.Currency.USD), capture_method=payment_pb2.CaptureMethod.AUTOMATIC, payment_method=payment_pb2.PaymentMethodData( card=payment_pb2.Card( card_number=SecretString(value="4111111111111111"), card_exp_month=SecretString(value="12"), card_exp_year=SecretString(value="2027"), card_cvc=SecretString(value="123"), ) ), test_mode=True, ) result = client.authorize(request) # result.status == payment_pb2.CHARGED (8) ``` ### 2.2 Adyen ⚠️ **CRITICAL: Adyen requires browserInfo for ALL card payments. Omitting throws `IntegrationError: MISSING_REQUIRED_FIELD: browser_info`** ```typescript import { PaymentClient, types } from 'hyperswitch-prism'; const client = new PaymentClient({ connectorConfig: { adyen: { apiKey: { value: process.env.ADYEN_API_KEY! }, merchantAccount: { value: process.env.ADYEN_MERCHANT_ACCOUNT! } } } }); const authResult = await client.authorize({ merchantTransactionId: 'txn_adyen_001', amount: { minorAmount: 1000, currency: types.Currency.USD }, captureMethod: types.CaptureMethod.MANUAL, paymentMethod: { card: { cardNumber: { value: '4111111111111111' }, cardExpMonth: { value: '03' }, cardExpYear: { value: '2030' }, cardCvc: { value: '737' }, // Adyen sandbox CVC is 737 cardHolderName: { value: 'Jane Doe' } } }, // REQUIRED for Adyen - do not omit browserInfo: { colorDepth: 24, screenHeight: 900, screenWidth: 1440, javaEnabled: false, javaScriptEnabled: true, language: 'en-US', timeZoneOffsetMinutes: 0, acceptHeader: 'text/html,*/*;q=0.8', userAgent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)' }, address: { billingAddress: {} }, authType: types.AuthenticationType.NO_THREE_DS, testMode: true }); // REFUND: reason must be enum, NOT free-text const refundResult = await client.refund({ merchantRefundId: 'ref_adyen_001', connectorTransactionId: authResult.connectorTransactionId!, refundAmount: { minorAmount: 500, currency: types.Currency.USD }, reason: 'RETURN', // Valid: OTHER|RETURN|DUPLICATE|FRAUD|CUSTOMER_REQUEST // reason: 'my text' // INVALID - throws ConnectorError testMode: true }); ``` ### 2.3 PayPal ```typescript import { PaymentClient, types } from 'hyperswitch-prism'; const client = new PaymentClient({ connectorConfig: { paypal: { clientId: { value: process.env.PAYPAL_CLIENT_ID! }, clientSecret: { value: process.env.PAYPAL_CLIENT_SECRET! } } } }); const result = await client.authorize({ merchantTransactionId: 'txn_paypal_001', amount: { minorAmount: 1000, currency: types.Currency.USD }, captureMethod: types.CaptureMethod.AUTOMATIC, paymentMethod: { card: { cardNumber: { value: '4111111111111111' }, cardExpMonth: { value: '12' }, cardExpYear: { value: '2027' }, cardCvc: { value: '123' } } }, testMode: true }); ``` ### 2.4 Error Handling Pattern ```typescript import { IntegrationError, ConnectorError, NetworkError, types } from 'hyperswitch-prism'; async function safeAuthorize(client, request) { try { const response = await client.authorize(request); // Soft declines are status values, NOT exceptions if (response.status === types.PaymentStatus.FAILURE) { // 21 console.error('Soft decline:', response.error?.message); return null; } if (response.status === types.PaymentStatus.AUTHORIZATION_FAILED) { // 7 console.error('Auth failed:', response.error?.message); return null; } return response; } catch (error) { if (error instanceof IntegrationError) { // Bad config, missing field, serialization error // FIX: Do NOT retry. Fix the request structure. console.error('[IntegrationError]', error.errorCode, error.message); } else if (error instanceof ConnectorError) { // Response transformation failed // FIX: Log and investigate. Do NOT retry automatically. console.error('[ConnectorError]', error.errorCode, error.message); } else if (error instanceof NetworkError) { // Timeout, DNS failure, connection refused // FIX: Safe to retry with exponential backoff console.error('[NetworkError]', error.message); } return null; } } ``` --- ## SECTION 3 — INTEGRATION RULES ### Rule 1: Status Codes Are Numbers ```typescript // WRONG - Always false if (response.status === 'CHARGED') { } if (response.status === 'AUTHORIZED') { } // CORRECT if (response.status === 8) { } if (response.status === types.PaymentStatus.CHARGED) { } // === 8 ``` ### Rule 2: PaymentStatus vs RefundStatus Value 4 has TWO meanings: - PaymentStatus 4 = AUTHENTICATION_PENDING (authorize/capture/void) - RefundStatus 4 = REFUND_SUCCESS (refund only) ```typescript const auth = await client.authorize(...); const refund = await client.refund(...); // CORRECT usage if (auth.status === types.PaymentStatus.AUTHORIZED) { } // === 6 if (refund.status === types.RefundStatus.REFUND_SUCCESS) { } // === 4 ``` ### Rule 3: Optional Field Guards ```typescript // connectorTransactionId can be undefined on failure const txId = authResult.connectorTransactionId ?? ''; // error may be undefined on success const errMsg = response.error?.message ?? 'Unknown error'; ``` ### Rule 4: Connector Config Formats ```typescript // Stripe - HeaderKey - apiKey only { stripe: { apiKey: { value: '...' } } } // Adyen - HeaderKey + MerchantAccount - apiKey + merchantAccount { adyen: { apiKey: { value: '...' }, merchantAccount: { value: '...' } } } // PayPal - SignatureKey - clientId + clientSecret { paypal: { clientId: { value: '...' }, clientSecret: { value: '...' } } } ``` ### Rule 5: Status Code Reference **PaymentStatus (authorize, capture, void)** | Number | Enum Name | Meaning | |--------|-----------|---------| | 0 | UNSPECIFIED | Unknown | | 1 | STARTED | Initiated | | 4 | AUTHENTICATION_PENDING | 3DS redirect needed | | 5 | AUTHENTICATION_SUCCESSFUL | 3DS passed | | 6 | AUTHORIZED | Funds held | | 7 | AUTHORIZATION_FAILED | Declined | | 8 | CHARGED | Captured/auto-captured | | 11 | VOIDED | Cancelled | | 20 | PENDING | Async processing | | 21 | FAILURE | Soft decline | **RefundStatus (refund only)** | Number | Enum Name | Meaning | |--------|-----------|---------| | 1 | REFUND_FAILURE | Failed | | 2 | REFUND_MANUAL_REVIEW | Under review | | 3 | REFUND_PENDING | Processing | | 4 | REFUND_SUCCESS | Completed | --- ## SECTION 4 — INSTALLATION ### Node.js (v18+) ```bash npm install hyperswitch-prism ``` ### Python (3.9+) ```bash pip install hyperswitch-prism ``` ### Java/Kotlin (JDK 17+) ```xml io.hyperswitch prism 0.0.1 ``` --- ## SECTION 5 — CONFIGURATION ### Timeouts ```typescript const client = new PaymentClient(config, { http: { totalTimeoutMs: 30000, connectTimeoutMs: 10000, responseTimeoutMs: 25000 } }); ``` ### Proxy ```typescript const client = new PaymentClient(config, { http: { proxy: { httpsUrl: 'https://proxy.company.com:8443', bypassUrls: ['http://localhost'] } } }); ``` ### Per-Request Override ```typescript const response = await client.authorize(request, { http: { totalTimeoutMs: 60000 } }); ``` --- ## SECTION 6 — ARCHITECTURE ``` Application (Node/Python/Java) │ ▼ Service Clients (PaymentClient, etc.) │ ▼ ConnectorClient (HTTP + connection pool) │ ▼ FFI Bindings (koffi/UniFFI/JNA) │ ▼ Rust Core (transformation logic) │ ▼ Payment Processor APIs ``` --- ## SECTION 7 — SERVICE CLIENTS | Client | Methods | |--------|---------| | PaymentClient | authorize, capture, refund, void, get, sync | | CustomerClient | create | | PaymentMethodClient | tokenize | | MerchantAuthenticationClient | createServerAuthenticationToken, createClientAuthenticationToken | | PaymentMethodAuthenticationClient | preAuthenticate, authenticate, postAuthenticate | | RecurringPaymentClient | setup, charge, revoke | | EventClient | handleEvent | | RefundClient | get, createRefund, updateRefund | | DisputeClient | accept, defend, submitEvidence, get | --- ## SECTION 8 — PLATFORM SUPPORT | Platform | Architectures | |----------|---------------| | macOS | x86_64, arm64 | | Linux | x86_64, aarch64 | | Windows | x86_64 | --- ## SECTION 9 — PRE-DEPLOYMENT CHECKLIST - [ ] Ran Field Probe for every connector × flow combination in use - [ ] Used Section 2 connector examples as source of truth - [ ] All `response.status` comparisons use numeric values - [ ] Using correct status enum (PaymentStatus vs RefundStatus) - [ ] Guarded optional fields with `??` or `?.` - [ ] Error handling distinguishes IntegrationError/ConnectorError/NetworkError - [ ] Tested with sandbox credentials --- ## ADDITIONAL RESOURCES - Repository: https://github.com/juspay/hyperswitch-prism - Full Examples: https://github.com/juspay/hyperswitch-prism/tree/main/examples - Field Probe Data: https://github.com/juspay/hyperswitch-prism/tree/main/data/field_probe - Generated API Documentation: https://raw.githubusercontent.com/juspay/hyperswitch-prism/main/docs-generated/llms.txt