Objavljeno dana

HolestPay FrontCore vodič za Lovable i slične AI sisteme za izgradnju sajtova

Reci Lovable-u (ili sličnom sistemu) da želiš da integrišeš HolestPay plaćanja/fiskalizaciju/isporuku i daj mu ovaj MD markup: https://apps.holest.com/holest-pay/Lovable_or_similar_ai_system.MD.txt
Lovable će tada znati šta treba da te pita i koje instrukcije da ti da…

PODEŠITE PRVO SVE metode koje planirate da koristite (placanje | fiskalizacija | isporuka-API) na https://sandbox.pay.holest.com/ i testirajte ih putem „pay-by-link“ opcije (potpuno eksterni proces). Ako je sve ispravno konfigurisano, integracija će teći glatko uz svega nekoliko upita.

HolestPay FrontCore Guide for Lovable and Similar AI Site Builder Systems – MD file…


# HolestPay FrontCore Integration — Guide for Lovable / AI Code Generators

> **Full technical reference:** https://apps.holest.com/holest-pay/AI_INTEGRATION_GUIDE_FRONTCORE.md.txt  
> **Working sample (sandbox):** https://apps.holest.com/holest-pay/test/sandbox-164-hpay-frontcore-sample.html  
> (View page source and inspect `` tags for real implementation examples.)
>
> **Sample data files — read these to understand real data structures:**
> - `pos_as_read.json` — https://apps.holest.com/holest-pay/pos_as_read.json  
>   Full `client.POS` (same as HPay.POS) object as returned by `HPayInit()`. Contains `payment`, `shipping`, and `fiscal` method arrays with all their properties (`Uid`, `HPaySiteMethodId`, `Name`, `Hidden`, `SubsciptionsType`, `POps`, `PayInputUrl`, `Use IFRAME`, etc.). **Read this to know what payment/shipping methods look like before building any selector UI.**
> - `response_sample.json` — https://apps.holest.com/holest-pay/response_sample.json  
>   Full `hpay_response` object as received in `onHPayResult` event and as POST-back `hpay_forwarded_payment_response`. Contains `payment_status`, `status`, `transaction_uid`, `transaction_user_info`, `vault_token_uid`, `vault_card_brand`, `vault_card_umask`, `vault_exp`, `payment_html`, `fiscal_html`, `integr_html`, `shipping_html`, and all other result fields. **Read this to know what data is available when displaying the thank-you / order confirmation page.**

---

## ?? FIRST ACTION — Ask the User for Their FrontCore Script URL

**Before writing any code, ask the user:**

> *"Please give me your HolestPay FrontCore script URL. It looks like this:*
> ``
> *Do you have it?"*

**If the user says they don't have it, or doesn't know what it is, explain:**

> *"This is a unique `
```

The UID segment in the URL (`07f689c5-...`) is the Merchant Site UID — it is embedded in the URL itself.

**If the user confirms they need backend implementation** (admin actions, backend charges — see pre-build questions above), they must also provide:
- **Merchant Site UID** — visible in HPay panel ? Site Settings (also in the FrontCore script URL)
- **Merchant Site Secret Key** — visible in HPay panel ? Site Settings (keep this server-side only, never expose on frontend)

### ?? Configuration values must be easily changeable by the user

Store all three of these as **user-editable configuration** (environment variables, a settings screen, or a clearly marked config file) — **never hardcode them**:

| Value | Where used | Why it changes |
|---|---|---|
| FrontCore script `src` URL | Frontend, global `
```

When the HPay script is loaded, it also exposes these globals on `window`:
- `window.presentHPayPayForm` — function
- `window.HPayIsSandbox` — environment flag variable

Add a startup check to catch misconfiguration early:

```javascript
// After page load — warn developer if FrontCore failed to initialize
setTimeout(function() {
  if (typeof HolestPayCheckout === 'undefined') {
    console.error(
      'HolestPay FrontCore script did not load. ' +
      'Check that the current origin is listed in "Frontend Script-Core Origins" in the HPay panel.'
    );
  }
}, 5000);
```

---

### Step 2 — Initialize HPay and Load Payment/Shipping Methods

Call `HPayInit()` once when the checkout page loads (or when the user reaches it). It returns a Promise.

- `merchant_site_uid` and environment (`sandbox`/`production`) are **not** parameters — they come from the script URL automatically.
- Language is optional — if omitted, HPay uses the `` attribute or the language set in HPay panel POS settings.

```javascript
// Save this after HPayInit so it can be used in charge_request and admin ops later
let hpayMerchantSiteUid = null;

