the first platform that gives real autonomy to merchants

Integration Portal
PaymentForm

PROCASH · Payment API v5.8.2 · Developer documentation

"The focus is on merchants, the priority is their profitability, the goal is innovation and pragmatism."

🔒 PCI SAQ-A ↗ Redirect ⬜ Embedded (iframe) ⇄ S2S 💳 Installments 📱 QR 🇦🇷 ARS · Argentina

PaymentForm is the hosted payment form by PROCASH. Your site never sees card data: the form is served from a PCI-compliant domain. You only execute two server-to-server calls from your backend: OrderInitial to create the order and OrderFinal to confirm the result.

Only 2 S2S calls

OrderInitial to create the order, OrderFinal to confirm the result. Everything else is automatic.

🔒

PCI SAQ-A included

Your server never sees or processes card data. The PCI scope is minimal by design.

🔀

2 integration modes

Full redirect (simpler) or embedded iframe with postMessage for an experience without leaving your site.

💳

Installments and QR

Native support for installments (1 to N) with configurable financial plans per acquirer. Dynamic QR payments available depending on the platform configuration.

🇦🇷

Argentine context

Currency ARS (032) · Amounts in cents · CUIT/CUIL as tax identifier · Time zone UTC-3 (Buenos Aires).

Payment flow

How it works

Complete sequence diagram: actors, calls, and data flow.

🖥️ Your siteMerchant / Backend
⚡ GatewayCore API
💳 PaymentFormHosted form
👤 BuyerBrowser
1
POST /OrderInitial
amount, currency, MerchantRedirectURL, MerchantNotifyURL
InitialToken + InitialIdentification
+ CustomerRedirectAddress — save InitialIdentification in your DB
3 · Redirect 302 → CustomerRedirectAddress?token=…
Merchant redirects the browser to the hosted form
4 · Opens PaymentForm
5 · Form retrieves configuration (internal)
6 · Enters card details
7 · Form processes payment (internal)
8 · Redirect → MerchantRedirectURL?token=…
9 · Browser returns to your site
10 · POST /OrderFinal (InitialIdentification)
11 · AuthCode, Tickets, confirmed amount
ℹ️
Golden rule: The redirect result (steps 8–9) is only a navigation signal. The actual and final result is always obtained via OrderFinal (steps 10–11) from your server.
Integration options

Integration modes

PaymentForm supports three modes depending on the level of UX control and integration you need. All three maintain PCI SAQ-A compliance — the merchant never captures card data.

↗️

Mode A — Redirect

The buyer's browser leaves your site and goes to the hosted form. The simplest and fastest integration mode.

✓ PCI SAQ-A Easiest

Mode B — Embedded (full iframe)

The complete form is displayed in a cross-origin iframe within your page. Communication via postMessage.

✓ PCI SAQ-A Better UX
UNDER CONSTRUCTION
🧩

Mode C — Hosted Fields

Only the card fields (PAN + CVV) go into a PROCASH iframe. The merchant builds the rest of the form — maximum layout control, without touching CHD.

✓ PCI SAQ-A Maximum control Designed · implementing

You redirect the buyer using the CustomerRedirectAddress returned by OrderInitial. The form processes the payment and returns the buyer to your MerchantRedirectURL.

Node.js / Express
// 1. Call OrderInitial from your server
const response = await fetch('https://api.procash.dev/OrderInitial', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Authorization': `Bearer ${API_KEY}`
  },
  body: JSON.stringify({
    OrderInitial: {
      MerchantSystemID: 'SHOP-01',      // required
      MerchantCompanyID: '0',          // required
      TransactionAmount: 1000000,      // $10,000.00 ARS (in cents)
      CurrencyCode: '032',            // desirable — if omitted assumes ARS
      ReferenceNumber: 'ORD-2026-0001',
      MerchantRedirectURL: 'https://www.mi-tienda.com.ar/pago/retorno', // optional
      MerchantNotifyURL: 'https://www.mi-tienda.com.ar/webhooks/pago',   // recommended
      FacilityNumber: 3,              // optional — cuotas (1 = contado)
    }
  })
});
const { OrderInitialResponse: r } = await response.json();

// 2. Verify that the order was created successfully
//    ResponseActions is the source of truth — must contain "OK"
//    ResponseCode "-1" is the success indicator in this contract
if (!r.ResponseActions?.includes('OK') || r.ResponseCode !== '-1') {
  // Order rejected by the platform — do not redirect
  throw new Error(`OrderInitial failed: [${r.ResponseActions}] ${r.ResponseMessage}`);
}

// 3. Validate presence of required fields in the response
if (!r.InitialIdentification || !r.CustomerRedirectAddress) {
  throw new Error('Incomplete response: missing InitialIdentification or CustomerRedirectAddress');
}

