Payments
On this page
PayU Latam-compatible API (Colombia)
A mock of PayU Latam's JSON API, version 4.0, with sandbox semantics for a Colombian account:
- card payments by number or token, authorizations, captures, voids and refunds;
- PSE bank transfers, with the bank list and a simulated bank page;
- card tokenisation from the server and from the browser (
PayU.js); - the Queries API;
- signed confirmations to your confirmation URL.
Only test card numbers are accepted, and no money moves.
Testlie is not affiliated with, endorsed or sponsored by PayU. "PayU" is used only to describe API compatibility.
Connect
Create a PayU Latam-compatible gateway under Payment gateways. Use its base URL in place of https://sandbox.api.payulatam.com (or https://api.payulatam.com):
| PayU | Mock |
|---|---|
POST /payments-api/4.0/service.cgi |
POST <base URL>/payments-api/4.0/service.cgi |
POST /reports-api/4.0/service.cgi |
POST <base URL>/reports-api/4.0/service.cgi |
https://gateway.payulatam.com/ppp-web-gateway/javascript/PayU.js |
<base URL>/ppp-web-gateway/javascript/PayU.js |
Token service (payU.setURL) …/payments-api/4.0/service |
<base URL>/payments-api/4.0/service |
Send JSON with Content-Type: application/json and Accept: application/json. The XML flavour of the API is not supported. Every command carries the credentials in the body, as PayU's does:
{ "language": "es", "command": "PING", "merchant": { "apiKey": "…", "apiLogin": "…" }, "test": true }| Credential | Environment variable | Use |
|---|---|---|
| API key | PAYU_LATAM_API_KEY |
merchant.apiKey; signs orders, confirmations and response pages |
| API login | PAYU_LATAM_API_LOGIN |
merchant.apiLogin |
| Merchant id | PAYU_LATAM_MERCHANT_ID |
In order signatures and confirmations |
| Account id | PAYU_LATAM_ACCOUNT_ID |
order.accountId; the tokenisation script's account |
| Public key | PAYU_LATAM_PUBLIC_KEY |
The tokenisation script (payU.setPublicKey) |
Answers are PayU's envelopes with HTTP 200: { "code": "SUCCESS", "error": null, … }, or { "code": "ERROR", "error": "<message>" } for wrong credentials, a bad signature or invalid input. Simulated outages (the API failure scenario, rate limits) answer HTTP 429 or 500.
Payments API
| Command | |
|---|---|
PING |
|
GET_BANKS_LIST |
bankListInformation: { paymentMethod: "PSE", paymentCountry: "CO" }. Returns banks[] with pseCode and description. The first entry, pseCode 0, is PayU's "select a bank" placeholder. |
GET_PAYMENT_METHODS |
The account's methods: VISA, VISA_DEBIT, MASTERCARD, MASTERCARD_DEBIT, AMEX, DINERS, CODENSA, PSE |
SUBMIT_TRANSACTION |
transaction.type: see below |
CREATE_TOKEN |
creditCardToken: { payerId, name, identificationNumber, paymentMethod, number, expirationDate: "YYYY/MM" }. The same card for the same payer returns the same token. |
GET_TOKENS |
creditCardTokenInformation: { payerId } or { creditCardTokenId }, optionally startDate and endDate. Returns creditCardTokenList[] with maskedNumber, never the number. |
REMOVE_TOKEN |
removeCreditCardToken: { payerId, creditCardTokenId } |
Transactions
transaction.type |
Body |
|---|---|
AUTHORIZATION_AND_CAPTURE, AUTHORIZATION |
order (accountId, referenceCode, description, language, signature, notifyUrl, additionalValues.TX_VALUE { value, currency }, buyer), payer, paymentMethod, paymentCountry, and either creditCard { number, securityCode, expirationDate, name }, or creditCardTokenId with creditCard { securityCode } or creditCard { processWithoutCvv2: true } |
CAPTURE, VOID |
order.id and parentTransactionId of an approved AUTHORIZATION. A capture may carry a lower additionalValues.TX_VALUE. |
REFUND, PARTIAL_REFUND |
order.id, parentTransactionId of the approved charge, reason; PARTIAL_REFUND takes additionalValues.TX_VALUE. As in Colombia, an order takes one partial refund, and PSE payments are refunded in full only. |
The order signature is hash(ApiKey~merchantId~referenceCode~tx_value~currency) in MD5, SHA1 or SHA256, and the mock accepts any of the three. For example, md5("4Vj8eK4rloUd272L48hsrarnUA~508029~TestPayU~3~USD") is ba9ffa71559580175585e45ce70b6c37. tx_value may be written as sent (3, 3.0 or 3.00). Confirmations and response pages are signed with the algorithm the order used.
Answers carry PayU's transactionResponse:
orderIdandtransactionId;state:APPROVED,DECLINED,PENDINGorEXPIRED;responseCode,pendingReason,trazabilityCode,authorizationCodeandoperationDate;extraParameters.
Refunds answer PENDING with pendingReason PENDING_REVIEW, as PayU reviews them first. They turn APPROVED after the mock's async delay; read the result with the Queries API.
Card outcomes
As in PayU's sandbox, the card holder's name decides, and for a token it's the name it was created with:
| Name | Result |
|---|---|
APPROVED, or any other name |
APPROVED |
REJECTED |
DECLINED, responseCode ENTITY_DECLINED |
PENDING |
PENDING (PENDING_REVIEW); turns APPROVED after the async delay, and the confirmation is sent then |
The Outcome scenario overrides the name:
- "succeed" approves every payment;
- "decline" declines with the chosen code:
ENTITY_DECLINED,PAYMENT_NETWORK_REJECTED,INSUFFICIENT_FUNDS,INVALID_CARD,CONTACT_THE_ENTITY,EXPIRED_CARD,RESTRICTED_CARD,ANTIFRAUD_REJECTEDorINTERNAL_PAYMENT_PROVIDER_ERROR; it also declines refunds; - "requires action" leaves payments in review.
Test cards only
A card number must pass the Luhn check and be one of these test numbers. Anything else, including a real card, is refused. Card numbers and security codes are never stored: tokens and transactions keep the masked number, such as 409744******0004, and the call log masks card numbers. Any future expiry date works.
| Method | Numbers |
|---|---|
VISA |
4097440000000004, 4037997623271984, 4111111111111111, 4242424242424242 |
VISA_DEBIT |
4509420000000008 |
MASTERCARD |
5471300000000003, 5120697176068275, 5555555555554444 |
AMEX |
377813000000001 |
DINERS |
36032400000007, 36032404150519 |
CODENSA |
5907120000000009 |
PSE bank transfers
- Read the banks with
GET_BANKS_LIST. - Submit an
AUTHORIZATION_AND_CAPTUREwithpaymentMethod: "PSE"in COP and theseextraParameters:FINANCIAL_INSTITUTION_CODE: apseCode;1022is PayU's test bank;USER_TYPE:Nfor a person,Jfor a company;PSE_REFERENCE2: the document type;PSE_REFERENCE3: the document number;RESPONSE_URL;- optionally
PSE_REFERENCE1, the payer's IP address.
- The answer is
PENDING, withpendingReasonAWAITING_NOTIFICATION,responseCodePENDING_TRANSACTION_CONFIRMATIONandextraParameters.BANK_URL. - Send the payer to
BANK_URL. It opens the mock's simulated PSE bank page, where you choose Approve the transfer, Reject or Let it expire. - The browser returns to
RESPONSE_URLwith PayU's response page fields:merchantId,referenceCode,reference_pol,transactionId;transactionState(4approved,6declined,5expired,7pending) andlapTransactionState;TX_VALUE,currency,cus,pseBank;signature=hash(ApiKey~merchantId~referenceCode~new_value~currency~transactionState), wherenew_valueisTX_VALUErounded half to even to one decimal.
- The confirmation is sent.
With the Outcome scenario set to "decline", PSE transfers are declined at once, with no BANK_URL. The page itself is the "auto" behaviour.
Queries API
POST <base URL>/reports-api/4.0/service.cgi, with details:
| Command | details |
result.payload |
|---|---|---|
ORDER_DETAIL |
{ orderId } |
The order, or null |
ORDER_DETAIL_BY_REFERENCE_CODE |
{ referenceCode } |
Every order with that reference, or null |
TRANSACTION_RESPONSE_DETAIL |
{ transactionId } |
{ state, trazabilityCode, authorizationCode, responseCode, operationDate, … }, or null |
An order has the following fields:
id,referenceCode,description;status:IN_PROGRESS,AUTHORIZED,CAPTURED,CANCELLED,DECLINEDorREFUNDED;additionalValues.TX_VALUE;transactions[], each with:id,type,paymentMethod,parentTransactionId;creditCard.maskedNumber;transactionResponse.state;additionalValues.TX_VALUE.
Tokenisation in the browser (PayU.js)
Load the mock's script instead of PayU's and point it at the mock's token service:
<script src="<base URL>/ppp-web-gateway/javascript/PayU.js"></script>
<form id="card">
<input payu-content="number"> <input payu-content="name_card">
<input payu-content="exp_month"> <input payu-content="exp_year"> <input payu-content="document">
<input type="hidden" payu-content="payer_id" value="customer-123">
</form>
<script>
payU.setURL("<base URL>/payments-api/4.0/service");
payU.setPublicKey("<public key>"); payU.setAccountID("<account id>");
payU.setListBoxID("methods"); payU.setLanguage("es"); payU.getPaymentMethods();
payU.createToken((r) => (r.error ? alert(r.error) : console.log(r.token)), document.getElementById("card"));
</script>The script supports PayU's documented calls:
setURL,setPublicKey,setAccountID,setListBoxID,setLanguage;setCardDetails,getPaymentMethods,validateCard;createToken(callback, form).
It sends the fields marked payu-content straight to the mock's token service (JSONP, GET …/service.token, so a page that allows no connect-src works), never to your page or server. Your server then reads the token with GET_TOKENS by payerId.
Allow the mock's origin in your page's script-src. The test cards and holder names above apply.
Confirmations
When a transaction is final, the mock POSTs PayU's confirmation, form-encoded, to the order's notifyUrl, or to the gateway's webhook URL when the order has none. A final transaction is one that is approved, declined, expired, or an approved review.
The fields:
merchant_id,reference_sale,reference_pol(the order id),transaction_id;state_pol:4approved,6declined,5expired;response_code_pol:1approved,5entity declined,6insufficient funds,20expired,23anti-fraud…;response_message_pol,value(two decimals),currency,tax;payment_method_type:2card,4PSE;payment_method_name,email_buyer,cus,pse_bank,transaction_date,test;sign.
sign = hash(ApiKey~merchant_id~reference_sale~new_value~currency~state_pol), where new_value is value with one decimal when its second decimal is 0 (150000.00 → 150000.0) and with two otherwise (150.25). Compare it to authenticate the confirmation, and answer HTTP 200 to stop retries.
The webhook scenarios (delay, drop, duplicate, bad signature) apply, and failed deliveries are retried.
Not implemented:
- cash and other alternative payment methods;
- WebCheckout;
- 3-D Secure;
- installment plans;
- subscriptions (the Recurring Payments API);
- the XML API;
- countries other than Colombia.