HPayInit(/* language optional, e.g. 'en' */).then(async client => {
  hpayMerchantSiteUid = client.MerchantsiteUid;

  // Filter available methods by buyer's country (recommended)
  const country = 'RS'; // use actual buyer country, ISO 3166-1 alpha-2
  let availablePayment = [], availableShipping = [];
  try { availablePayment  = await HPay.availablePaymentMethods(country, orderAmount, orderCurrency); } catch(e) {}
  try { availableShipping = await HPay.availableShippingMethods(country, orderAmount, orderCurrency); } catch(e) {}

  // Populate payment method selector
  client.POS.payment.forEach(pm => {
    if (!pm.Hidden && (!availablePayment.length || availablePayment.find(m => m.Uid == pm.Uid))) {
      // Add pm to your UI selector
      // pm.HPaySiteMethodId ? use as pay_request.payment_method
      // pm.Name             ? display name (use this — do NOT invent a name)
      // pm.SubsciptionsType ? contains "cof" or "mit" ? card saving is supported for this method
      // pm.POps             ? e.g. "charge,refund" ? backend operations available
      // pm.PayInputUrl      ? if set, this method supports docking (embedded payment input)
      // pm['Use IFRAME']    ? if false, method uses redirect flow (bank page POST redirect)
    }
  });

  // Populate shipping method selector (if POS has shipping configured)
  if (client.POS.shipping) {
    client.POS.shipping.forEach(sm => {
      if (!sm.Hidden && (!availableShipping.length || availableShipping.find(m => m.Uid == sm.Uid))) {
        // sm.HPaySiteMethodId ? use as pay_request.shipping_method
        // sm.Name             ? display name
      }
    });
  }
});
```

> **Make sure existing payment methods in your UI have a name and description.** Use `pm.Name` from the POS config — do not hardcode or invent names.

---

### Step 3 — Build the `pay_request` and Initiate Payment

```javascript
const pay_request = {
  // NOTE: merchant_site_uid is NOT included here for FrontCore — the script handles auth automatically
  hpaylang: 'en',                                // optional
  order_uid: 'ORDER-20260425-001',               // required — unique per order
  order_name: '#Order 204',                      // optional
  order_amount: '15000.00',                         // required — string, in smallest currency unit or decimal
  order_currency: 'RSD',                         // required — ISO 4217
  payment_method: '179',                         // required — pm.HPaySiteMethodId from Step 2
  shipping_method: '45',                         // optional — sm.HPaySiteMethodId
  order_user_url: 'https://yoursite.com/thanks', // recommended — redirect/thank-you page URL
  notify_url: 'https://yoursite.com/webhook',    // optional — server-to-server webhook (must be publicly reachable)
  cof: 'optional',                               // optional — 'optional'|'required'|'none' — enables card saving
  vault_token_uid: '',                           // optional — saved token UUID, or 1|true|new to force new token
  order_billing: {                               // optional but recommended
    email: 'customer@example.com',
    first_name: 'TEST',
    last_name: 'TEST',
    phone: '+38111111111',
    is_company: 0,
    company: '',                                   // company legal name
    company_tax_id: '',                            // company tax ID in merchant's country
    company_reg_id: '',                            // company registration ID in merchant's country
    address: 'TEST',                                // street name
    address2: '',                                   // recommended for street number / address addition
    city: 'Beograd',
    country: 'RS',
    state: 'Beograd',
    postcode: '11000',
    lang: 'sr_RS'                                // language from merchant platform/system
  },
  order_shipping: {                              // optional
    shippable: false,
    is_cod: 1,                                      // set to 1 when COD logic is used/allowed
    first_name: '',
    last_name: '',
    phone: '',
    company: '',
    address: '',                                    // street name
    address2: '',                                   // recommended for street number / address addition
    city: '',
    country: '',
    state: '',
    postcode: ''
  },
  order_items: [                                  // strongly recommended for reconciliation
    {
      posuid: 114,                                           // merchant's own internal item ID (string or number)
      type: 'product',
      name: 'Sample product name',
      sku: '000550',
      qty: 1,
      price: 4695.99,
      subtotal: 4695.99,
      tax_label: '',
      tax_amount: 0,
      length: '',                                          // always in centimeters (cm)
      width: '',                                           // always in centimeters (cm)
      height: '',                                          // always in centimeters (cm)
      weight: '',                                          // always in grams (g)
      split_pay_uid: '',
      virtual: true,
      tax_percent: 0
    }
  ]
};