// 4. ⚠️ Save InitialIdentification in your DB BEFORE redirecting
//    It is PRIVATE — it never travels to the browser
await db.orders.update({ referenceNumber: 'ORD-2026-0001' }, {
  initialIdentification: r.InitialIdentification
});

// 5. Redirect the buyer to the form — only the InitialToken (PUBLIC) travels in the URL
res.redirect(302, r.CustomerRedirectAddress);

Embed the form in your page with an iframe using the same URL. Listen to postMessage events — card data never leaves the iframe.

📡
Available postMessage events:
paymentform:ready · paymentform:resize · paymentform:submitted · paymentform:error
HTML + JavaScript
<!-- iframe cross-origin — PCI SAQ-A maintained -->
<iframe
  id="payment-frame"
  src="https://payment.procash.dev/?token=INITIAL_TOKEN_AQUI"
  style="width:100%;border:none;min-height:420px;"
  allow="payment"
></iframe>

<script>
window.addEventListener('message', (e) => {
  // Always verify origin
  if (e.origin !== 'https://payment.procash.dev') return;

  const { type, result } = e.data;

  if (type === 'paymentform:submitted') {
    if (result === 'approved') {
      // Call your backend to execute OrderFinal
      confirmOrder(result);
    } else if (result === 'refused') {
      showRefusedMessage();
    }
  }

  if (type === 'paymentform:resize') {
    document.getElementById('payment-frame').style.height = e.data.height + 'px';
  }
});
</script>
🚧
Status: designed and under construction (Phase 16). The v1.0.0 integration contract is defined and the client-side logic (embed-fields.ts) is implemented. The cross-origin subdomain infrastructure and WASM→JWE encryption are pending. Consult the PROCASH team for availability in sandbox.

¿Qué es Hosted Fields?

Instead of embedding the complete form, only the sensitive fields (PAN + CVV) are in a cross-origin iframe served by PROCASH. Your page builds the rest of the checkout — amount, installments, buyer details, layout — while card data never touches your DOM.

// Your page (out of PCI scope)
YOUR FORM
[ Amount: $10,000.00 ARS ]
[ Installments: 3 interest-free ]
⬛ PROCASH IFRAME (cross-origin · PROCASH SAQ-D scope)
[ PAN: ________________ ]
[ CVV: ___ ] [ Exp: __/__ ]
→ WASM encrypts to JWE before leaving
[ Cardholder name: ________ ]
[ Pay → ]
↕ postMessage: "ready" · "fieldValidity" · "submit" · "error" · "challenge"

Tiers de hosting disponibles

TierIframe domainWho is it for
T1 — Compartido{tenant}.payment.procash.devDefault — quick onboarding
T2 — White-labelpay.tudominio.com (CNAME → PROCASH)Merchants with their own branding
T3 — EnterpriseDominio completamente customBanks / large retailers (regional/on-prem hosting)

Contrato postMessage (eventos del iframe)

EventDirectionPayload
paymentform:readyiframe → parent{ mode: 'fields' } — iframe ready to receive interaction
paymentform:fieldValidityiframe → parent{ field: 'pan'|'cvv', valid: bool } — to enable/disable the button
paymentform:resizeiframe → parent{ height: px } — adjust iframe height
paymentform:submitparent → iframe{ token } — submit trigger from your button
paymentform:submittediframe → parent{ result: 'approved'|'refused'|'challenge' }
paymentform:erroriframe → parent{ code, message }
HTML + JavaScript — Hosted Fields (Model C)
<!-- Only the sensitive fields iframe (cross-origin) -->
<div id="checkout">
  <!-- Your UI: amount, installments, cardholder name -->
  <p>Total: <strong>$10.000,00 ARS</strong> en 3 cuotas</p>

  <!-- PROCASH iframe: PAN + CVV only -->
  <iframe
    id="fields-frame"
    src="https://{tenant}.payment.procash.dev/fields?token=INITIAL_TOKEN"
    style="width:100%;border:none;height:120px;"
    allow="payment"
    sandbox="allow-scripts allow-same-origin"
  ></iframe>

  <!-- Your own payment button -->
  <input type="text" placeholder="Cardholder name" id="cardName">
  <button id="pay-btn" disabled>Pay</button>
</div>

<script>
const frame = document.getElementById('fields-frame');
const payBtn = document.getElementById('pay-btn');
let panOk = false, cvvOk = false;

// Listen to iframe events
window.addEventListener('message', (e) => {
  if (e.origin !== 'https://{tenant}.payment.procash.dev') return;
  const { type, field, valid, height, result } = e.data;

  if (type === 'paymentform:resize')
    frame.style.height = height + 'px';

  if (type === 'paymentform:fieldValidity') {
    if (field === 'pan') panOk = valid;
    if (field === 'cvv') cvvOk = valid;
    payBtn.disabled = !(panOk && cvvOk);  // enable only if both OK
  }

  if (type === 'paymentform:submitted' && result === 'approved')
    confirmOrder();  // call your backend → OrderFinal
});

