Payments
The hosted payment page
Section titled “The hosted payment page”Send checkout with a return_url in POST /payments and the payment comes with checkout.url, our page for the payer on your account’s own domain, in your brand. The Hosted payment page guide covers the request, the way back, the iframe and the WebView cases and the page’s options.
Traffic type
Section titled “Traffic type”Tell us with traffic_type in POST /payments whose deposit a payment is: ftd, the customer’s first deposit with you, or std, a subsequent one. A payment without it is ftd, so mark subsequent deposits std. The payment keeps the type for good, answers it in traffic_type (and, once they are here, in its webhooks), and GET /payments?traffic_type=std lists one type.
- Our team can turn either type off on your account, and on again. A payment of a type turned off is
400 traffic_type_disabledwithparam: traffic_type, and nothing is made. Withftdoff, a request withouttraffic_typeis refused too. - Turning a type off stops new payments only: payments already made, and their hosted pages, carry on.
- A value other than
ftdorstd, the empty one too, is400 parameter_invalid.
The customer’s tax id
Section titled “The customer’s tax id”In markets whose payments take one (Argentina), send the payer’s tax id in customer.tax_id of POST /payments. We find the payer by it when their transfer comes: their bank sends us the sender’s CUIT, and we compare the DNI inside it.
"customer": { "id": "user_1234567890", "tax_id": { "type": "ar_cuil", "value": "27-12345678-0" }}typeisar_cuitorar_cuil, 11 digits whose last is the check digit, orar_dni, 7 or 8 digits.valuemay have dashes, dots and spaces.- Payers often get the first two digits of a CUIT or CUIL wrong. When the check digit does not fit the number but does fit one of a person’s prefixes (20, 23, 24 or 27) for the same DNI, we take the number as that DNI instead of refusing it.
- Any other number that is not one is
400 tax_id_invalidwithparam: customer.tax_idand the reason inmessage. Atax_idwithout itstypeorvalueis400 parameter_missing, and anothertype400 parameter_invalidwithparam: customer.tax_id.type. - A market whose payments do not take a tax id, such as India, answers
400 parameter_unknownfor a well-formed one. - We keep the number encrypted and never write it to our logs.
A transfer in Argentina
Section titled “A transfer in Argentina”In Argentina the payer transfers pesos from their own bank or wallet (Mercado Pago, Ualá, Brubank…) to a CVU we give, or to its alias. Create the payment with payment_method_data.type ar_bank_transfer and the payer’s tax id:
{ "amount": 1000000, "currency": "ARS", "merchant_reference": "dep_000123", "payment_method_data": { "type": "ar_bank_transfer" }, "customer": { "id": "user_1234567890", "tax_id": { "type": "ar_cuil", "value": "27-12345678-0" } }}- The amount is whole pesos, from 2,000 to 2,000,000: a multiple of 100 centavos. One with centavos is
400 amount_not_wholewithparam: amount; one outside the range400 amount_too_smalloramount_too_large. - When you show the payer the details yourself,
customer.tax_idis required: without it,400 parameter_missingwithparam: customer.tax_id. - With
checkout, our hosted page shows the transfer in Spanish.customer.tax_idis then optional: when you send none, the page asks the payer for their DNI, CUIT or CUIL before it shows where to pay. The payer copies the CVU or the alias, transfers from their bank, and taps «Ya transferí»; the page then shows that the payment is being checked, and asks for the COELSA id on the receipt only if it is not found half an hour after that; a payer who never tapped «Ya transferí» is asked once the time to pay ran out. next_actionisdisplay_bank_transfer_instructions, as Stripe’s bank transfers have it:
"next_action": { "type": "display_bank_transfer_instructions", "display_bank_transfer_instructions": { "type": "ar_bank_transfer", "amount_remaining": 1000000, "currency": "ARS", "financial_addresses": [ { "type": "cvu", "cvu": { "cvu": "0000009300000000000017" } }, { "type": "alias", "alias": { "alias": "pago.tienda.ars" } } ], "hosted_instructions_url": "https://pay.your-shop.com/c/..." }}- Show the payer the amount, the CVU and the alias: either reaches the same account. Each address is an object under its type’s name, as Stripe’s
financial_addressesare, so it can carry more later; a wallet without an alias gives the CVU alone.hosted_instructions_urlis our page with the same details, which you can send the payer to; it isnullwhen your account has no page domain. There is no reference to put on the transfer. Once the payer says they paid, confirm the payment with the COELSA id on their receipt:POST /payments/{id}/confirmationswithcoelsa_id(1 to 64 letters, digits, dashes and underscores), asconfirmation_fieldsnames it. For now our team checks each confirmed transfer against the money that came and marks the payment paid; finding the transfer by the tax id of the account it comes from comes next. - We do not give the account’s holder: your payer’s app may show another name than yours, which is right.
What arrived and what to credit
Section titled “What arrived and what to credit”Once a payment is succeeded it says what arrived and what you credit your customer. Each of these is null until then.
amount_paid: what arrived from the payer’s bank, in the smallest unit.amount_credited: what to credit your customer. It is the amount you asked for when the payer paid exactlyamount_payable, andamount_paidotherwise. Credit this. (amount_receivedis the same amount, under its first name.)amount_mismatch:truewhen the payer paid other thanamount_payable, soamount_creditedisamount_paidrather than the amount you asked for.
This is how Stripe has amount_received beside amount: what arrived can differ from what you asked for.
The payment’s version
Section titled “The payment’s version”version grows with every change of a payment. Of two copies of the same payment, the one with the higher version is the newer: a webhook event’s data.object has the version of that event, so an event whose version is lower than one you already processed is an older change, and you can ignore it.
Confirming a payment
Section titled “Confirming a payment”When your payer tells you they paid and gives you the transaction’s reference (in India, the 12-digit UTR their UPI app shows), you can pass it on with POST /payments/{id}/confirmations. It is optional: we match payments without it. We keep what you send with the payment, as your payer’s word, for our checks and our team. A payment’s confirmation_fields name the fields your market takes and the pattern each must match.
- A confirmation is not proof. A payment waiting for the payer is
processingafter it and staysprocessingwhile we look for its money: it succeeds when we see it, and fails if we have not seen it 24 hours after your confirmation. - The answer is
200with the payment, whether or not its money arrived yet: a payment that succeeds comes as the webhook eventpayment.succeeded. The same value again on the same payment answers it again and records nothing new, and so does the reference of the bank transaction that paid it, after it succeeded too; another value is kept beside the first. - A UTR is one UPI transaction, so it confirms one payment: a value already confirmed on another payment, or one that paid another payment, is
409 reference_already_used. One that does not match the field’s pattern is400 parameter_invalid. - A payment takes at most 3 different values: more is
400 parameter_invalid. A value holds only while its payment is open: once that payment succeeded or failed, the value can confirm another payment. - An expired payment takes the confirmation and stays
expired: if the money arrives in time, it still succeeds. A payment that succeeded or failed refuses one:409 payment_final. - A method with no
confirmation_fieldstakes none:400 confirmation_not_supported.
Endpoints
GET/paymentsListPaymentsPOST/paymentsCreatePaymentGET/payments/{id}GetPaymentPOST/payments/{id}/confirmationsConfirmPayment
Loading the reference…