{"id":6655,"date":"2026-05-09T15:12:28","date_gmt":"2026-05-09T15:12:28","guid":{"rendered":"https:\/\/ecommerce.holest.com\/?p=6655"},"modified":"2026-05-09T15:41:41","modified_gmt":"2026-05-09T15:41:41","slug":"holestpay-frontcore-vodic-za-lovable-i-slicne-ai-sisteme-za-izgradnju-sajtova","status":"publish","type":"post","link":"https:\/\/ecommerce.holest.com\/en\/holestpay-frontcore-vodic-za-lovable-i-slicne-ai-sisteme-za-izgradnju-sajtova\/","title":{"rendered":"HolestPay FrontCore Guide for Lovable and Similar AI Site Builder Systems"},"content":{"rendered":"<p>Tell Lovable (or similar system&#8230;) that you want to integrate HolestPay payments\/fiscal\/shipping and give it this MD markup: https:\/\/apps.holest.com\/holest-pay\/Lovable_or_similar_ai_system.MD.txt<br \/>\nLovable will know then what to ask you and what to instruct you to do&#8230;<\/p>\n<p>Make sure to SET UP FIRST ALL methods you plan to use on https:\/\/sandbox.pay.holest.com\/ (payment | fiscal | shipping) and test them using &#8220;pay-by-link&#8221; (entirely off-site). If everything is configured properly, the integration will go smoothly with just a few queries. <\/p>\n<p><a href=\"https:\/\/apps.holest.com\/holest-pay\/Lovable_or_similar_ai_system.MD.txt\" target=\"_blank\" rel=\"noopener noreferrer\" data-doc-type=\"lovable\" data-integration-mode=\"javascript-only\" data-format=\"markdown-text\">HolestPay FrontCore Guide for Lovable and Similar AI Site Builder Systems &#8211; MD file&#8230;<\/a><br \/>\n<\/p>\n<pre><code>\r\n# HolestPay FrontCore Integration \u2014 Guide for Lovable \/ AI Code Generators\r\n\r\n> **Full technical reference:** https:\/\/apps.holest.com\/holest-pay\/AI_INTEGRATION_GUIDE_FRONTCORE.md.txt  \r\n> **Working sample (sandbox):** https:\/\/apps.holest.com\/holest-pay\/test\/sandbox-164-hpay-frontcore-sample.html  \r\n> (View page source and inspect `<code>` tags for real implementation examples.)\r\n>\r\n> **Sample data files \u2014 read these to understand real data structures:**\r\n> - `pos_as_read.json` \u2014 https:\/\/apps.holest.com\/holest-pay\/pos_as_read.json  \r\n>   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.**\r\n> - `response_sample.json` \u2014 https:\/\/apps.holest.com\/holest-pay\/response_sample.json  \r\n>   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.**\r\n\r\n---\r\n\r\n## ?? FIRST ACTION \u2014 Ask the User for Their FrontCore Script URL\r\n\r\n**Before writing any code, ask the user:**\r\n\r\n> *\"Please give me your HolestPay FrontCore script URL. It looks like this:*\r\n> `<script src=\"https:\/\/sandbox.pay.holest.com\/clientpay\/handlers\/pos\/YOUR-UID\/frontend-script-core.js\"><\/script>`\r\n> *Do you have it?\"*\r\n\r\n**If the user says they don't have it, or doesn't know what it is, explain:**\r\n\r\n> *\"This is a unique `<script>` tag that HolestPay generates specifically for your POS\/site. It contains your Merchant Site UID in the URL and acts as the authorization key for the JavaScript-only checkout \u2014 no backend signature is needed because of it.*\r\n>\r\n> *Here is how to get it:*\r\n> 1. Go to https:\/\/sandbox.pay.holest.com (if you are testing) or https:\/\/pay.holest.com (if you are going live). Create an account if you don't have one.\r\n> 2. Create a **company** on the HPay panel.\r\n> 3. Create a **POS \/ site** for that company.\r\n> 4. Add the **payment methods** you want to offer. You can test them right away using the built-in **Pay-By-Link** feature (no integration needed for that).\r\n> 5. *(Optional)* Add **fiscal**, **integration**, and\/or **shipping** modules if you need them.\r\n> 6. In the top bar, select your company and site, then go to **Site Settings**.\r\n> 7. Find the field **\"Frontend Script-Core Origins\"** and enter your site's domain (one per line, wildcards allowed \u2014 e.g. `*.mysite.com`). Save.\r\n> 8. The panel will immediately display the full `<script>` tag. Copy it and paste it here.\"*\r\n\r\n**Do not proceed with implementation until the user provides this script tag.**  \r\nOnce you have it, extract the `src` URL \u2014 that is all you need to continue.\r\n\r\n> ### ?? IMPORTANT \u2014 Tell the user this before any code is written:\r\n>\r\n> *\"Before we start the implementation, please make sure you have done the following on the HolestPay panel:*\r\n>\r\n> - ? **All payment methods** you want to offer are added to your POS and working\r\n> - ? **Shipping methods** are added and configured (if you need shipping)\r\n> - ? **Fiscal \/ integration modules** are added and configured (if you need fiscalization)\r\n> - ? **Every method has been tested using the HPay panel's Pay-By-Link feature** \u2014 this lets you create a real test payment link without any code and confirm each method actually processes correctly\r\n>\r\n> *This is critical. If a payment method is missing, misconfigured, or untested on the HPay panel, the implementation here will point in the wrong direction and you will waste time debugging something that is actually a panel configuration problem, not a code problem. Fix the HPay panel first, then come back here.\"*\r\n\r\nThen ask the user the following **before starting to build**:\r\n\r\n> *\"A few things to know before we start:*\r\n>\r\n> - **Existing payment and shipping methods on your site do not need to be removed.** HolestPay payment and shipping methods are added **alongside** whatever you already have. You can keep PayPal, Stripe, manual bank transfer, COD \u2014 all of it \u2014 and HolestPay methods appear as additional options in the same selectors.\r\n>\r\n> - **Tip:** HolestPay also supports defining **generic payment methods** directly in the HPay panel \u2014 cash on delivery (COD), manual bank transfer, and other custom manual methods. If you want everything managed in one place through HolestPay (instead of mixing HolestPay with your platform's built-in methods), that is possible. Just add those methods on the HPay panel as well. But this is entirely optional \u2014 you decide what goes through HolestPay and what doesn't.\r\n>\r\n> *Do you also need:*\r\n> - ?? **Shipping modules** \u2014 HolestPay can provide shipping method selection with carrier integrations, address autocomplete, and shipping labels\/receipts. Do you have shipping methods configured on your HPay POS?\r\n> - ?? **Fiscalization** \u2014 HolestPay can issue fiscal receipts automatically after payment (required by law in some countries). Do you have a fiscal module configured on your HPay POS?\"*\r\n\r\n- ?? **Subscriptions \/ card saving** \u2014 HolestPay can save a card token after the first payment so the buyer doesn't need to re-enter card details next time, or for automatic recurring charges. **Note: not all payment methods support this** \u2014 only methods where `pm.SubsciptionsType` contains `\"cof\"` or `\"mit\"` do. Do you plan to offer subscriptions or saved-card checkout?\r\n\r\n- ?? **Backend admin commands (refunds, captures, cancellations, etc.)** \u2014 HolestPay provides admin operations that can be triggered from your order detail \/ order list pages (e.g. capture a reservation, issue a refund, resend a fiscal receipt). These require the **Merchant Site Secret Key** on the server side.\r\n  - **If the site runs on Shopify, BigCommerce, or a similar hosted platform** \u2014 skip this, backend is not needed.\r\n  - **If you are building a custom backend or the user's platform allows custom server code** \u2014 ask: *\"Do you want admin payment actions (refund, capture, cancel, etc.) available on your order detail or order list pages?\"*\r\n\r\n- ?? **Shopify payment method name parity (Shopify only)** \u2014 If the user is on Shopify, ask them to create a custom\/manual Shopify payment method with the **exact same name** as configured in HolestPay admin. If the name is changed later, it must be updated in **both** Shopify and HolestPay admin to stay aligned.\r\n\r\n- ?? **Shopify shipping method\/price parity (Shopify only)** \u2014 If the user is on Shopify, ask them to configure Shopify shipping rates using the **same shipping method names** as in HolestPay POS, and keep names synchronized in both systems if they are renamed.\r\n\r\n- ?? **Footer bank\/card\/3DS logotypes** \u2014 Do you want us to implement the footer branding strip with card logos, bank logos, and 3DS logos sourced from HolestPay POS parameters (as required by banks for production approval)? These logotypes should be visible in the site footer on **all site pages**, not only on checkout.\r\n\r\n- ?? **Terms of Service source strategy** \u2014 Do you want to use the HolestPay-provided Terms of Service page directly, compare it and merge equivalent clauses into your existing Terms page, or handle Terms in another way?\r\n\r\n- ?? **Checkout acceptance checkbox** \u2014 Do you need an `I accept Terms of Service` checkbox on checkout, where `Terms of Service` is clickable (opens your TOS page or modal)?\r\n\r\nImplement shipping, fiscalization, subscription\/card-saving, and backend admin commands **only if the user confirms they need them.** If unsure, tell them they can add it later \u2014 the POS configuration drives what is available (`client.POS.shipping`, `client.POS.fiscal`, `pm.SubsciptionsType`, `pm.POps`) and nothing breaks if a feature is not configured.\r\n\r\n---\r\n\r\n## What FrontCore Is\r\n\r\nFrontCore is a **JavaScript-only** HolestPay integration. No backend signature is required for checkout \u2014 the POS-specific script URL acts as the authorization token. A secret key is only needed on the server for backend charges and admin operations.\r\n\r\n## HolestPay Order Status Format\r\n\r\n```shell\r\n[PAYMENT:payment_status][ (fmethod1_uid)_FISCAL:(fmethod1_status) [(fmethod2_uid)_FISCAL:(fmethod2_status)]...][ (imethod1_uid)_INTEGR:(imethod1_status) [(imethod2_uid)_INTEGR:(imethod2_status)]...][ (smethod1_uid)_SHIPPING:packet_no@shipping_status [(smethod2_uid)_SHIPPING:packet_no@shipping_status]...]\r\n```\r\n\r\n- ORDER OF SUB-STATUSES SECTIONS PAYMENT -> FISCAL & INTEGRATION -> SHIPPING IS IMPORTANT.\r\n- ORDER OF METHOD STATUSES WITHIN SAME SUB-STATUSES SECTION IS NOT IMPORTANT.\r\n- ONE AND ONLY ONE SPACE CHARACTER AS SUB-STATUSES SEPARATOR IS IMPORTANT.\r\n\r\n```shell\r\nPossible payment status:\r\n    SUCCESS (alias of PAID)\r\n    PAID\r\n    PAYING (partially paid, indicates all partial payments are on time; used for advance payments or multi-source payments)\r\n    AWAITING (waiting bank transfer, for example)\r\n    REFUNDED\r\n    PARTIALLY-REFUNDED\r\n    VOID\r\n    OVERDUE\r\n    RESERVED (amount is reserved but still not captured from buyer card)\r\n    EXPIRED (used with methods that have expiration)\r\n    OBLIGATED (same as AWAITING but when service delivery has started or there is legal means to guarantee payment will happen)\r\n    REFUSED\r\n    FAILED\r\n    CANCELED\r\n```\r\n\r\n`PAYMENT:payment_status` may not exist if HolestPay payment module is not used and you do not set it explicitly.\r\n\r\n```shell\r\nPossible fiscal module status:\r\n  - varies depending on module\r\n```\r\n\r\nFiscal\/Integration statuses exist only if fiscal\/integration modules add status and are executed.\r\n\r\n```shell\r\nPossible packet shipping status:\r\n    PREPARING - initial status if shipping address is OK; instructions can be submitted to courier from this status\r\n    READY - used by some companies to indicate goods are checked and ready for courier submission\r\n    SUBMITTED - request submitted to courier\r\n    DELIVERY - under delivery\r\n    DELIVERED - delivered\r\n    ERROR - error in courier API request\r\n    RESOLVING - shipping address (or something else) needs backend attention\r\n    FAILED - delivery permanently failed, or courier API refused the request\r\n    REVOKED - explicitly canceled by buyer or company\r\n```\r\n\r\nShipping statuses exist only when packets are handled by HolestPay shipping modules.\r\n\r\n### ?? FrontCore Security Trade-off \u2014 Amount Manipulation\r\n\r\nBecause everything runs on the frontend without a server-side signature, **FrontCore does not protect against amount manipulation**. A technically skilled buyer could in theory alter the `order_amount` in the JavaScript before the payment is submitted (e.g. change 3000 RSD to 30 RSD) and the payment would succeed at the tampered amount.\r\n\r\n**When this is acceptable (most cases):**\r\n- Sites selling **physical\/tangible goods** \u2014 the merchant sees 30 RSD was paid instead of 3000 RSD and simply does not ship the order. No automated fulfillment happens before a human reviews it.\r\n- Low-risk digital goods or services where order values are small or fixed.\r\n- Situations where the webhook (`notify_url`) result is verified server-side before fulfillment is triggered.\r\n\r\n**When you should use the Standard integration instead (server-side signature):**\r\n- Automatic digital fulfillment (license keys, downloads, subscriptions activated instantly)\r\n- High-value orders where manual review of every payment is not practical\r\n- Any case where the server automatically fulfills the order based solely on the payment result without a human check\r\n\r\n> **Tell the user this before implementing FrontCore:**  \r\n> *\"FrontCore is the simplest integration but it does not prevent a determined buyer from manipulating the payment amount on the frontend. For most shops selling physical goods this is fine \u2014 you simply don't ship if the paid amount doesn't match the order. If your site automatically delivers digital goods or activates services immediately after payment, you need the **Standard integration with server-side signature** instead \u2014 see https:\/\/apps.holest.com\/holest-pay\/AI_INTEGRATION_GUIDE_STANDARD.md.txt \u2014 which cryptographically signs each request on your server so the amount cannot be tampered with on the frontend.\"*\r\n\r\n---\r\n\r\n## What You Need from the User Before You Start\r\n\r\n**The user must provide one thing to start: their FrontCore script `<script>` tag.**\r\n\r\nIt looks like this (sandbox example):\r\n\r\n```html\r\n<script src=\"https:\/\/sandbox.pay.holest.com\/clientpay\/handlers\/pos\/07f689c5-5bc8-44b6-a563-8facc6870fab\/frontend-script-core.js\"><\/script>\r\n```\r\n\r\nThe UID segment in the URL (`07f689c5-...`) is the Merchant Site UID \u2014 it is embedded in the URL itself.\r\n\r\n**If the user confirms they need backend implementation** (admin actions, backend charges \u2014 see pre-build questions above), they must also provide:\r\n- **Merchant Site UID** \u2014 visible in HPay panel ? Site Settings (also in the FrontCore script URL)\r\n- **Merchant Site Secret Key** \u2014 visible in HPay panel ? Site Settings (keep this server-side only, never expose on frontend)\r\n\r\n### ?? Configuration values must be easily changeable by the user\r\n\r\nStore all three of these as **user-editable configuration** (environment variables, a settings screen, or a clearly marked config file) \u2014 **never hardcode them**:\r\n\r\n| Value | Where used | Why it changes |\r\n|---|---|---|\r\n| FrontCore script `src` URL | Frontend, global `<script>` tag | Different URL for sandbox vs production, or when switching POS |\r\n| Merchant Site UID | Backend charge requests, admin ops | Changes with sandbox ? production swap or different POS |\r\n| Merchant Site Secret Key | Backend only (charges, admin, webhook verification) | Changes with sandbox ? production swap or different POS |\r\n\r\nThe most common user action after initial setup is **swapping sandbox ? production** \u2014 this should require changing only these three values and nothing else.\r\n\r\n---\r\n\r\n## Integration Steps\r\n\r\n### Step 1 \u2014 Add the FrontCore Script\r\n\r\nAdd the user's script tag **once**, in a global location so it is available on all pages\/views. This is important for payment methods like Apple Pay \/ Google Pay that can be triggered from a product listing page.\r\n\r\n```html\r\n<!-- Place in global layout, e.g. <head> or before <\/body> -->\r\n<!-- USER PROVIDES THIS TAG \u2014 store src as a config value so sandbox?production swap is one edit -->\r\n<script src=\"FRONTCORE_SCRIPT_URL_FROM_USER\"><\/script>\r\n```\r\n\r\nWhen the HPay script is loaded, it also exposes these globals on `window`:\r\n- `window.presentHPayPayForm` \u2014 function\r\n- `window.HPayIsSandbox` \u2014 environment flag variable\r\n\r\nAdd a startup check to catch misconfiguration early:\r\n\r\n```javascript\r\n\/\/ After page load \u2014 warn developer if FrontCore failed to initialize\r\nsetTimeout(function() {\r\n  if (typeof HolestPayCheckout === 'undefined') {\r\n    console.error(\r\n      'HolestPay FrontCore script did not load. ' +\r\n      'Check that the current origin is listed in \"Frontend Script-Core Origins\" in the HPay panel.'\r\n    );\r\n  }\r\n}, 5000);\r\n```\r\n\r\n---\r\n\r\n### Step 2 \u2014 Initialize HPay and Load Payment\/Shipping Methods\r\n\r\nCall `HPayInit()` once when the checkout page loads (or when the user reaches it). It returns a Promise.\r\n\r\n- `merchant_site_uid` and environment (`sandbox`\/`production`) are **not** parameters \u2014 they come from the script URL automatically.\r\n- Language is optional \u2014 if omitted, HPay uses the `<html lang=\"...\">` attribute or the language set in HPay panel POS settings.\r\n\r\n```javascript\r\n\/\/ Save this after HPayInit so it can be used in charge_request and admin ops later\r\nlet hpayMerchantSiteUid = null;\r\n\r\nHPayInit(\/* language optional, e.g. 'en' *\/).then(async client => {\r\n  hpayMerchantSiteUid = client.MerchantsiteUid;\r\n\r\n  \/\/ Filter available methods by buyer's country (recommended)\r\n  const country = 'RS'; \/\/ use actual buyer country, ISO 3166-1 alpha-2\r\n  let availablePayment = [], availableShipping = [];\r\n  try { availablePayment  = await HPay.availablePaymentMethods(country, orderAmount, orderCurrency); } catch(e) {}\r\n  try { availableShipping = await HPay.availableShippingMethods(country, orderAmount, orderCurrency); } catch(e) {}\r\n\r\n  \/\/ Populate payment method selector\r\n  client.POS.payment.forEach(pm => {\r\n    if (!pm.Hidden && (!availablePayment.length || availablePayment.find(m => m.Uid == pm.Uid))) {\r\n      \/\/ Add pm to your UI selector\r\n      \/\/ pm.HPaySiteMethodId ? use as pay_request.payment_method\r\n      \/\/ pm.Name             ? display name (use this \u2014 do NOT invent a name)\r\n      \/\/ pm.SubsciptionsType ? contains \"cof\" or \"mit\" ? card saving is supported for this method\r\n      \/\/ pm.POps             ? e.g. \"charge,refund\" ? backend operations available\r\n      \/\/ pm.PayInputUrl      ? if set, this method supports docking (embedded payment input)\r\n      \/\/ pm['Use IFRAME']    ? if false, method uses redirect flow (bank page POST redirect)\r\n    }\r\n  });\r\n\r\n  \/\/ Populate shipping method selector (if POS has shipping configured)\r\n  if (client.POS.shipping) {\r\n    client.POS.shipping.forEach(sm => {\r\n      if (!sm.Hidden && (!availableShipping.length || availableShipping.find(m => m.Uid == sm.Uid))) {\r\n        \/\/ sm.HPaySiteMethodId ? use as pay_request.shipping_method\r\n        \/\/ sm.Name             ? display name\r\n      }\r\n    });\r\n  }\r\n});\r\n```\r\n\r\n> **Make sure existing payment methods in your UI have a name and description.** Use `pm.Name` from the POS config \u2014 do not hardcode or invent names.\r\n\r\n---\r\n\r\n### Step 3 \u2014 Build the `pay_request` and Initiate Payment\r\n\r\n```javascript\r\nconst pay_request = {\r\n  \/\/ NOTE: merchant_site_uid is NOT included here for FrontCore \u2014 the script handles auth automatically\r\n  hpaylang: 'en',                                \/\/ optional\r\n  order_uid: 'ORDER-20260425-001',               \/\/ required \u2014 unique per order\r\n  order_name: '#Order 204',                      \/\/ optional\r\n  order_amount: '15000.00',                         \/\/ required \u2014 string, in smallest currency unit or decimal\r\n  order_currency: 'RSD',                         \/\/ required \u2014 ISO 4217\r\n  payment_method: '179',                         \/\/ required \u2014 pm.HPaySiteMethodId from Step 2\r\n  shipping_method: '45',                         \/\/ optional \u2014 sm.HPaySiteMethodId\r\n  order_user_url: 'https:\/\/yoursite.com\/thanks', \/\/ recommended \u2014 redirect\/thank-you page URL\r\n  notify_url: 'https:\/\/yoursite.com\/webhook',    \/\/ optional \u2014 server-to-server webhook (must be publicly reachable)\r\n  cof: 'optional',                               \/\/ optional \u2014 'optional'|'required'|'none' \u2014 enables card saving\r\n  vault_token_uid: '',                           \/\/ optional \u2014 saved token UUID, or 1|true|new to force new token\r\n  order_billing: {                               \/\/ optional but recommended\r\n    email: 'customer@example.com',\r\n    first_name: 'TEST',\r\n    last_name: 'TEST',\r\n    phone: '+38111111111',\r\n    is_company: 0,\r\n    company: '',                                   \/\/ company legal name\r\n    company_tax_id: '',                            \/\/ company tax ID in merchant's country\r\n    company_reg_id: '',                            \/\/ company registration ID in merchant's country\r\n    address: 'TEST',                                \/\/ street name\r\n    address2: '',                                   \/\/ recommended for street number \/ address addition\r\n    city: 'Beograd',\r\n    country: 'RS',\r\n    state: 'Beograd',\r\n    postcode: '11000',\r\n    lang: 'sr_RS'                                \/\/ language from merchant platform\/system\r\n  },\r\n  order_shipping: {                              \/\/ optional\r\n    shippable: false,\r\n    is_cod: 1,                                      \/\/ set to 1 when COD logic is used\/allowed\r\n    first_name: '',\r\n    last_name: '',\r\n    phone: '',\r\n    company: '',\r\n    address: '',                                    \/\/ street name\r\n    address2: '',                                   \/\/ recommended for street number \/ address addition\r\n    city: '',\r\n    country: '',\r\n    state: '',\r\n    postcode: ''\r\n  },\r\n  order_items: [                                  \/\/ strongly recommended for reconciliation\r\n    {\r\n      posuid: 114,                                           \/\/ merchant's own internal item ID (string or number)\r\n      type: 'product',\r\n      name: 'Sample product name',\r\n      sku: '000550',\r\n      qty: 1,\r\n      price: 4695.99,\r\n      subtotal: 4695.99,\r\n      tax_label: '',\r\n      tax_amount: 0,\r\n      length: '',                                          \/\/ always in centimeters (cm)\r\n      width: '',                                           \/\/ always in centimeters (cm)\r\n      height: '',                                          \/\/ always in centimeters (cm)\r\n      weight: '',                                          \/\/ always in grams (g)\r\n      split_pay_uid: '',\r\n      virtual: true,\r\n      tax_percent: 0\r\n    }\r\n  ]\r\n};\r\n\r\n\/\/ Remove empty fields before sending\r\nObject.keys(pay_request).forEach(k => { if (pay_request[k] === '') delete pay_request[k]; });\r\n\r\n\/\/ Initiate payment \u2014 shows modal or triggers redirect depending on payment method\r\nHPay.presentHPayPayForm(pay_request);\r\n```\r\n\r\n**Important \u2014 `order_items` field naming must match HolestPay template keys:**\r\n\r\n- Use `name`, not `title`\r\n- Use `posuid`, not `variantId`\r\n- Use `qty`, not `quantity`\r\n- `subtotal` is mandatory for each item line\r\n- `posuid` can be any identifier from the merchant's system (SKU\/variant\/product\/internal DB ID)\r\n\r\nIf source platform fields are Shopify-style, map them explicitly before sending:\r\n- `variantId -> posuid`\r\n- `title -> name`\r\n- `quantity -> qty`\r\n- top-level `items -> order_items`\r\n\r\nThe same order payload structure is used across all three markups\/docs (Lovable prompt, FrontCore guide, Standard guide).\r\nAddress convention recommendation: use `address` for street name and `address2` for street number\/additional address details.\r\n\r\n---\r\n\r\n### Step 4 \u2014 Docking (Embedded Payment Input)\r\n\r\nSome payment methods support an embedded payment input directly in the page (e.g. card form inline). Check `pm.PayInputUrl` \u2014 if it is set, docking is supported for that method.\r\n\r\nCall `HPay.setPaymentMethodDock()` **when the user selects a payment method or when any checkout field changes** (amount, currency, etc.).\r\n\r\n```html\r\n<!-- Place dock container below payment method description in your checkout UI -->\r\n<div id=\"paymentMethodDock\" style=\"max-width:460px;\"><\/div>\r\n```\r\n\r\n```css\r\n#paymentMethodDock { background: #ffffff9e; }\r\n```\r\n\r\n```javascript\r\nfunction updateDock() {\r\n  const selectedPm = \/* pm object for selected payment method *\/;\r\n  if (selectedPm && selectedPm.PayInputUrl) {\r\n    HPay.setPaymentMethodDock(\r\n      pay_request.payment_method,\r\n      {\r\n        order_amount:         pay_request.order_amount,\r\n        order_currency:       pay_request.order_currency,\r\n        monthly_installments: null,\r\n        vault_token_uid:      pay_request.vault_token_uid || null,\r\n        hpaylang:             pay_request.hpaylang,\r\n        cof:                  pay_request.cof\r\n      },\r\n      document.getElementById('paymentMethodDock')\r\n    );\r\n  } else {\r\n    document.getElementById('paymentMethodDock').innerHTML = '';\r\n  }\r\n}\r\n```\r\n\r\n---\r\n\r\n### Step 5 \u2014 Handle Results\r\n\r\n#### A \u2014 Event handler (iframe \/ modal methods)\r\n\r\nMost payment methods return the result via this event, fired on the current page:\r\n\r\n```javascript\r\ndocument.addEventListener('onHPayResult', function(e) {\r\n  const r = e.hpay_response;\r\n  if (!r) return;\r\n\r\n  if (r.error && r.error.code) {\r\n    \/\/ Payment error \u2014 retry\r\n    HPay.presentHPayPayForm(pay_request);\r\n    return;\r\n  }\r\n\r\n  if (\/PAID|RESERVED|SUCCESS|PAYING|OBLIGATED|AWAITING\/i.test(r.payment_status)) {\r\n    \/\/ Payment completed or pending payment instructions (AWAITING\/OBLIGATED are NOT failed)\r\n    \/\/ Clear cart for PAID\/RESERVED and also for PAYING\/AWAITING\/OBLIGATED.\r\n\r\n    \/\/ Display HTML receipts in dedicated containers on your thank-you page:\r\n    \/\/ r.payment_html  ? payment receipt HTML\r\n    \/\/ r.fiscal_html   ? fiscal receipt HTML (if fiscal module active)\r\n    \/\/ r.integr_html   ? integration module HTML\r\n    \/\/ r.shipping_html ? shipping label\/receipt HTML (if shipping module active)\r\n    \/\/ r.transaction_user_info ? object with card brand, masked number, etc.\r\n\r\n    if (r.vault_token_uid) {\/\/only if card save is on for some reason subscription or simply token save for faster checkout\r\n      \/\/ IMPORTANT: save this to your database linked to the user account \u2014 do NOT only store in browser\r\n      const saveCardData = {\r\n        vault_token_uid:   r.vault_token_uid,    \/\/e.g. hJ0khUi67856765rtyrytrytry 12 up to 128 characters\r\n        vault_card_brand:  r.vault_card_brand,   \/\/ e.g. \"MASTERCARD\"\r\n        vault_card_umask:  r.vault_card_umask,   \/\/ e.g. \"544358******4639\"\r\n        vault_exp:         r.vault_exp,          \/\/ e.g. \"12\/26\"\r\n        vault_scope:       r.vault_scope,        \/\/ e.g. can be Terminal ID fro payment method config or soemthinglike that\r\n        vault_onlyforuser: r.vault_onlyforuser,  \/\/subscription falsy | fast checkout 0 \r\n        pay_method_uid:    r.pay_method_uid      \/\/Uid of payment method from HPay.POS.payment[N].Uid\r\n      };\r\n      \/\/ POST saveCardData to your backend\r\n    }\r\n\r\n    \/\/ Redirect to thank-you page if needed:\r\n    \/\/ window.location.href = r.order_user_url;\r\n  }\r\n\r\n  \/\/ r.status ? order status (always present)\r\n});\r\n\r\ndocument.addEventListener('onHPayPanelClose', function(e) {\r\n  const r = e.hpay_response; \/\/ null if user closed without completing\r\n  const reason = String((r && r.reason) || '').toLowerCase();\r\n\r\n  \/\/ If pay button was locked during payment start, unlock it on close reasons below.\r\n  if (\/^(user|timeout|cancel|error)$\/.test(reason)) {\r\n    const payBtn = document.getElementById('do-pay');\r\n    if (payBtn) payBtn.disabled = false;\r\n  }\r\n\r\n  if (r && r.reason === '' && \/* user wants retry *\/ false) {\r\n    setTimeout(() => HPay.presentHPayPayForm(pay_request), 300);\r\n  }\r\n});\r\n```\r\n\r\n#### B \u2014 POST-back redirect (redirect methods)\r\n\r\nSome 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.\r\n\r\nOn `order_user_url` (your thank-you\/return page), read the result from the POST body:\r\n\r\n```javascript\r\n\/\/ Server-side (Node.js example)\r\n\/\/ The POST body contains: hpay_forwarded_payment_response = JSON string\r\nconst result = JSON.parse(req.body.hpay_forwarded_payment_response);\r\n\/\/ result is the same structure as e.hpay_response from onHPayResult\r\n```\r\n\r\n> 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 \u2014 you cannot predict it at build time.\r\n\r\n#### C \u2014 Webhook topics, panel URL, and `notify_url` override\r\n\r\nIf server-to-server notifications are needed, configure panel setting:\r\n- `I(P|S|F|I)N - Link za instant notifikacije - pla\u0107anje\/isporuka\/fiskal\/integracije`\r\n- `I(P|S|F|I)N - Instant payment\/shipping\/fiscal\/integation notification url`\r\n\r\nIf request payload includes `notify_url`, it overrides panel-level `I(P|S|F|I)N` URL for that request.\r\n\r\nHPay appends query string parameter `topic` and sends POST JSON.\r\n\r\n`topic` can be:\r\n- `payresult` \u2014 same shape as `onHPayResult` \/ `https:\/\/apps.holest.com\/holest-pay\/response_sample.json`\r\n- `orderupdate` \u2014 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`\r\n- `posconfig-updated` \u2014 contains POS object (`HPay.POS` format plus non-public fields), `environment`, and `checkstr = md5(${merchant_site_uid}${secret_token})`\r\n\r\nImportant payload mapping note:\r\n- Request and response payloads are similar in shape; response usually contains request fields plus normalization and additional result fields.\r\n- Hash field names are different by direction: request -> `verificationhash`, response -> `vhash`.\r\n- `order` payload is a different model (same as `HPay.getOrder(...)` `ord` object), so do not map it as request\/response.\r\n- Example key differences:\r\n  - request\/response `order_uid`, `order_amount`, `order_currency` -> order object `Uid`, `Amount`, `Currency`\r\n  - request\/response `order_items`, `order_billing`, `order_shipping` -> order object `Data.items`, `Data.billing`, `Data.shipping`\r\n  - fiscal method specific data -> `order.FiscalData[fiscal_method_uid] = {...}` (module-specific payload)\r\n  - integration method data -> `order.Data[integr_method_uid] = {...}` (may exist or may be empty\/missing)\r\n  - shipping method data -> `order.ShippingData[real_or_temp_shipping_code] = { method_uid: shipping_method_uid, ... }`\r\n\r\nThe same result may arrive from browser callback and webhook; use `vhash` (plus order\/transaction IDs) to prevent duplicate processing.\r\n\r\n#### D \u2014 Redirect POST-back parse robustness\r\n\r\nFor redirect methods, HPay can return result via:\r\n\r\n```html\r\n<form method='POST' id='frmRedirect' action='${order_user_url}'>\r\n  <input type='hidden' name='hpay_forwarded_payment_response' id='hpay_response' \/>\r\n<\/form>\r\n<script nonce='${csp_nonce}'>\r\n  document.getElementById('hpay_response').value = JSON.stringify(hpay_result);\r\n  document.getElementById('frmRedirect').submit();\r\n<\/script>\r\n```\r\n\r\nIf `JSON.parse` fails on first try, normalize escaped payload and retry:\r\n\r\n```javascript\r\nfunction parseForwardedHPayResponse(raw) {\r\n  if (!raw) return null;\r\n  if (typeof raw === 'object') return raw;\r\n  try { return JSON.parse(raw); } catch (_) {}\r\n  const unescaped = String(raw).replace(\/\\\\\\\\\\\"\/g, '\"').replace(\/\\\\\\\\\\\\\\\\\/g, '\\\\');\r\n  try { return JSON.parse(unescaped); } catch (_) {}\r\n  return null;\r\n}\r\n```\r\n\r\n---\r\n\r\n### Step 6 \u2014 Display HTML Receipts on Thank-You Page\r\n\r\nOn the thank-you page, always render data in this order:\r\n1) `transaction_user_info` block first  \r\n2) `payment_html`, `fiscal_html`, `shipping_html`, `integr_html` blocks\r\n\r\nFor bank production approval, thank-you page must also show complete order summary for all outcomes (success, failed, awaiting payment):\r\n- buyer\/customer identity data\r\n- billing and email data\r\n- shipping data\r\n- order number\r\n- ordered products list with quantity, unit price, and line totals\r\n- shipping cost\r\n- payment method name and shipping method name\r\n- grand total amount\r\n\r\nIf any field is missing in response, keep the block visible and show a placeholder message.\r\n\r\nCreate containers for transaction details and each receipt type:\r\n\r\n```html\r\n<div id=\"hpay-transaction-user-info\"><\/div> <!-- translated keys, original values -->\r\n<div id=\"hpay-receipt-payment\"><\/div>  <!-- payment receipt -->\r\n<div id=\"hpay-receipt-fiscal\"><\/div>   <!-- fiscal receipt (white background recommended for legibility) -->\r\n<div id=\"hpay-receipt-integr\"><\/div>   <!-- integration module output -->\r\n<div id=\"hpay-receipt-shipping\"><\/div> <!-- shipping label \/ receipt -->\r\n```\r\n\r\n```javascript\r\nfunction renderTransactionUserInfo(info, keyMap) {\r\n  const host = document.getElementById('hpay-transaction-user-info');\r\n  if (!host) return;\r\n  host.innerHTML = '';\r\n  if (!info || typeof info !== 'object' || !Object.keys(info).length) {\r\n    host.innerHTML = '<p class=\"hpay-placeholder\">Transaction details are not available.<\/p>';\r\n    return;\r\n  }\r\n  const dl = document.createElement('dl');\r\n  Object.entries(info).forEach(([k, v]) => {\r\n    const dt = document.createElement('dt');\r\n    const dd = document.createElement('dd');\r\n    dt.textContent = keyMap[k] || k;  \/\/ keys can be translated\r\n    dd.textContent = String(v ?? ''); \/\/ values must stay original\r\n    dl.appendChild(dt);\r\n    dl.appendChild(dd);\r\n  });\r\n  host.appendChild(dl);\r\n}\r\n\r\nrenderTransactionUserInfo(r.transaction_user_info, {\r\n  'Order UID': 'Order UID',\r\n  'Payment Status': 'Payment Status',\r\n  'Transaction Time': 'Transaction Time',\r\n  'Amount in order currency': 'Amount in order currency',\r\n  'Amount in payment currency': 'Amount in payment currency',\r\n  'Bank Account': 'Bank Account',\r\n  'REF MOD97 PNB': 'REF MOD97 PNB',\r\n  'Purphose': 'Purpose'\r\n});\r\n\r\nconst FALLBACK_HTML = '<p class=\"hpay-placeholder\">Not available for this payment.<\/p>';\r\ndocument.getElementById('hpay-receipt-payment').innerHTML  = r.payment_html  || FALLBACK_HTML;\r\ndocument.getElementById('hpay-receipt-fiscal').innerHTML   = r.fiscal_html   || FALLBACK_HTML;\r\ndocument.getElementById('hpay-receipt-shipping').innerHTML = r.shipping_html || FALLBACK_HTML;\r\ndocument.getElementById('hpay-receipt-integr').innerHTML   = r.integr_html   || FALLBACK_HTML;\r\n```\r\n\r\nExample `transaction_user_info` payload:\r\n\r\n```json\r\n{\r\n  \"transaction_user_info\": {\r\n    \"Order UID\": \"NIPI-1777290504591-8X6YD2\",\r\n    \"Payment Status\": \"AWAITING\",\r\n    \"Transaction Time\": \"2026-04-27 13:48:27.847Z\",\r\n    \"Amount in order currency\": \"1360.00 RSD\",\r\n    \"Amount in payment currency\": \"1360.00 RSD\",\r\n    \"Bank Account\": \"160-6000002552312-02\",\r\n    \"REF MOD97 PNB\": \"(97) 2726042713\",\r\n    \"Purphose\": \"Order npinipi17772905045918x6yd2\"\r\n  }\r\n}\r\n```\r\n\r\nRule: 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.\r\n\r\nFor `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).\r\nCart handling rule: clear cart for `PAID`, `RESERVED`, `PAYING`, `AWAITING`, and `OBLIGATED` (same cart behavior for all these statuses).\r\n\r\n---\r\n\r\n### Step 7 \u2014 Verify Response `vhash` on Server (Node.js)\r\n\r\nImportant naming:\r\n- request to HPay (`pay_request` \/ `charge_request`) -> field `verificationhash` -> generate with `generatePOSRequestSignature(...)`\r\n- response from HPay (browser callback \/ webhook) -> field `vhash` -> validate with `verifyHPayResponse(...)`\r\n\r\nAlways verify response `vhash` server-side before marking order as paid\/fulfilled.\r\n\r\n```javascript\r\nconst crypto = require('crypto');\r\nconst md5 = require('md5');\r\n\r\nfunction generatePOSRequestSignature(merchant_site_uid, secretKey, payload) {\r\n  const amount = Number(payload.order_amount ?? 0).toFixed(8);\r\n  const src =\r\n    String(payload.transaction_uid ?? '').trim() + '|' +\r\n    String(payload.status ?? '').trim() + '|' +\r\n    String(payload.order_uid ?? '').trim() + '|' +\r\n    amount + '|' +\r\n    String(payload.order_currency ?? '').trim() + '|' +\r\n    String(payload.vault_token_uid ?? '').trim() + '|' +\r\n    String(payload.subscription_uid ?? '').trim() +\r\n    String(payload.rand ?? '').trim();\r\n\r\n  const srcMd5 = md5(src + merchant_site_uid);\r\n  return crypto.createHash('sha512').update(srcMd5 + secretKey).digest('hex').toLowerCase();\r\n}\r\n\r\nfunction verifyHPayResponse(result, merchant_site_uid, secretKey) {\r\n  if (!result || !result.vhash) return false;\r\n  if (!result.order_uid || !String(result.order_uid).trim()) return false;\r\n\r\n  const expected = generatePOSRequestSignature(merchant_site_uid, secretKey, {\r\n    transaction_uid: result.transaction_uid ?? '',\r\n    status: result.status ?? '',\r\n    order_uid: result.order_uid,\r\n    order_amount: result.order_amount ?? 0,\r\n    order_currency: result.order_currency ?? '',\r\n    vault_token_uid: result.vault_token_uid ?? '',\r\n    subscription_uid: result.subscription_uid ?? '',\r\n    rand: result.rand ?? ''\r\n  });\r\n\r\n  return expected === String(result.vhash).toLowerCase();\r\n}\r\n```\r\n\r\n---\r\n\r\n## Optional \u2014 Advanced: Backend Charges (Server-Side, Subscriptions \/ MIT)\r\n\r\n> **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\u20136\u20146) is completely independent of this.\r\n\r\n### What it is\r\n\r\nA backend charge lets your **server** silently charge a customer's saved card without any buyer interaction \u2014 no payment form, no redirect. This is used for:\r\n- Recurring subscription billing (charge every month automatically)\r\n- MIT (Merchant Initiated Transactions) \u2014 charging after service delivery\r\n\r\n### Prerequisites for backend charge\r\n\r\n- A payment method with `pm.SubsciptionsType` containing `\"cof\"` or `\"mit\"` must be active on the POS\r\n- `pm.POps` must contain `\"charge\"` for that method\r\n- 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\r\n- **Merchant Site UID** and **Merchant Site Secret Key** (server-side only)\r\n\r\n### How the token gets saved\r\n\r\nDuring 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.\r\n\r\n### Backend charge request (Node.js)\r\n\r\n```javascript\r\n\/\/ SERVER-SIDE ONLY \u2014 never run this on the frontend\r\nconst crypto = require('crypto');\r\nconst md5    = require('md5');\r\n\r\n\/\/ Signature function \u2014 required to authenticate the charge request\r\nfunction generatePOSRequestSignature(merchant_site_uid, secretKey, request) {\r\n  const amt = parseFloat(request.order_amount || 0).toFixed(8);\r\n  let cstr  = [request.transaction_uid, request.status, request.order_uid,\r\n               amt, request.order_currency, request.vault_token_uid,\r\n               request.subscription_uid].map(v => String(v || '').trim()).join('|');\r\n  cstr     += String(request.rand || '').trim();\r\n  return crypto.createHash('sha512')\r\n    .update(md5(cstr + merchant_site_uid) + secretKey)\r\n    .digest('hex').toLowerCase();\r\n}\r\n\r\n\/\/ charge_request has same structure as pay_request but:\r\n\/\/   - merchant_site_uid IS required (backend operation)\r\n\/\/   - vault_token_uid IS required (the saved token from your DB)\r\n\/\/   - order_user_url is NOT needed (no buyer to redirect)\r\n\/\/   - cof is NOT needed\r\nconst charge_request = {\r\n  merchant_site_uid: MERCHANT_SITE_UID,      \/\/ from config \u2014 never hardcode\r\n  order_uid:         'ORDER-20260425-001',   \/\/ unique per charge attempt\r\n  order_amount:      '15000',\r\n  order_currency:    'RSD',\r\n  payment_method:    '179',                  \/\/ pm.HPaySiteMethodId\r\n  vault_token_uid:   'saved-token-from-db',  \/\/ from your database for this customer\r\n};\r\n\r\ncharge_request.verificationhash = generatePOSRequestSignature(\r\n  charge_request.merchant_site_uid, MERCHANT_SITE_SECRET, charge_request\r\n);\r\n\r\nconst BASE_URL = 'https:\/\/sandbox.pay.holest.com'; \/\/ or https:\/\/pay.holest.com for production\r\n\r\nconst response = await fetch(BASE_URL + '\/clientpay\/charge', {\r\n  method:  'POST',\r\n  headers: { 'Content-Type': 'application\/json' },\r\n  body:    JSON.stringify(charge_request)\r\n});\r\nconst result = await response.json();\r\n\/\/ result has same structure as e.hpay_response from onHPayResult\r\n\/\/ check result.payment_status for PAID|RESERVED|SUCCESS|PAYING|OBLIGATED|AWAITING\r\nif (\/PAID|PAYING|RESERVED|OBLIGATED|AWAITING\/i.test(result.payment_status)) {\r\n  \/\/ charge succeeded\r\n}\r\n```\r\n\r\n---\r\n\r\n## Optional: Shipping Address Autocomplete (AdaptCheckout)\r\n\r\nIf 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.\r\n\r\nThe selector strings map your existing checkout input fields to HolestPay's address model \u2014 **update them to match your actual input selectors**.\r\n\r\n```javascript\r\nlet adapted_checkout_destroy    = null;\r\nlet adapted_shipping_method_uid = null;\r\n\r\nfunction adaptCurrentShipping(shipping_method_uid) {\r\n  try {\r\n    if (shipping_method_uid) {\r\n      if (shipping_method_uid === adapted_shipping_method_uid) return;\r\n      const smethod = HPay.POS.shipping.find(s => s.Uid == shipping_method_uid);\r\n      if (smethod && smethod.AdaptCheckout) {\r\n        adapted_checkout_destroy = smethod.AdaptCheckout({\r\n          billing: {\r\n            address:         \"#addressInput[name='address1']\",       \/\/ update selectors to match your inputs\r\n            address_num:     \"#addressLine2Input[name='address2']\",\r\n            postcode:        \"#postCodeInput[name='postalCode']\",\r\n            city:            \"#cityInput[name='city']\",\r\n            municipality:    \"#provinceInput[name='stateOrProvince']\",\r\n            phone:           \"#phoneInput[name='phone']\",\r\n            country:         \"#countryCodeInput[name='countryCode']\",\r\n            is_company:      \"#companyInput[name='company']\",\r\n            company:         \"#companyInput[name='company']\",\r\n            company_tax_id:  \"\",\r\n            company_reg_id:  \"\"\r\n          },\r\n          shipping: {\r\n            address:         \"#addressInput[name='shippingAddress.address1']\",\r\n            address_num:     \"#addressLine2Input[name='shippingAddress.address2']\",\r\n            postcode:        \"#postCodeInput[name='shippingAddress.postalCode']\",\r\n            city:            \"#cityInput[name='shippingAddress.city']\",\r\n            municipality:    \"#provinceInput[name='shippingAddress.stateOrProvince']\",\r\n            phone:           \"#phoneInput[name='shippingAddress.phone']\",\r\n            country:         \"#countryCodeInput[name='shippingAddress.countryCode']\",\r\n            is_company:      \"#companyInput[name='shippingAddress.company']\",\r\n            company:         \"#companyInput[name='shippingAddress.company']\",\r\n            company_tax_id:  \"\",\r\n            company_reg_id:  \"\"\r\n          }\r\n        }) || null;\r\n        adapted_shipping_method_uid = shipping_method_uid;\r\n      }\r\n    } else {\r\n      if (adapted_checkout_destroy) {\r\n        adapted_checkout_destroy();\r\n        adapted_checkout_destroy = null;\r\n        adapted_shipping_method_uid = null;\r\n      }\r\n    }\r\n  } catch(ex) { console.error(ex); }\r\n}\r\n```\r\n\r\n---\r\n\r\n## No Backend Needed for Basic Checkout\r\n\r\nIf the site runs on Shopify, BigCommerce, or any platform where you cannot run custom server code, the FrontCore flow (Steps 1\u20136\u20146) is fully self-contained \u2014 no backend is required for standard checkout. Backend code is only needed if you implement:\r\n- **Backend charges** (subscription \/ MIT auto-charge)\r\n- **Admin operations** (refunds, captures, etc.)\r\n- **Webhook verification** (verify response `vhash` from `notify_url` payload)\r\n\r\nFor webhooks and backend operations you also need the **Merchant Site Secret Key** (from HPay panel ? Site Settings).\r\n\r\n---\r\n\r\n## Checklist\r\n\r\n- [ ] FrontCore `<script>` tag added globally (all pages\/views)\r\n- [ ] Script URL stored as a single config value (easy sandbox ? production swap)\r\n- [ ] `HPayInit()` called on checkout page load; `client.MerchantsiteUid` saved\r\n- [ ] Payment method selector populated from `client.POS.payment` using `pm.Name` and `pm.HPaySiteMethodId`\r\n- [ ] Shipping method selector populated from `client.POS.shipping` (if applicable)\r\n- [ ] `onHPayResult` event handler implemented\r\n- [ ] POST-back handler implemented on `order_user_url` page (for redirect-type methods)\r\n- [ ] Receipt containers (`payment_html`, `fiscal_html`, `integr_html`, `shipping_html`) present on result page\r\n- [ ] If card saving used: `vault_token_uid` saved to database on successful payment\r\n- [ ] Dock container present if any payment method supports docking (`pm.PayInputUrl`)\r\n- [ ] Footer logotypes rendered from `HPay.POS.pos_parameters` (cards, banks, 3DS)\r\n- [ ] TOS checkbox present near Pay button; TOS content from `\/clientpay\/tos\/<uid>`\r\n\r\n---\r\n\r\n## Required for Bank Production Approval \u2014 Logotypes and Terms of Service\r\n\r\n> ?? **This section has nothing to do with payment functionality** \u2014 payments work without it. However, **almost all banks in the region will require these elements to be present on the site before approving the POS for production use.** Implement these alongside the payment integration.\r\n\r\n---\r\n\r\n### Footer Logotypes (Card logos, Bank logos, 3DS logos)\r\n\r\nBanks require card brand logos, acquiring bank logos, and 3DS security logos to appear in the site footer \u2014 in a single horizontal line, **no taller than approximately 1 cm visually**. Order: card logos first, bank logos in the middle (with some spacing on both sides), 3DS logos on the right. Bank and 3DS logos must be linked. The footer strip must be visible across **all pages of the website**, not just the checkout page.\r\n\r\nHolestPay provides all logo image URLs and link targets via `HPay.POS.pos_parameters` after `HPayInit()`. Use them \u2014 do not source logos elsewhere.\r\n\r\n**CSS for the footer branding strip:**\r\n\r\n```css\r\n.hpay_footer_branding_wrapper {\r\n  width: 100%;\r\n  padding: 8px 0;\r\n  border-top: 1px solid #e0e0e0;\r\n}\r\n.hpay_footer_branding {\r\n  display: flex;\r\n  align-items: center;\r\n  gap: 0;\r\n  flex-wrap: nowrap;\r\n}\r\n.hpay-footer-branding-cards,\r\n.hpay-footer-branding-bank,\r\n.hpay-footer-branding-3ds {\r\n  display: flex;\r\n  align-items: center;\r\n  flex-wrap: nowrap;\r\n}\r\n.hpay-footer-branding-bank  { margin: 0 12px; }\r\n.hpay_footer_branding img   { height: 1cm; width: auto; display: inline-block; }\r\n```\r\n\r\n**JavaScript \u2014 call this after `HPayInit()` resolves:**\r\n\r\n```javascript\r\nfunction renderHPayFooterLogotypes() {\r\n  if (!(typeof HPay !== 'undefined' && HPay && HPay.POS)) return;\r\n  if (!HPay.POS.pos_parameters) return;\r\n\r\n  let card_images_html = '';\r\n  let banks_html       = '';\r\n  let threes_html      = '';\r\n\r\n  if (HPay.POS.pos_parameters['Logotypes Card Images']) {\r\n    HPay.POS.pos_parameters['Logotypes Card Images'].split('\\n').forEach(src => {\r\n      if (src.trim()) card_images_html += `<img decoding=\"async\" src=\"${src.trim()}\" alt=\"Card\" \/>`;\r\n    });\r\n  }\r\n\r\n  if (HPay.POS.pos_parameters['Logotypes Banks']) {\r\n    HPay.POS.pos_parameters['Logotypes Banks'].split('\\n').forEach(line => {\r\n      if (!line.trim()) return;\r\n      \/\/ format: \"imageUrl:linkUrl\" \u2014 colons in URLs are escaped before splitting\r\n      const t = line.replace(\/https:\/gi, '-PS-').replace(\/http:\/gi, '-P-')\r\n        .split(':').map(r => r.replace(\/-P-\/g, 'http:').replace(\/-PS-\/g, 'https:'));\r\n      banks_html += t.length > 1\r\n        ? `<a href=\"${t[1]}\" target=\"_blank\"><img decoding=\"async\" src=\"${t[0]}\" alt=\"Bank\" \/><\/a>`\r\n        : `<img decoding=\"async\" src=\"${t[0]}\" alt=\"Bank\" \/>`;\r\n    });\r\n  }\r\n\r\n  if (HPay.POS.pos_parameters['Logotypes 3DS']) {\r\n    HPay.POS.pos_parameters['Logotypes 3DS'].split('\\n').forEach(line => {\r\n      if (!line.trim()) return;\r\n      const t = line.replace(\/https:\/gi, '-PS-').replace(\/http:\/gi, '-P-')\r\n        .split(':').map(r => r.replace(\/-P-\/g, 'http:').replace(\/-PS-\/g, 'https:'));\r\n      threes_html += t.length > 1\r\n        ? `<a href=\"${t[1]}\" target=\"_blank\"><img decoding=\"async\" src=\"${t[0]}\" alt=\"3DS\" \/><\/a>`\r\n        : `<img decoding=\"async\" src=\"${t[0]}\" alt=\"3DS\" \/>`;\r\n    });\r\n  }\r\n\r\n  const logotypesDiv = document.createElement('div');\r\n  logotypesDiv.className = 'hpay_footer_branding';\r\n  logotypesDiv.innerHTML =\r\n    `<div class=\"hpay-footer-branding-cards\">${card_images_html}<\/div>` +\r\n    `<div class=\"hpay-footer-branding-bank\">${banks_html}<\/div>` +\r\n    `<div class=\"hpay-footer-branding-3ds\">${threes_html}<\/div>`;\r\n\r\n  const wrapper = document.createElement('div');\r\n  wrapper.className = 'hpay_footer_branding_wrapper';\r\n  wrapper.appendChild(logotypesDiv);\r\n\r\n  (document.querySelector('footer') || document.querySelector('main') || document.body)\r\n    .appendChild(wrapper);\r\n}\r\n\r\n\/\/ Call after HPayInit resolves:\r\n\/\/ HPayInit().then(client => { renderHPayFooterLogotypes(); });\r\n```\r\n\r\n---\r\n\r\n### Terms of Service Acceptance Checkbox\r\n\r\nAlmost all banks in the region require the customer to explicitly accept the site Terms of Service before payment \u2014 typically a checkbox with a link to the TOS content.\r\n\r\n**HolestPay provides a ready-to-use Terms of Service \/ Purchase Conditions template page for each POS\/site:**\r\n\r\n```\r\nhttps:\/\/sandbox.pay.holest.com\/clientpay\/tos\/<merchant_site_uid>?lang=rs\r\nhttps:\/\/pay.holest.com\/clientpay\/tos\/<merchant_site_uid>?lang=en\r\n```\r\n\r\nSupported `lang` values: `en`, `rs`, `bs`, `hr`, `me`, `de`, `es`, `gr`, `tr`, `mk`, and others.\r\n\r\nThis URL returns HTML content (no `<html>` wrapper) and can be:\r\n- Loaded in an `<iframe>`\r\n- Fetched with `fetch()` \/ AJAX and injected into a modal\r\n- Opened directly in the browser (use `target=\"_blank\"`)\r\n\r\n> ?? **Important:** This is **not** a separate \"second HolestPay Terms\" that replaces your site Terms. The `\/clientpay\/tos\/<merchant_site_uid>` content is a merchant-specific **template\/proposal of your own purchase Terms** (with your POS\/merchant context), meant to be used as the same Terms of Service page your checkout checkbox points to. Keep one coherent TOS page for customers (your site TOS), and ensure it includes the required payment clauses.\r\n\r\n**Implementation \u2014 TOS modal using HolestPay built-in dialog** (`hpay_dialog_open` becomes available after `client.loadHPayUI()` resolves):\r\n\r\n```javascript\r\n\/\/ Call client.loadHPayUI() first to make hpay_dialog_open available:\r\n\/\/ HPayInit().then(client => client.loadHPayUI()).then(() => { \/* hpay_dialog_open is ready *\/ });\r\n\r\nfunction openTOS(merchant_site_uid, lang) {\r\n  const tos_url = `https:\/\/sandbox.pay.holest.com\/clientpay\/tos\/${merchant_site_uid}?lang=${lang || 'en'}`;\r\n  \/\/ Replace sandbox host with pay.holest.com for production\r\n  hpay_dialog_open('tos', 'Terms of Service', tos_url, 'large', {\r\n    ['I understand and accept these Terms of Service']: {\r\n      Run: function(dlg) {\r\n        dlg.close();\r\n        if (dlg.parentNode) dlg.parentNode.removeChild(dlg);\r\n        \/\/ Mark TOS as accepted \u2014 enable the Pay button or proceed with payment\r\n      },\r\n      action_position: 'center',\r\n      style: { 'min-width': '120px' }\r\n    }\r\n  });\r\n}\r\n```\r\n\r\n**Minimum required UI \u2014 add this near the Pay button:**\r\n\r\n```html\r\n<label style=\"display:flex;align-items:center;gap:8px;margin-bottom:8px;\">\r\n  <input type=\"checkbox\" id=\"tos-accept\" required \/>\r\n  <span>\r\n    I accept the\r\n    <a href=\"#\" onclick=\"openTOS(MERCHANT_SITE_UID, 'en'); return false;\">Terms of Service<\/a>\r\n  <\/span>\r\n<\/label>\r\n<!-- Disable Pay button until checkbox is checked -->\r\n```\r\n\r\n```javascript\r\ndocument.getElementById('tos-accept').addEventListener('change', function() {\r\n  document.getElementById('do-pay').disabled = !this.checked;\r\n});\r\n```\r\n\r\n**Checklist for bank approval:**\r\n- [ ] Card brand logos visible in footer (from `HPay.POS.pos_parameters['Logotypes Card Images']`)\r\n- [ ] Bank logos visible in footer, linked (from `HPay.POS.pos_parameters['Logotypes Banks']`)\r\n- [ ] 3DS logos visible in footer, linked (from `HPay.POS.pos_parameters['Logotypes 3DS']`)\r\n- [ ] All logos in a single horizontal line, max ~1 cm height\r\n- [ ] TOS checkbox present near the Pay button, Pay button disabled until checked\r\n- [ ] TOS content matches or includes HolestPay-provided TOS (`\/clientpay\/tos\/<uid>`)\r\n\r\n---\r\n\r\n## Test Cards for Sandbox Testing\r\n\r\nTest card numbers for almost all supported banks and payment methods can be found directly on the **dashboard page** of the HolestPay sandbox panel at https:\/\/sandbox.pay.holest.com \u2014 no need to search elsewhere. Log in and check the dashboard.\r\n\r\n---\r\n\r\n## Terms of Service Page \u2014 Required Content\r\n\r\nThe \"Terms of Service\" page that the customer checks before payment must be **comprehensive and self-contained**. Because the customer ticks a single \"I accept the Terms of Service\" checkbox that links to this one page, **everything required by the bank and by law must be covered on that exact page** \u2014 not spread across separate pages.\r\n\r\nThe following must be present in the Terms of Service content (either written directly or clearly summarized with a reference to the full document inline):\r\n\r\n- **Purchase conditions** \u2014 what is being sold, pricing, order confirmation process\r\n- **Delivery policy** \u2014 delivery methods, timeframes, costs, geographic coverage\r\n- **Refund and return policy** \u2014 conditions, process, and timeframes for refunds and returns\r\n- **PCI DSS statement** \u2014 explicit confirmation that card data transfer\/processing is secured according to PCI DSS standards and that the merchant does not store raw card data (HolestPay handles card processing on the merchant's behalf)\r\n- **Merchant contact information** \u2014 legal business name, address, email, and phone number for customer support\r\n\r\n> The merchant may have separate dedicated pages for privacy policy, delivery conditions, refund policy, etc. \u2014 that is fine. But **all of the above topics must also appear on the single Terms of Service page** that the payment checkbox links to, because that is the only page the customer is asked to review and accept before paying.\r\n\r\n> HolestPay provides a base TOS\/purchase-conditions text via `\/clientpay\/tos\/<merchant_site_uid>` that already includes payment-security wording (including PCI DSS transfer handling). Treat it as baseline content for the merchant's own single Terms page, then extend it with delivery, refund, and contact details \u2014 not as a separate second TOS document.\r\n\r\n---\r\n\r\n## Before Requesting Bank Production Approval \u2014 Site Readiness\r\n\r\nBefore the merchant contacts their bank to activate the POS for production, the site must be genuinely complete. A bank technician will review the site manually and will reject it if it does not look like a real, finished online store.\r\n\r\n**The following will cause immediate rejection:**\r\n\r\n- **Placeholder content** \u2014 any \"Lorem ipsum\", \"Coming soon\", \"Test product\", dummy images, or unfilled template text anywhere on the site\r\n- **Mixed languages** \u2014 site content, product names, descriptions, and all pages must be consistently in one language (or properly localized if multilingual); a mix of languages on the same page signals an unfinished site\r\n- **Missing or incomplete pages** \u2014 the site must have real products\/services with actual descriptions and prices, a working checkout flow, and all required legal pages (Terms of Service, Privacy Policy, Contact\/About)\r\n- **Non-functional links or broken pages** \u2014 every linked page must load and contain real content\r\n- **Test or sandbox data visible** \u2014 no test order UIDs, sandbox URLs, or debug output visible to visitors\r\n\r\n> Tell the user: *\"Before you ask your bank to approve the POS for production, make sure the site looks like a finished, real store. Bank technicians visit the site in person before approving. If they see Lorem ipsum text, empty product pages, mixed languages, or anything that looks unfinished, they will ask you to complete the site first and resubmit \u2014 which adds weeks to the process.\"*\r\n\r\n---\r\n\r\n## Bank Validation Testing Before Production Approval\r\n\r\nMost banks require a **formal validation test** to be performed before activating the POS for production. This is separate from the developer's own sandbox testing.\r\n\r\nWhat this typically involves:\r\n\r\n- The bank provides a set of **specific test scenarios** that must be completed successfully (e.g. approved payment, declined payment, 3DS challenge flow, cancellation)\r\n- Tests are performed using **test cards provided by the bank** (which may differ from the general sandbox test cards on the HPay dashboard)\r\n- Results are reported back to the bank (sometimes automatically via their test monitoring system, sometimes manually by the merchant)\r\n- **Whether validation testing is required, and exactly how it is done, depends on the bank and the specific payment method** \u2014 some banks require it for every new integration, others only for certain card brands or 3DS configurations\r\n\r\n> Tell the user: *\"Before your bank activates the production POS, they will likely ask you to run a set of validation test payments using specific test cards they provide. This is a standard bank requirement and is separate from the testing you did during development. Contact your bank's technical integration team to find out exactly what tests are required for your payment method \u2014 HolestPay sandbox will be used for these tests as well.\"*\r\n\r\n---\r\n\r\n## Shipping Method UI \u2014 Required `hpay-sm-options` Placeholder\r\n\r\nIn the UI element that displays a shipping method's description (the area shown to the buyer when they select a shipping method), you **must include an empty `<span>` with the class `hpay-sm-options` and attribute `hpay_shipping_method_id=\"<hpay_shipping_method.HPaySiteMethodId>\"`**:\r\n\r\n```html\r\n<span class=\"hpay-sm-options\" hpay_shipping_method_id=\"<hpay_shipping_method.HPaySiteMethodId>\"><\/span>\r\n```\r\n\r\nHolestPay uses this element to inject additional shipping options and information (e.g. parcel locker selector, delivery time slots, carrier tracking info) for the selected shipping method. Without this placeholder, those features will silently fail to render.\r\n\r\nPlace it inside the shipping method description container, after any static description text:\r\n\r\n```html\r\n<div class=\"shipping-method-description\">\r\n  <!-- your static description text here -->\r\n  <span class=\"hpay-sm-options\" hpay_shipping_method_id=\"45\"><\/span>\r\n<\/div>\r\n```\r\n\r\n---\r\n\r\n## Content Security Policy (CSP) and Site Configuration Requirements\r\n\r\nFor HolestPay to function correctly, the site must permit the following \u2014 ensure these are not blocked by Content Security Policy headers, server configuration, or any firewall\/proxy:\r\n\r\n### Allowed origins (iframes, scripts, XHR\/fetch, content)\r\n\r\nThe site must allow iframes, scripts, and content loaded from:\r\n\r\n```\r\nhttps:\/\/pay.holest.com\r\nhttps:\/\/sandbox.pay.holest.com\r\n```\r\n\r\nIf the site sets a `Content-Security-Policy` header, include these in all relevant directives:\r\n\r\n```\r\nContent-Security-Policy:\r\n  script-src  'self' https:\/\/pay.holest.com https:\/\/sandbox.pay.holest.com ...;\r\n  frame-src   'self' https:\/\/pay.holest.com https:\/\/sandbox.pay.holest.com ...;\r\n  connect-src 'self' https:\/\/pay.holest.com https:\/\/sandbox.pay.holest.com ...;\r\n  img-src     'self' https:\/\/pay.holest.com https:\/\/sandbox.pay.holest.com data: ...;\r\n```\r\n\r\n### `eval()` must be permitted\r\n\r\nHolestPay internally uses `eval()` to deserialize and execute certain POS method action functions returned from the server (`initActions`, `orderActions`). The site must **not** block `eval()`.\r\n\r\nIf a CSP header is set, `'unsafe-eval'` must be present in `script-src`:\r\n\r\n```\r\nContent-Security-Policy:\r\n  script-src 'self' 'unsafe-eval' https:\/\/pay.holest.com https:\/\/sandbox.pay.holest.com ...;\r\n```\r\n\r\n> ?? If the site uses a strict CSP that blocks `eval()` or restricts iframes\/scripts to specific origins, HolestPay will fail silently or partially. This is one of the most common causes of \"nothing happens when I click Pay\" during integration.\r\n\r\n---\r\n\r\n## Dock Container Placement\r\n\r\nFor each payment method row, use this visual order:\r\n1) method **name\/label**\r\n2) method **description**\r\n3) method **dock container** (if that method supports docking)\r\n\r\nThe dock container must be below the description of the same method, and before the next method name is rendered. It must **not** be placed after the full list of all payment methods.\r\n\r\nEach payment method in the list that supports docking (`pm.PayInputUrl` is set) needs its own dock container adjacent to it. Best practice is to wrap **description + dock** in one method-details wrapper that is shown only when that method is selected. When the buyer selects that method, `HPay.setPaymentMethodDock()` renders the embedded payment input directly inside that container.\r\n\r\n**Correct structure:**\r\n```html\r\n<label>\r\n  <input type=\"radio\" name=\"payment_method\" value=\"179\" \/>\r\n  Credit Card\r\n<\/label>\r\n<div class=\"method-details is-selected\" data-method=\"179\">\r\n  <div class=\"method-description\">Card payment description...<\/div>\r\n  <div id=\"paymentMethodDock-179\" class=\"hpay-dock-container\"><\/div>\r\n<\/div>\r\n\r\n<label>\r\n  <input type=\"radio\" name=\"payment_method\" value=\"180\" \/>\r\n  Bank Transfer\r\n<\/label>\r\n<div class=\"method-details\" data-method=\"180\">\r\n  <div class=\"method-description\">Bank transfer description...<\/div>\r\n  <!-- no dock here \u2014 this method does not support docking -->\r\n<\/div>\r\n```\r\n\r\n---\r\n\r\n## Always Render Method Description When Selected\r\n\r\nWhenever a payment method or shipping method is selected by the buyer, **always display its description**. Do not skip or hide descriptions.\r\n\r\nMethod descriptions sometimes contain **functionally important content** \u2014 instructions the buyer must read (e.g. bank account number for manual transfer, pickup location details, special conditions). Hiding or omitting descriptions can cause buyer confusion and failed orders.\r\n\r\nFor shipping methods, the description container must also include the `<span class=\"hpay-sm-options\" hpay_shipping_method_id=\"<hpay_shipping_method.HPaySiteMethodId>\"><\/span>` placeholder (see earlier section) so HolestPay can inject carrier-specific UI into it.\r\n\r\n---\r\n\r\n## Shopify-Specific Notes (if building a Lovable app for Shopify)\r\n\r\n### Order creation timing\r\n\r\nIf this integration is for a Shopify storefront, **all communication with the Shopify API (order creation, order update, fulfillment, etc.) must happen only after receiving the HolestPay payment result** \u2014 i.e. inside the `onHPayResult` handler or the POST-back handler on `order_user_url`. Do not create or confirm the Shopify order before payment is confirmed. The HolestPay result contains the definitive payment status (`payment_status: PAID|RESERVED|...`) that should trigger the Shopify order write.\r\n\r\n### Shopify API credentials with `write_orders` permission\r\n\r\nShopify access tokens that merchants create themselves in the Shopify admin expire after **24 hours** and cannot be used for permanent integrations.\r\n\r\nIf a permanent Shopify API access token with `write_orders` permission is needed, the merchant can **borrow the credentials from the HolestPay Shopify app**:\r\n\r\n1. In the HolestPay panel, go to site\/POS settings for the Shopify site.\r\n2. Find the **SHOPIFY CLIENT SECRET** parameter.\r\n3. Use the **Copy All Shopify APP Credentials...** next to it to copy the credentials.\r\n\r\n> ?? **Security warning \u2014 tell the user this explicitly:**  \r\n> *\"These are shared API credentials tied to the HolestPay Shopify app. Do not share them with anyone, do not commit them to a public repository, and do not expose them in frontend code. Store them as private environment variables on your server only.\"*\r\n\r\n---\r\n\r\n## HolestPay Language Codes\r\n\r\nHolestPay uses its own language code convention \u2014 **do not use standard ISO\/BCP-47 codes** for Serbian:\r\n\r\n| Language | HolestPay code | ? Do NOT use |\r\n|---|---|---|\r\n| Serbian Latin | `rs` | `sr`, `sr-Latn`, `sr-YU`, `sr-lat` |\r\n| Serbian Cyrillic | `rs-cyr` | `sr-Cyrl`, `sr-cyr`, `cyr` |\r\n| Bosnian | `bs` | |\r\n| Croatian | `hr` | |\r\n| Slovenian | `si` | |\r\n| Macedonian | `mk` | |\r\n| English | `en` | |\r\n| German | `de` | |\r\n| Italian | `it` | |\r\n| Spanish | `es` | |\r\n| French | `fr` | |\r\n| Portuguese | `pt` | |\r\n| Dutch | `nl` | |\r\n| Greek | `el` | `gr` |\r\n| Turkish | `tr` | |\r\n\r\nPass this value as the `language` parameter to `HPayInit()` and as `hpaylang` in `pay_request`.\r\n<\/code><\/pre>\n","protected":false},"excerpt":{"rendered":"<p>Tell Lovable (or similar system&#8230;) that you want to integrate HolestPay payments\/fiscal\/shipping and give it this MD markup: https:\/\/apps.holest.com\/holest-pay\/Lovable_or_similar_ai_system.MD.txt Lovable will know then what to ask you and what to instruct you to do&#8230; Make sure to SET UP FIRST ALL methods you plan to use on https:\/\/sandbox.pay.holest.com\/ (payment | fiscal | shipping) and test [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_hpay_column_layout":"0","_hpay_name_price":"0","footnotes":""},"categories":[68],"tags":[],"class_list":["post-6655","post","type-post","status-publish","format-standard","hentry","category-hpay-ai-integration"],"_links":{"self":[{"href":"https:\/\/ecommerce.holest.com\/en\/wp-json\/wp\/v2\/posts\/6655","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/ecommerce.holest.com\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/ecommerce.holest.com\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/ecommerce.holest.com\/en\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/ecommerce.holest.com\/en\/wp-json\/wp\/v2\/comments?post=6655"}],"version-history":[{"count":11,"href":"https:\/\/ecommerce.holest.com\/en\/wp-json\/wp\/v2\/posts\/6655\/revisions"}],"predecessor-version":[{"id":6673,"href":"https:\/\/ecommerce.holest.com\/en\/wp-json\/wp\/v2\/posts\/6655\/revisions\/6673"}],"wp:attachment":[{"href":"https:\/\/ecommerce.holest.com\/en\/wp-json\/wp\/v2\/media?parent=6655"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/ecommerce.holest.com\/en\/wp-json\/wp\/v2\/categories?post=6655"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/ecommerce.holest.com\/en\/wp-json\/wp\/v2\/tags?post=6655"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}