// Your button triggers the submit in the iframe
payBtn.addEventListener('click', () => {
  frame.contentWindow.postMessage(
    { type: 'paymentform:submit' },
    'https://{tenant}.payment.procash.dev'
  );
});
</script>
🔒
Security: the iframe encrypts PAN + CVV using WASM → JWE before they leave the iframe. Your page never sees the plaintext data, even though they share the same browser window. The iframe's sandbox and allow-same-origin are configured by the platform so that postMessage communication works without exposing the sensitive DOM.
Integration guide

Step by step

Follow these steps to integrate PaymentForm in your backend.

1

OrderInitial (S2S)

Call from your server to create the payment order. Never from the browser.

POST https://api.procash.dev/OrderInitial

Auth: Authorization: Bearer {API_KEY}

Request JSON
{
  "OrderInitial": {
    "MerchantSystemID": "SHOP-01",       // required
    "MerchantCompanyID": "0",           // required
    "TransactionAmount": 1000000,       // $10,000.00 ARS (in cents)
    "CurrencyCode": "032",              // desirable — if omitted assumes ARS
    "ReferenceNumber": "ORD-2026-0001", // your internal order ID
    "MerchantRedirectURL": "https://www.mi-tienda.com.ar/pago/retorno", // optional
    "MerchantNotifyURL": "https://www.mi-tienda.com.ar/webhooks/pago",   // recommended
    "FacilityNumber": 3,               // optional — cuotas (1 = contado)
    "Products": [
      { "Code": "PLAN-PRO", "Name": "Plan Pro Mensual", "Quantity": 1, "UnitAmount": 1000000 }
    ]
  }
}
Response JSON
{
  "OrderInitialResponse": {
    "ResponseActions": ["OK"],          // ← source of truth
    "ResponseCode": "-1",                 // ← informational (-1 = OK in this contract)
    "ResponseMessage": "Orden creada",     // ← informational
    "InitialToken": "11111111-1111-5111-8111-111111111111",
    "InitialIdentification": "99999999-9999-5999-8999-999999999999",
    "CustomerRedirectAddress": "https://payment.procash.dev/?token=11111111-1111-5111-8111-111111111111",
    "MerchantRedirectURL": "https://www.mi-tienda.com.ar/pago/retorno",
    "TransactionValidThru": "2026-06-04T23:59:59-03:00", // UTC-3 · Buenos Aires
    "Sequence": ""
  }
}
ℹ️
ResponseActions is the source of truth. ResponseCode and ResponseMessage are informational — they are always present but must not be used as decision criteria.
⚠️
Critical: Save InitialIdentification in your database associated with the order. It is PRIVATE — never send it to the browser or expose it in URLs.
2

Redirect the buyer

Use CustomerRedirectAddress (which already has the token embedded). Equivalent to https://payment.procash.dev/?token={InitialToken}

Express / Node.js
const { OrderInitialResponse: r } = await orderInitial(); // see Step 1

// ✅ Only redirect if ResponseActions contains "OK" and ResponseCode is "-1"
if (r.ResponseActions?.includes('OK') && r.ResponseCode === '-1'
    && r.InitialIdentification && r.CustomerRedirectAddress) {
  res.redirect(302, r.CustomerRedirectAddress);
} else {
  // Handle error — the order was not created
  res.status(400).json({ error: r.ResponseMessage });
}
3

The form processes the payment (internal)

The form manages all payment processing internally — it retrieves the order configuration, captures the buyer's card details, and processes the transaction against the platform. No code is required on your part in this step.

🔒
Your site never sees or touches card details. Everything occurs within the PROCASH PCI environment.
4

Return to your site

The browser returns to your MerchantRedirectURL. The redirect does not include the payment result — the status is always retrieved using OrderFinal (or OrderStatus) from your server.

Return URL (what reaches the browser)
https://www.mi-tienda.com.ar/pago/retorno
  ?token=11111111-1111-5111-8111-111111111111
  // ← no status, no result — only the public token
  // The actual result is obtained by calling OrderFinal from your server
⚠️
The redirect does not carry the result. Never assume approved/rejected simply because the buyer returned to your site. Always execute OrderFinal (S2S) to get the actual result. The webhook (MerchantNotifyURL) also confirms it asynchronously.
💡
No MerchantRedirectURL: if you omit this field in OrderInitial, there is no redirect. The form shows the result directly on screen. In that case, use the webhook (MerchantNotifyURL) and/or OrderStatus to find out the result in your backend.
5

OrderFinal (S2S)

Confirm the result from your server using the InitialIdentification you saved in Step 1.