// Remove empty fields before sending
Object.keys(pay_request).forEach(k => { if (pay_request[k] === '') delete pay_request[k]; });

// Initiate payment — shows modal or triggers redirect depending on payment method
HPay.presentHPayPayForm(pay_request);
```

**Important — `order_items` field naming must match HolestPay template keys:**

- Use `name`, not `title`
- Use `posuid`, not `variantId`
- Use `qty`, not `quantity`
- `subtotal` is mandatory for each item line
- `posuid` can be any identifier from the merchant's system (SKU/variant/product/internal DB ID)

If source platform fields are Shopify-style, map them explicitly before sending:
- `variantId -> posuid`
- `title -> name`
- `quantity -> qty`
- top-level `items -> order_items`

The same order payload structure is used across all three markups/docs (Lovable prompt, FrontCore guide, Standard guide).
Address convention recommendation: use `address` for street name and `address2` for street number/additional address details.

---

### Step 4 — Docking (Embedded Payment Input)

Some payment methods support an embedded payment input directly in the page (e.g. card form inline). Check `pm.PayInputUrl` — if it is set, docking is supported for that method.

Call `HPay.setPaymentMethodDock()` **when the user selects a payment method or when any checkout field changes** (amount, currency, etc.).

```html

``` ```css #paymentMethodDock { background: #ffffff9e; } ``` ```javascript function updateDock() { const selectedPm = /* pm object for selected payment method */; if (selectedPm && selectedPm.PayInputUrl) { HPay.setPaymentMethodDock( pay_request.payment_method, { order_amount: pay_request.order_amount, order_currency: pay_request.order_currency, monthly_installments: null, vault_token_uid: pay_request.vault_token_uid || null, hpaylang: pay_request.hpaylang, cof: pay_request.cof }, document.getElementById('paymentMethodDock') ); } else { document.getElementById('paymentMethodDock').innerHTML = ''; } } ``` --- ### Step 5 — Handle Results #### A — Event handler (iframe / modal methods) Most payment methods return the result via this event, fired on the current page: ```javascript document.addEventListener('onHPayResult', function(e) { const r = e.hpay_response; if (!r) return; if (r.error && r.error.code) { // Payment error — retry HPay.presentHPayPayForm(pay_request); return; } if (/PAID|RESERVED|SUCCESS|PAYING|OBLIGATED|AWAITING/i.test(r.payment_status)) { // Payment completed or pending payment instructions (AWAITING/OBLIGATED are NOT failed) // Clear cart for PAID/RESERVED and also for PAYING/AWAITING/OBLIGATED. // Display HTML receipts in dedicated containers on your thank-you page: // r.payment_html ? payment receipt HTML // r.fiscal_html ? fiscal receipt HTML (if fiscal module active) // r.integr_html ? integration module HTML // r.shipping_html ? shipping label/receipt HTML (if shipping module active) // r.transaction_user_info ? object with card brand, masked number, etc. if (r.vault_token_uid) {//only if card save is on for some reason subscription or simply token save for faster checkout // IMPORTANT: save this to your database linked to the user account — do NOT only store in browser const saveCardData = { vault_token_uid: r.vault_token_uid, //e.g. hJ0khUi67856765rtyrytrytry 12 up to 128 characters vault_card_brand: r.vault_card_brand, // e.g. "MASTERCARD" vault_card_umask: r.vault_card_umask, // e.g. "544358******4639" vault_exp: r.vault_exp, // e.g. "12/26" vault_scope: r.vault_scope, // e.g. can be Terminal ID fro payment method config or soemthinglike that vault_onlyforuser: r.vault_onlyforuser, //subscription falsy | fast checkout 0 pay_method_uid: r.pay_method_uid //Uid of payment method from HPay.POS.payment[N].Uid }; // POST saveCardData to your backend } // Redirect to thank-you page if needed: // window.location.href = r.order_user_url; } // r.status ? order status (always present) }); document.addEventListener('onHPayPanelClose', function(e) { const r = e.hpay_response; // null if user closed without completing const reason = String((r && r.reason) || '').toLowerCase(); // If pay button was locked during payment start, unlock it on close reasons below. if (/^(user|timeout|cancel|error)$/.test(reason)) { const payBtn = document.getElementById('do-pay'); if (payBtn) payBtn.disabled = false; } if (r && r.reason === '' && /* user wants retry */ false) { setTimeout(() => HPay.presentHPayPayForm(pay_request), 300); } }); ``` #### B — POST-back redirect (redirect methods) Some payment methods (e.g. certain bank integrations) require a **full page redirect to the bank**. `HPay.presentHPayPayForm()` handles this automatically with a POST redirect. After the bank interaction, the user is returned to `order_user_url` via a POST-back. On `order_user_url` (your thank-you/return page), read the result from the POST body: ```javascript // Server-side (Node.js example) // The POST body contains: hpay_forwarded_payment_response = JSON string const result = JSON.parse(req.body.hpay_forwarded_payment_response); // result is the same structure as e.hpay_response from onHPayResult ``` > Implement **both** the event handler (Step 5A) and the POST-back handler (Step 5B). Which one fires depends on the payment method the buyer chooses — you cannot predict it at build time. #### C — Webhook topics, panel URL, and `notify_url` override If server-to-server notifications are needed, configure panel setting: - `I(P|S|F|I)N - Link za instant notifikacije - plaćanje/isporuka/fiskal/integracije` - `I(P|S|F|I)N - Instant payment/shipping/fiscal/integation notification url` If request payload includes `notify_url`, it overrides panel-level `I(P|S|F|I)N` URL for that request. HPay appends query string parameter `topic` and sends POST JSON. `topic` can be: - `payresult` — same shape as `onHPayResult` / `https://apps.holest.com/holest-pay/response_sample.json` - `orderupdate` — root includes `order_uid`, `status`, `vhash`; payload fields are the same as `payresult`; and has `order` property with HolestPay order object in the same format as `ord` from `HPay.getOrder(order_uid).then(ord => {...})` (`https://apps.holest.com/holest-pay/hpay_order_sample.json`) (`"id"` is ID from HPay system); validate `vhash` the same way as `payresult` - `posconfig-updated` — contains POS object (`HPay.POS` format plus non-public fields), `environment`, and `checkstr = md5(${merchant_site_uid}${secret_token})` Important payload mapping note: - Request and response payloads are similar in shape; response usually contains request fields plus normalization and additional result fields. - Hash field names are different by direction: request -> `verificationhash`, response -> `vhash`. - `order` payload is a different model (same as `HPay.getOrder(...)` `ord` object), so do not map it as request/response. - Example key differences: - request/response `order_uid`, `order_amount`, `order_currency` -> order object `Uid`, `Amount`, `Currency` - request/response `order_items`, `order_billing`, `order_shipping` -> order object `Data.items`, `Data.billing`, `Data.shipping` - fiscal method specific data -> `order.FiscalData[fiscal_method_uid] = {...}` (module-specific payload) - integration method data -> `order.Data[integr_method_uid] = {...}` (may exist or may be empty/missing) - shipping method data -> `order.ShippingData[real_or_temp_shipping_code] = { method_uid: shipping_method_uid, ... }` The same result may arrive from browser callback and webhook; use `vhash` (plus order/transaction IDs) to prevent duplicate processing. #### D — Redirect POST-back parse robustness For redirect methods, HPay can return result via: ```html
``` If `JSON.parse` fails on first try, normalize escaped payload and retry: ```javascript function parseForwardedHPayResponse(raw) { if (!raw) return null; if (typeof raw === 'object') return raw; try { return JSON.parse(raw); } catch (_) {} const unescaped = String(raw).replace(/\\\\\"/g, '"').replace(/\\\\\\\\/g, '\\'); try { return JSON.parse(unescaped); } catch (_) {} return null; } ``` --- ### Step 6 — Display HTML Receipts on Thank-You Page On the thank-you page, always render data in this order: 1) `transaction_user_info` block first 2) `payment_html`, `fiscal_html`, `shipping_html`, `integr_html` blocks For bank production approval, thank-you page must also show complete order summary for all outcomes (success, failed, awaiting payment): - buyer/customer identity data - billing and email data - shipping data - order number - ordered products list with quantity, unit price, and line totals - shipping cost - payment method name and shipping method name - grand total amount If any field is missing in response, keep the block visible and show a placeholder message. Create containers for transaction details and each receipt type: ```html
``` ```javascript function renderTransactionUserInfo(info, keyMap) { const host = document.getElementById('hpay-transaction-user-info'); if (!host) return; host.innerHTML = ''; if (!info || typeof info !== 'object' || !Object.keys(info).length) { host.innerHTML = '

Transaction details are not available.

'; return; } const dl = document.createElement('dl'); Object.entries(info).forEach(([k, v]) => { const dt = document.createElement('dt'); const dd = document.createElement('dd'); dt.textContent = keyMap[k] || k; // keys can be translated dd.textContent = String(v ?? ''); // values must stay original dl.appendChild(dt); dl.appendChild(dd); }); host.appendChild(dl); } renderTransactionUserInfo(r.transaction_user_info, { 'Order UID': 'Order UID', 'Payment Status': 'Payment Status', 'Transaction Time': 'Transaction Time', 'Amount in order currency': 'Amount in order currency', 'Amount in payment currency': 'Amount in payment currency', 'Bank Account': 'Bank Account', 'REF MOD97 PNB': 'REF MOD97 PNB', 'Purphose': 'Purpose' }); const FALLBACK_HTML = '

Not available for this payment.

'; document.getElementById('hpay-receipt-payment').innerHTML = r.payment_html || FALLBACK_HTML; document.getElementById('hpay-receipt-fiscal').innerHTML = r.fiscal_html || FALLBACK_HTML; document.getElementById('hpay-receipt-shipping').innerHTML = r.shipping_html || FALLBACK_HTML; document.getElementById('hpay-receipt-integr').innerHTML = r.integr_html || FALLBACK_HTML; ``` Example `transaction_user_info` payload: ```json { "transaction_user_info": { "Order UID": "NIPI-1777290504591-8X6YD2", "Payment Status": "AWAITING", "Transaction Time": "2026-04-27 13:48:27.847Z", "Amount in order currency": "1360.00 RSD", "Amount in payment currency": "1360.00 RSD", "Bank Account": "160-6000002552312-02", "REF MOD97 PNB": "(97) 2726042713", "Purphose": "Order npinipi17772905045918x6yd2" } } ``` Rule: keys may be translated for UI labels, but values should be displayed exactly as received. If any section is missing, render a visible placeholder instead of hiding the section. For `AWAITING` and `OBLIGATED`, always render `payment_html` on the thank-you page. These are not failed statuses; they are commonly used for account/invoice payment instructions (bank transfer details). Cart handling rule: clear cart for `PAID`, `RESERVED`, `PAYING`, `AWAITING`, and `OBLIGATED` (same cart behavior for all these statuses). --- ### Step 7 — Verify Response `vhash` on Server (Node.js) Important naming: - request to HPay (`pay_request` / `charge_request`) -> field `verificationhash` -> generate with `generatePOSRequestSignature(...)` - response from HPay (browser callback / webhook) -> field `vhash` -> validate with `verifyHPayResponse(...)` Always verify response `vhash` server-side before marking order as paid/fulfilled. ```javascript const crypto = require('crypto'); const md5 = require('md5'); function generatePOSRequestSignature(merchant_site_uid, secretKey, payload) { const amount = Number(payload.order_amount ?? 0).toFixed(8); const src = String(payload.transaction_uid ?? '').trim() + '|' + String(payload.status ?? '').trim() + '|' + String(payload.order_uid ?? '').trim() + '|' + amount + '|' + String(payload.order_currency ?? '').trim() + '|' + String(payload.vault_token_uid ?? '').trim() + '|' + String(payload.subscription_uid ?? '').trim() + String(payload.rand ?? '').trim(); const srcMd5 = md5(src + merchant_site_uid); return crypto.createHash('sha512').update(srcMd5 + secretKey).digest('hex').toLowerCase(); } function verifyHPayResponse(result, merchant_site_uid, secretKey) { if (!result || !result.vhash) return false; if (!result.order_uid || !String(result.order_uid).trim()) return false; const expected = generatePOSRequestSignature(merchant_site_uid, secretKey, { transaction_uid: result.transaction_uid ?? '', status: result.status ?? '', order_uid: result.order_uid, order_amount: result.order_amount ?? 0, order_currency: result.order_currency ?? '', vault_token_uid: result.vault_token_uid ?? '', subscription_uid: result.subscription_uid ?? '', rand: result.rand ?? '' }); return expected === String(result.vhash).toLowerCase(); } ``` --- ## Optional — Advanced: Backend Charges (Server-Side, Subscriptions / MIT) > **Skip this section** unless the user explicitly asked for subscriptions or automatic recurring charges. This is used by a small fraction of integrations. The standard checkout flow (Steps 1–6—6) is completely independent of this. ### What it is A backend charge lets your **server** silently charge a customer's saved card without any buyer interaction — no payment form, no redirect. This is used for: - Recurring subscription billing (charge every month automatically) - MIT (Merchant Initiated Transactions) — charging after service delivery ### Prerequisites for backend charge - A payment method with `pm.SubsciptionsType` containing `"cof"` or `"mit"` must be active on the POS - `pm.POps` must contain `"charge"` for that method - A `vault_token_uid` saved from a previous successful checkout (from `r.vault_token_uid` in `onHPayResult`) must exist in your database for that customer - **Merchant Site UID** and **Merchant Site Secret Key** (server-side only) ### How the token gets saved During a normal checkout (Step 5), if card saving was enabled (`cof: 'optional'|'required'`), the `onHPayResult` response will contain a `vault_token_uid`. You **must save this to your database** linked to the user's account. The backend charge uses this token later. ### Backend charge request (Node.js) ```javascript // SERVER-SIDE ONLY — never run this on the frontend const crypto = require('crypto'); const md5 = require('md5'); // Signature function — required to authenticate the charge request function generatePOSRequestSignature(merchant_site_uid, secretKey, request) { const amt = parseFloat(request.order_amount || 0).toFixed(8); let cstr = [request.transaction_uid, request.status, request.order_uid, amt, request.order_currency, request.vault_token_uid, request.subscription_uid].map(v => String(v || '').trim()).join('|'); cstr += String(request.rand || '').trim(); return crypto.createHash('sha512') .update(md5(cstr + merchant_site_uid) + secretKey) .digest('hex').toLowerCase(); } // charge_request has same structure as pay_request but: // - merchant_site_uid IS required (backend operation) // - vault_token_uid IS required (the saved token from your DB) // - order_user_url is NOT needed (no buyer to redirect) // - cof is NOT needed const charge_request = { merchant_site_uid: MERCHANT_SITE_UID, // from config — never hardcode order_uid: 'ORDER-20260425-001', // unique per charge attempt order_amount: '15000', order_currency: 'RSD', payment_method: '179', // pm.HPaySiteMethodId vault_token_uid: 'saved-token-from-db', // from your database for this customer }; charge_request.verificationhash = generatePOSRequestSignature( charge_request.merchant_site_uid, MERCHANT_SITE_SECRET, charge_request ); const BASE_URL = 'https://sandbox.pay.holest.com'; // or https://pay.holest.com for production const response = await fetch(BASE_URL + '/clientpay/charge', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(charge_request) }); const result = await response.json(); // result has same structure as e.hpay_response from onHPayResult // check result.payment_status for PAID|RESERVED|SUCCESS|PAYING|OBLIGATED|AWAITING if (/PAID|PAYING|RESERVED|OBLIGATED|AWAITING/i.test(result.payment_status)) { // charge succeeded } ``` --- ## Optional: Shipping Address Autocomplete (AdaptCheckout) If the user uses HolestPay shipping modules, some methods provide address autocomplete/suggestion UI. Call `adaptCurrentShipping()` whenever the selected shipping method changes. Pass `null` to destroy the adapter when no shipping method is selected. The selector strings map your existing checkout input fields to HolestPay's address model — **update them to match your actual input selectors**. ```javascript let adapted_checkout_destroy = null; let adapted_shipping_method_uid = null; function adaptCurrentShipping(shipping_method_uid) { try { if (shipping_method_uid) { if (shipping_method_uid === adapted_shipping_method_uid) return; const smethod = HPay.POS.shipping.find(s => s.Uid == shipping_method_uid); if (smethod && smethod.AdaptCheckout) { adapted_checkout_destroy = smethod.AdaptCheckout({ billing: { address: "#addressInput[name='address1']", // update selectors to match your inputs address_num: "#addressLine2Input[name='address2']", postcode: "#postCodeInput[name='postalCode']", city: "#cityInput[name='city']", municipality: "#provinceInput[name='stateOrProvince']", phone: "#phoneInput[name='phone']", country: "#countryCodeInput[name='countryCode']", is_company: "#companyInput[name='company']", company: "#companyInput[name='company']", company_tax_id: "", company_reg_id: "" }, shipping: { address: "#addressInput[name='shippingAddress.address1']", address_num: "#addressLine2Input[name='shippingAddress.address2']", postcode: "#postCodeInput[name='shippingAddress.postalCode']", city: "#cityInput[name='shippingAddress.city']", municipality: "#provinceInput[name='shippingAddress.stateOrProvince']", phone: "#phoneInput[name='shippingAddress.phone']", country: "#countryCodeInput[name='shippingAddress.countryCode']", is_company: "#companyInput[name='shippingAddress.company']", company: "#companyInput[name='shippingAddress.company']", company_tax_id: "", company_reg_id: "" } }) || null; adapted_shipping_method_uid = shipping_method_uid; } } else { if (adapted_checkout_destroy) { adapted_checkout_destroy(); adapted_checkout_destroy = null; adapted_shipping_method_uid = null; } } } catch(ex) { console.error(ex); } } ``` --- ## No Backend Needed for Basic Checkout If the site runs on Shopify, BigCommerce, or any platform where you cannot run custom server code, the FrontCore flow (Steps 1–6—6) is fully self-contained — no backend is required for standard checkout. Backend code is only needed if you implement: - **Backend charges** (subscription / MIT auto-charge) - **Admin operations** (refunds, captures, etc.) - **Webhook verification** (verify response `vhash` from `notify_url` payload) For webhooks and backend operations you also need the **Merchant Site Secret Key** (from HPay panel ? Site Settings). --- ## Checklist - [ ] FrontCore `