POST https://api.procash.dev/OrderFinal
Request JSON
{
  "OrderFinal": {
    "InitialIdentification": "99999999-9999-5999-8999-999999999999"
  }
}
Response JSON — Approved
{
  "OrderFinalResponse": {
    "ResponseActions": ["OK", "Approve", "Tickets", "Completed"], // ← source of truth
    //  OK        → successful operation
    //  Approve   → payment approved
    //  Tickets   → there are receipts to render
    //  Completed → full cycle: OrderInitial→form→OrderFinal executed
    "ResponseCode": "-1",                                      // ← informational (-1 = aprobado)
    "ResponseMessage": "Aprobado",                               // ← informational
    "AuthCode": "AUTH123",
    "TransactionAmount": 1000000,
    "CurrencyCode": "032",
    "Tickets": [
      { "Type": "Customer", "Content": "..." },
      { "Type": "Merchant", "Content": "..." }
    ]
  }
}
Response JSON — Refused
{
  "OrderFinalResponse": {
    "ResponseActions": ["OK", "Refuse", "Completed"], // ← source of truth — pago NO acreditado
    //  OK        → operation processed
    //  Refuse    → refused by issuer
    //  Completed → full cycle executed (same as in Approve)
    "ResponseCode": "05",                              // ← informational, solo un ejemplo — puede ser cualquier código
    "ResponseMessage": "Tarjeta rechazada por el emisor", // ← informational, solo un ejemplo
    "TransactionAmount": 1000000,
    "CurrencyCode": "032"
  }
}
ℹ️
Decision logic — ResponseActions is always an array:

OK → always present along with Approve or Refuse. Approve → payment approved · confirm and deliver. Refuse → refused · not charged · notify buyer. Completed → full cycle: merchant executed OrderFinal and closed integration cycle. Tickets → there are receipts in Tickets[] to render to buyer.

Do not use ResponseCode or ResponseMessage as decision criteria. Correct logic: includes('Approve') for approved · includes('Refuse') for refused · includes('Completed') for closed cycle.

📡 Webhook — MerchantNotifyURL

The Core calls your MerchantNotifyURL asynchronously with the payment result. It guarantees that you receive the result even if the browser does not return to your site.

🔁 May arrive more than once — make it idempotent ✓ Use it alongside OrderFinal 📬 Verify signature if available
Visual Customization

Form Look & Feel

PaymentForm fully adapts to the merchant's branding. Styles, interface model, products, and logo are configured per order, directly in the OrderInitial via AdditionalInformation — without touching form code.

ℹ️
Styles travel in AdditionalInformation[].Name = "PaymentForm.Styles" with the styles JSON in Base64. Merchant branding (name + logo) goes in Name = "PaymentForm.Company". Both are sent in OrderInitial and the form applies them with priority over the base configuration.

Modelos de interfaz

Selected with FormMode in the configuration. You can combine any model with any color theme.

Screenshots — the same order in the four combinations

Con tarjeta y con productos
With card · with products
interactive-card · ShowProducts:true
Con tarjeta sin productos
With card · without products
interactive-card · ShowProducts:false
Sin tarjeta con productos
Without card · with products
classic · ShowProducts:true
Sin tarjeta sin productos
Without card · without products
classic · ShowProducts:false

How to configure styles from OrderInitial

Styles are sent in AdditionalInformation as Base64 JSON. The form applies them with priority over any default configuration.

⚠️
Important (JSON Structure): The form rendering engine only supports three root objects inside the styles array: Background, Text, and Form. Any input or card styling properties must be configured inside these blocks (for example, use Form.input_color instead of a standalone Input object). Legacy root objects like Card or Input are not recognized and will be ignored.
Step 1 — Build the styles object
// Styles object (flat JSON before encoding)
const stylesArray = [
  { "Background": { "color": "#fcf9fb" } },
  { "Text": { "color": "#130a25" } },
  {
    "Form": {
      "background_color": "#fcf9fb",
      "button_color": "#a47fab",
      "price_color": "#68ac5c",
      "error_color": "#dc2626",
      "border_radius": "10px",
      "max_width": "520px",
      "input_color": "#ffffff",
      "input_innertext_color": "#130a25",
      "input_border_color": "#f3f3f4",
      "form_label": "orden",         // "pedido" | "orden" | "operacion" | "transaction"
      "show_cft": true,
      "show_tea": false,
      "show_interest_rate": true,
      "show_installment_calculation": false,
      "installment_calculation_mode": "simple"
    }
  }
];

const stylesB64 = btoa(JSON.stringify(stylesArray));  // encode to Base64

// Merchant branding
const companyB64 = btoa(JSON.stringify({
  "Name": "Tu Comercio",
  "LogoUrl": "https://www.mi-tienda.com.ar/logo.png"   // Public URL — requires access from the buyer's browser
  // — or —
  // "LogoUrl": "data:image/svg+xml;base64,PHN2ZyB4bWxucz0i..."  // Data URI — zero external requests (recommended for PCI)
}));

// Real example of Data URI with an SVG icon (64×64, background #004785)
// You can generate yours with: btoa(svgString) in the browser, or base64.b64encode(svg.encode()).decode() in Python
const iconoBase64 = "data:image/svg+xml;base64," +
  // PNG: icon + white on background #004785 (32×32 px)
  "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAIAAAD8GO2jAAAAc0lEQVR42u3WWw4AERQDULuzMuvmW+J1S+sRN36nJ0Zm1LnjxgdCYnsRo3HGFG1m4PQhYzK9Y9SfiaWxG1yguWszUDC4QO/cECAzxEBE51lg7I0jQM34Z7D/OyAA9//snrhwFHeyolUoepGi2Ym66Yp2nQBekRDCxivTugAAAABJRU5ErkJggg==";
Step 2 — Include them in OrderInitial
{
  "OrderInitial": {
    "MerchantSystemID": "SHOP-01",
    "MerchantCompanyID": "0",
    "TransactionAmount": 1000000,
    "CurrencyCode": "032",
    "ReferenceNumber": "ORD-2026-0001",
    "Products": [
      {
        "Code": "PLAN-PRO",
        "Name": "Plan Pro Mensual",
        "Quantity": 1,
        "UnitAmount": 1000000,
        "ImageUrl": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAIAAAD8GO2jAAAAc0lEQVR42u3WWw4AERQDULuzMuvmW+J1S+sRN36nJ0Zm1LnjxgdCYnsRo3HGFG1m4PQhYzK9Y9SfiaWxG1yguWszUDC4QO/cECAzxEBE51lg7I0jQM34Z7D/OyAA9//snrhwFHeyolUoepGi2Ym66Yp2nQBekRDCxivTugAAAABJRU5ErkJggg=="
        // ↑ Real PNG 32×32 px — icon + white on background #004785 — 172 bytes / 232 chars base64
      }
    ],
    "AdditionalInformation": [
      {
        "Name": "PaymentForm.Styles",
        "Value": "<stylesB64>"   // result of btoa(JSON.stringify(stylesArray))
      },
      {
        "Name": "PaymentForm.Company",
        "Value": "<companyB64>"  // result of btoa(JSON.stringify(companyObj))
      }
    ]
  }
}

Available style tokens

TokenObjectDescriptionExample
colorBackgroundPage background color#fcf9fb · #0f172a
colorTextMain card text color#130a25 · #ffffff
background_colorFormForm card background color#fcf9fb · #ffffff
button_colorFormColor of the "Pay" button#a47fab · #004785
price_colorFormColor of the total amount#68ac5c · #22c55e
error_colorFormColor of validation error messages#dc2626 · #fb7185
input_colorFormBackground color of input fields#ffffff · #f8fafc
input_innertext_colorFormColor of the text entered in fields#130a25 · #0f172a
input_border_colorFormBorder color of input fields#f3f3f4 · #e2e8f0
border_radiusFormForm card border radius10px · 0
max_widthFormMaximum form width520px
form_labelFormForm title / label contextorden · pedido · operacion · transaction
show_cftFormEnables/Disables showing the Total Financial Cost (CFT) in the installment selectortrue · false
show_teaFormEnables/Disables showing the Annual Effective Rate (TEA) in the installment selectortrue · false
show_interest_rateFormEnables/Disables showing the Annual Nominal Rate (TNA) in the installment selectortrue · false
show_installment_calculationFormIf true, calculates the value of each installment applying the plan's interest rate instead of a simple divisiontrue · false
installment_calculation_modeFormFormula used to calculate the installment with interest: simple (direct interest), french_tna (French TNA), french_tea (French TEA), cft (French CFT)simple · french_tna · french_tea · cft
header_alignFormHorizontal alignment of the order headerleft · center · right
header_fontFormFont family of the order headerOutfit, sans-serif
header_sizeFormFont size of the order header14px · 0.875rem
header_colorFormFont color of the order header#475569
button_alignFormAlignment and stretching of the pay buttonflex-start · center · flex-end · stretch
button_widthFormExplicit width of the pay button200px · 100%
button_paddingFormInner padding of the pay button12px 24px
button_font_sizeFormFont size of the pay button16px
button_icon_urlFormCustom icon URL to replace the default padlock on the buttonhttps://example.com/shield.png
amount_fontFormFont family of the amount textInter, sans-serif
amount_font_sizeFormFont size of the amount text24px · 1.5rem
amount_colorFormFont color of the amount text#16a34a
💡
Configuration Note: The following properties correspond to the default Tenant (merchant/platform) configuration. However, you can dynamically override them for each transaction by sending them in the style JSON (PaymentForm.Styles) inside the "Form" block (e.g., Styles[].Form.form_mode). If not sent, the platform will apply the pre-configured values for your account or the form's default values.

Form configuration

FieldTypeDefaultDescription
FormModestringclassicclassic — traditional form · interactive-card — interactive 3D card (premium)
ShowProductsbooleantrueShows or hides product details. If false, the form is more compact.
AllowInstallmentsbooleantrueEnables the installment selector. Available plans are determined by the card's BIN.
AllowAmountEditbooleanfalseAllows the buyer to modify the amount before paying.
ProductLayoutstringlistlist — vertical · grid — 2-column grid · compact — without images, ideal for large carts
Localestringes-ARLanguage and format. es-AR · en-US · pt-BR. Changes labels, date and currency formats.
🖼️
Product images: the ImageUrl field in Products[] accepts a public URL or base64 Data URI. When base64 is used, the image does not generate external network requests — strict PCI compliance. Images can also come in the Products[] returned by the Core.
Preview — Data URI rendered in the browser
Product icon
32×32 · PNG · 172 bytes
Ícono
Plan Pro Mensual
SKU: PLAN-PRO · x1
$10.000
The string that travels in ImageUrl:
data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAIAAAD8GO2jAAAAc0lEQVR42u3WWw4AERQDULuzMuvmW+J1S+sRN36nJ0Zm1LnjxgdCYnsRo... (232 chars · PNG 32×32 px)
Format: data:<mime>;base64,<data> — RFC 2397. The header iVBORw0KGgo always identifies a PNG (magic bytes \x89PNG). Supports image/png, image/jpeg, image/webp, image/svg+xml.
How to generate the Data URI?
// Browser (JS)
const
reader =
new
FileReader();
reader.onload = e =>
console.log
(e.target.result);
reader.readAsDataURL(imageFile);
# Python
import
base64
with
open
("logo.png", "rb") as f:
  b64 = base64.b64encode(f.read()).decode()
uri = f"data:image/png;base64,{b64}"
# Node.js
const fs = require('fs');
const b64 = fs.readFileSync('logo.png')
  .toString('base64');
const uri = `data:image/png;base64,${b64}`;
Sandbox & Testing

Test data

Use these cards and scenarios in the PROCASH sandbox environment.

Tarjetas de prueba

Card number Brand CVV Expiration Result
4111 1111 1111 1111 Visa 123 12/28 ✅ Approved
4000 0000 0000 0002 Visa 123 12/28 ❌ Refused
5555 5555 5555 4444 Mastercard 123 12/28 ✅ Approved
5105 1051 0510 5100 Mastercard 123 12/28 ❌ Refused

ResponseActions — valores posibles

ResponseActions is an array — it can always contain multiple values at once. OK and Completed always accompany Approve or Refuse when the cycle is complete.

ResponseActions (array) ResponseCode Meaning
["OK", "Approve", "Completed"] -1 ✅ Payment approved · closed cycle
["OK", "Approve", "Tickets", "Completed"] -1 ✅ Approved + receipts available
["OK", "Refuse", "Completed"] 05 (ej.) ❌ Refused — the code is informational and may vary
⚠️ The values of ResponseCode are only examples. There is a wide variety of possible codes depending on the issuer and the platform. The source of truth is always the action Refuse or Error in ResponseActions — this is the real indicator that the payment was not approved, regardless of the code.
💡
Correct code logic:
actions.includes('Approve') → approved, credit/deliver.
actions.includes('Refuse') → refused, not charged.
actions.includes('Completed') → the merchant executed OrderFinal and closed the cycle.
actions.includes('Tickets') → render Tickets[] to the buyer.

Payment NOT approved: includes('Refuse') or includes('Error') are the only real indicators of refusal. ResponseCode and ResponseMessage are informational and may vary — never use them as decision criteria.

Escenarios de prueba

Configurable scenarios in sandbox — consult the PROCASH team to activate them.

baseline
Standard approved flow without friction
refused-response
Response refused by issuer
3ds-frictionless
3DS without challenge — automatic approval
3ds-snap-challenge
3DS with interactive challenge
high-risk
High risk transaction — additional review

Métodos de pago en sandbox

MethodAvailable in sandboxNotes
💳 Credit card (installments) ✅ Yes Visa, Mastercard, Amex · up to 12 installments depending on the BIN plan
💳 Debit card ✅ Yes Single installment · PIN not required in CNP channel
📱 Dynamic QR ⚡ Depending on config Requires enablement on the platform · consult the PROCASH team
🏦 Transfer / CVU ⚡ Depending on config Available if the plan includes it · the form shows the destination CVU

Endpoints Sandbox

S2S https://api.procash.dev · Gateway / Core API
WEB https://payment.procash.dev · PaymentForm (hosted form)
API Reference

Quick reference

Key fields of the OrderInitial request.

Field Type Required Description
MerchantSystemID string ✅ Yes Merchant system identifier
MerchantCompanyID string ✅ Yes Company ID
MerchantBranch string N/A Not used in CNP web integration. The platform resolves it by merchant configuration.
MerchantPOSID string N/A Not used in CNP web integration. The platform resolves it by merchant configuration.
TransactionAmount integer ✅ Yes Amount in cents (e.g. 1000000 = $10,000.00 ARS)
CurrencyCode string ⚡ Desirable ISO 4217 — 032 = ARS (Argentine Pesos). If omitted, the platform assumes the currency of the merchant's country. Always recommended to send.
ReferenceNumber string ✅ Yes Your internal order ID (for reconciliation)
MerchantRedirectURL string Opcional URL to which the buyer returns after payment. If omitted, there is no redirect: the form directly shows the final result (approved / refused) without leaving the form page.
MerchantNotifyURL string ⚡ Recom. Webhook — the Core notifies the result asynchronously
Products array Opcional Product details to display on the form
FacilityNumber integer Opcional Number of installments (1 = single payment, 3/6/12… = installments). Requires a financial plan enabled for the BIN.
TaxIdentification string Opcional Tax identifier of the buyer — CUIT/CUIL for Argentina (e.g. 20-12345678-9)

Montos en ARS — formato

The TransactionAmount field is in cents (without decimal comma). Use the dot as thousands separator and the comma for decimals when displaying to the user.

Monto para el usuarioTransactionAmountNota
$1.000,00 ARS100000One thousand pesos
$5.000,00 ARS500000Five thousand pesos
$10.000,00 ARS1000000Ten thousand pesos
$50.000,00 ARS5000000Fifty thousand pesos
$100.000,00 ARS10000000One hundred thousand pesos

💡 To convert: TransactionAmount = Math.round(montoPesos * 100)

Flujo resumido

1️⃣
OrderInitial
Tu server → Gateway
Get token + ID
2️⃣
Redirect
Browser → PaymentForm
Buyer enters card
3️⃣
Retorno
Browser → your MerchantRedirectURL
+ async webhook
4️⃣
OrderFinal
Your server → Gateway
Confirm the actual result
Questions? Contact the PROCASH integration team. Mention contract number PROCASH Payments API v5.8.2 in your inquiry.
Optional elements of OrderInitial

Seller · Payer · Customer · Shipping

OrderInitial accepts four optional objects that enrich the transaction with data from the involved parties. All are optional — including them allows for better traceability, anti-fraud analysis, and regulatory compliance.

ℹ️
Payer vs Customer: if Payer is not present, the platform takes the data from Customer as the payer. In most e-commerce cases, they are the same person — sending Customer is sufficient.

Data of the buyer/customer. It is the most common object in e-commerce. If Payer is not sent, these details are also used as the payer.

CampoTipoDescripción
FirstNamestringFirst name
LastNamestringLast name
MiddleNamestringMiddle name(s)
EmailstringCustomer's email
PhonestringPhone number
DocumentTypeenumCI · PAS · ACCOUNT_NUMBER · CONTRACT · OTHER
DocumentNumberstringDocument number
TaxIdentificationTypestringType of tax identifier — in Argentina: CUIT or CUIL
TaxIdentificationstringCUIT/CUIL number or other tax identifier
AddressStreetstringStreet
AddressNumberstringStreet number
AddressInternalstringFloor, apartment, unit
AddressSuburbstringNeighborhood
CitystringCity
StatestringState / province
CountrystringCountry
ZipCodestringZip code
NotifyURLstringNotification URL specific to the customer
Example — Customer in OrderInitial (Argentina)
{
  "OrderInitial": {
    "MerchantSystemID": "SHOP-01",
    "MerchantCompanyID": "0",
    "TransactionAmount": 1000000,
    "CurrencyCode": "032",
    "ReferenceNumber": "ORD-2026-0001",
    "Customer": {
      "FirstName": "María",
      "LastName": "González",
      "Email": "maria.gonzalez@email.com",
      "Phone": "1123456789",
      "DocumentType": "CI",
      "DocumentNumber": "12345678",
      "TaxIdentificationType": "CUIL",
      "TaxIdentification": "27-12345678-3",
      "AddressStreet": "Av. Corrientes",
      "AddressNumber": "1234",
      "AddressInternal": "Piso 3 Dpto B",
      "City": "Buenos Aires",
      "State": "CABA",
      "Country": "AR",
      "ZipCode": "C1043"
    }
  }
}

Data of the payer — the person making the payment with their card. Same schema as Customer. Only necessary when the payer is different from the buyer (e.g. someone paying on behalf of another).

CampoTipoDescripción
FirstNamestringFirst name del pagador
LastNamestringLast name del pagador
EmailstringPayer's email
PhonestringPayer's phone
DocumentTypeenumCI · PAS · ACCOUNT_NUMBER · CONTRACT · OTHER
DocumentNumberstringDocument number del pagador
TaxIdentificationTypestringType of tax identifier — in Argentina: CUIT or CUIL
TaxIdentificationstringPayer's CUIT/CUIL number
AddressStreet · AddressNumber · City · State · Country · ZipCodestringPayer's full address
NotifyURLstringNotification URL specific to the payer
💡
In most e-commerce cases, the buyer and the payer are the same person — just send Customer and omit Payer. The platform will automatically use Customer as the payer.

Seller details. Useful in marketplace models or when the merchant needs to identify the specific seller within the platform.

CampoTipoDescripción
FirstNamestringSeller's name
LastNamestringLast name del vendedor
EmailstringSeller's email
DocumentTypeenumCI · PAS · ACCOUNT_NUMBER · CONTRACT · OTHER
DocumentNumberstringDocument number del vendedor
TaxIdentificationTypestringType of tax identifier — in Argentina: CUIT
TaxIdentificationstringSeller's CUIT
IdentificationstringInternal identifier of the seller on the platform
IdentificationTypeenumIdentifier type: CI · PAS · ACCOUNT_NUMBER · CONTRACT · OTHER
AddressStreet · AddressNumber · City · State · CountrystringSeller's address
Example — Seller in OrderInitial (marketplace)
{
  "OrderInitial": {
    // ... base fields ...
    "Seller": {
      "Identification": "SELLER-0042",
      "IdentificationType": "CONTRACT",
      "FirstName": "Distribuidora",
      "LastName": "Sur S.A.",
      "TaxIdentificationType": "CUIT",
      "TaxIdentification": "30-71234567-8",
      "Email": "ventas@distribuidorasur.com.ar"
    }
  }
}

Delivery address of the order. Independent of the buyer's billing address. Necessary when physical shipping is part of the flow.

CampoTipoMaxDescripción
FirstNamestring100Recipient's name
LastNamestring100Last name del destinatario
Address1string255Primary address (street and number)
Address2string255Complement (floor, apartment, unit)
Citystring100City de entrega
StateProvincestring100Province
Countrystring50Country (ej: AR)
ZipCodestring20Zip code
PhoneNumberstring50Contact phone number for delivery
Emailstring255Contact email for shipping notifications
Example — Shipping in OrderInitial
{
  "OrderInitial": {
    // ... base fields + Customer ...
    "Shipping": {
      "FirstName": "María",
      "LastName": "González",
      "Address1": "Av. Corrientes 1234",
      "Address2": "Piso 3 Dpto B",
      "City": "Buenos Aires",
      "StateProvince": "CABA",
      "Country": "AR",
      "ZipCode": "C1043",
      "PhoneNumber": "1123456789",
      "Email": "maria.gonzalez@email.com"
    }
  }
}

Ejemplo completo — todos los objetos

OrderInitial with Customer + Shipping (typical Argentina e-commerce case)
{
  "OrderInitial": {
    "MerchantSystemID": "SHOP-01",
    "MerchantCompanyID": "0",
    "TransactionAmount": 1000000,       // $10,000.00 ARS
    "CurrencyCode": "032",
    "ReferenceNumber": "ORD-2026-0001",
    "FacilityNumber": 3,               // 3 installments
    "MerchantRedirectURL": "https://www.mi-tienda.com.ar/pago/retorno",
    "MerchantNotifyURL": "https://www.mi-tienda.com.ar/webhooks/pago",
    "Products": [
      { "Code": "PROD-001", "Name": "Running Shoes", "Quantity": 1, "UnitAmount": 1000000 }
    ],
    "Customer": {              // buyer = payer (most common case)
      "FirstName": "María",
      "LastName": "González",
      "Email": "maria.gonzalez@email.com",
      "Phone": "1123456789",
      "DocumentType": "CI",
      "DocumentNumber": "12345678",
      "TaxIdentificationType": "CUIL",
      "TaxIdentification": "27-12345678-3"
    },
    "Shipping": {             // delivery address (may differ from Customer's)
      "FirstName": "María",
      "LastName": "González",
      "Address1": "Av. Corrientes 1234",
      "Address2": "Piso 3 Dpto B",
      "City": "Buenos Aires",
      "StateProvince": "CABA",
      "Country": "AR",
      "ZipCode": "C1043",
      "PhoneNumber": "1123456789",
      "Email": "maria.gonzalez@email.com"
    }
    // Seller only if it is a marketplace — Payer only if it differs from Customer
  }
}