Skip to main content

Top-Up

Definition

A topup card is a way for your customer to credit money on their account directly from a debit/credit card. There are different methods to do a topup.

Refere to this page for the functionnal overview: https://docs.xpollens.com/docs/payments/topup/#xpollens-shop-integration


Top-up state diagram


Statut codeStatus name
0Approved
1Completed
2Refunded
3Rejected

General rules

A top-up amount must be between 1€ and 1000€ (excluded).
A user cannot make more than 5 top-ups within a 48-hour period. You cannot load an account with a card belonging to that account.


Create a top-up

Top-up types

There are 4 possibilities for the top-up:

  • create a top-up without card registration.
    The card information will have to be filled in again the next time a topup is done.
  • create a top-up with card registration.
    This first top-up is necessary for one-click top-ups.
  • create a one-click top-up.
    this is possible only if the card is registred. In this case, the card information was registred during the first top-up, and is not needed during the one-click top-up. Only the 3DS validation remains to be done.
  • creation of a subscription, or reccurent top-up
    Enabling the card to be saved and not having to validate it on the 3DS the next time it is loaded: it is called "recurrent"
note

The one-click top-up is customer-initiated.

note

Subscription top-up, on the other hand, is reserved exclusively for the partner initiative, for example to take expenses or a subscription. It is forbidden to use it on a customer's initiative, in order to dispense with 3DS. For all customer-initiated top-ups, the 3DS is mandatory.

Hosted fields

To create a top-up, you need to implement the Dalenys hosted fields.
Please refere to this documentation: https://developer.dalenys.com/ui/developer-doc/integration-modes/hosted-fields.html


Top-up sequence diagram


3DS top-up with / without card registration

If the user wants to save the card information, the attribute Card is not null.
In this case, for the next top-up:

  • the user will not have to fill in the card information
  • the user will still need to validate the 3DS

Case 1: without card registration

POST /api/v1.1/payins/cardpayments

  • the appCardId is not filled
{
[...]
"card": {
"hfToken": "xxx"
[...]
}

Case 2: with card registration

POST /api/v1.1/payins/cardpayments

{
[...]
"card": {
"hfToken": "xxx",
"appCardId": "CB_Test"
},
[...]
}

One-click payment (with 3DS validation)

The card must already be registered.

To create a top up oneclick, you must, in the body of the request, add and fill in the appCardId parameter instead of the hfToken parameter. This will allow you to directly call the previously registered bank card.

POST /api/v1.1/payins/cardpayments

{
[...]
"card": {
"appCardId": "CB_Test",
},
"subscriptionTopUp": false
[...]

}

With subscription (one-click without 3DS validation)

The card must already be registered.

1st request

  • appCardId and hfToken
  • 3DS validation

POST /api/v1.1/payins/cardpayments

{
[...]
"card": {
"hfToken": "xxx"
"appCardId": "CB_Test",
},
[...]
}

Next request

  • no hfToken, only the appCardId
  • no 3DS validation

POST /api/v1.1/payins/cardpayments

{
[...]
"card": {
"appCardId": "CB_Test"
},
"subscriptionTopUp": true
[...]
}

Top-up life cycle

EtapeDefinition---Response
1Creation of the authorisation at Xpollens sidePrerequesite:
- request is correct.
- Xpollens controls are OK.
post/v1.1/payins/cardpayments -> Response 200
23DS authenticationIf KO, callback 1 {status 3}
3Creation of the authorisation on the Payplug side.If OK, callback 1 {status: 1}.
If KO, callback 1 {status: 3}


Erros Code: response 400

MessageError
When Hftoken is not filled
{
"Code": 354,
"ErrorMessage": "Erreur module de rechargement",
"Title": "",
"Priority": 2
}
When card is already registrered
{
"Code": 717,
"ErrorMessage": "CardId déjà existant.",
"Title": "L'opération ne peut pas aboutir",
"Priority": 2
}
When OrderId already exists
{
"Code": 710,
"ErrorMessage": "OrderId déjà existant.",
"Title": "L'opération ne peut pas aboutir",
"Priority": 2
}
When the card is not found
{
"Code": 195,
"ErrorMessage": "Carte de crédit introuvable",
"Title": "L'opération ne peut pas aboutir",
"Priority": 2
}
When Payer name is not filled
{
"Code": 177,
"ErrorMessage": "Valeur de paramètre invalide ('Name' ne doit pas être vide.)",
"Title": "L'opération ne peut pas aboutir",
"Priority": 2
}
When Amount is not filled
{
"Code": 178,
"ErrorMessage": "Les paramètres suivants sont invalides : cardPaymentRequestDto.Payments\[0\].Amount.",
"Title": "L'opération ne peut pas aboutir",
"Priority": 2
}
When amount is lower or equal to 0
{
"Code": 177,
"ErrorMessage": "Valeur de paramètre invalide ('Amount' doit être plus grand à '0'.)",
"Title": "L'opération ne peut pas aboutir",
"Priority": 2
}
When AppAcountId is not filled
{
"Code": 178,
"ErrorMessage": "Les paramètres suivants sont invalides : cardPaymentRequestDto.Payments\[0\].Beneficiary.AppAccountId.",
"Title": "L'opération ne peut pas aboutir",
"Priority": 2
}
When AppAcountId is not filled
{
"Code": 149,
"ErrorMessage": "Plafond de transaction atteint",
"Title": "Opération non autorisée"
}

ExecCode: Execution Code

The ExecCode translates the status of the CB loading at the PayPlug level and the 3DS validation.

The GET {{URLT}}/v1.1/users/{appUserId}/payins/cardpayments/{orderId} retrieves details.

The execution codes are organized with different ranges:

  • 0XXX operation succeeded or still processing
  • 4XXX operation rejected because of the bank or the supplier
  • 5XXX operation rejected because of a system error
  • 6XXX operation rejected because of anti-fraud engine
CODEMessageTop-up status
0000Successful operation1
00013-D Secure authentication required0
4001Transaction declined by the banking network3
4002Insufficient funds3
4003Card declined by the banking network3
4004The transaction has been abandoned3
4005Fraud suspicion3
40093DSecure authentication abandoned or expired3
4010Invalid transaction3
4011Duplicated transaction3
4012Invalid card data3
4013Transaction not allowed by banking network for this holder3
4014Non 3-D Secure-enrolled card3
4015Expired transaction3
4016Transaction declined by the payment terminal3
4017Form expiration (as planed by the merchant)3
4018Recurring payment revocated for this card holder3
4019The bank will decline further transactions from this card3
4020Strong customer authentication required by issuer3
4021Operation not allowed / not supported3
5001Exchange protocol failure3
5002Banking network error3
5003System under maintenance, please try again later3
5004Time out, the response will be sent to the notification URL (only applicable for Visa / MasterCard direct connection)3
50053-D Secure authentication error3
5006Unexpected bank response3
6001Transaction declined by the merchant3
6002Transaction declined3
6003The cardholder has already disputed a transaction3
6004Transaction declined by merchant and/or platform rules3
6005Card not enrolled or 3-D secure unavailable3
6006Blocked payment method3
6007Operation prohibited by the bank networks3
6008Card holder has already declared transaction as fraudulent3

API, callbacks and technical items

Callbacks

Callback1 : https://docs.xpollens.com/api/Callbacks#post-/-callback01Url-
Callback5 : https://docs.xpollens.com/api/Callbacks#post-/-callback05Url-


API

POST /api/v1.1/payins/cardpayments
TermsAndConditionsValidationDate: date/time UTC+3
date: date/time UTC+2

NameTypeRequiredRestrictionsDescription
Messagestringfalse-Obsolete
OrderIdstringtrue-transaction Id
UrlReturnstringfalse-URL to redirect your enduser after the top-up
Statusintegerfalse-Obsolete, don't use
TermsAndConditions
ValidationDate
date-timetrueyyyy-mm-ddT1hh:mm:ss.xxxxxxxTop-up date
Payer.namestringtrue-First Name & Last name of the payer
Payer.emailstringtrue-Obsolete, use your enduser's email address
Payer.userAgentstringtrue-Obsolete, use "{partnerName} Browser"
Payer.urlReferrerstringtrue-Obsolete, use your website address
Payer.ipAddressstringtrue-Ip address of the user (ipv4 or v6)
Card.HfTokenstringfalse - 
depending of the use case
-Hf token previously created
Card.AppCardIdstringfalse - 
depending of the use case
Existing cardToken of the card used for the top-up
Card.Statusintegerfalse-Obsolete
Card.HintObsoletefalse-Obsolete
Card.ExpiryDatestringfalse-Obsolete
Card.IsActivestringfalse-Obsolete
Payments.OrderIdstringtrue-Obsolete, use payment_orderId
Payments.Amountstringtrue-Amount in cents
Payments.Feestringfalse-Obsolete, use the P2P post to debit fees
Payments.
Beneficiary.AppAccountId
stringtrueExisting account for the appUserIdappAccountId to credit
Payments.Messagestringfalse-Obsolete
Payments.Statutstringfalse-Obsolete
SubscriptionTopUpstringfalsetrue/falseSubscription for a topup

Get a top-up

By orderid

GET /api/v1.1/users/{userid}/payins/cardpayments/{id}

date: date/time UTC+2

Response code 200

NameTypeTo useValueDescription
MessagestringYes-Obsolete
OrderIdstringYes-transaction Id
UrlReturnstringYes-URL to redirect your enduser after the top-up
StatusintegerYes-Obsolete, don't use
Payer.namestringYes-First Name & Last name of the payer
Payer.emailstringYes-Obsolete
Payer.userAgentstringYes-Obsolete
Payer.urlReferrerstringYes-Obsolete
Payer.ipAddressstringYes-Enduser Ip address
Card.AppCardIdstringYesGiven name to the used cardToken of the card used for the top-up
Card.Statusintegerno0Obsolete
Card.HintObsoleteno-Obsolete
Card.ExpiryDatestringno-Obsolete
Card.IsActivestringno-Obsolete
Payments.OrderIdstringno-Obsolete, use orderId
Payments.AmountstringYes-Amount of the top-up
Payments.Feestringno0.0Obsolete, use the P2P post to debit fees
Payments.
Beneficiary.AppAccountId
stringYesExisting account for the appUserIdappAccountId to credit
Payments.MessagestringnonullObsolete
Payments.Statutstringno0Obsolete
ExtraResult.TransactionIdstringno-Obsolete
ExtraResult.ExecCodestringYes-excution code on Payplug side
ExtraResult.MessagestringYes-Translation of the ExecCode
ExtraResult.CurrencystringnonullObsolete
ExtraResult.ThreeDSecurestringnonullObsolete
ExtraResult.ThreeDSAuthenticationStatusstringnonullObsolete
extraResult.AuthorizationNumberstringnonullObsolete
extraResult.CardNetworkstringnonullObsolete
extraResult.CardValidityDatestringnonullObsolete
extraResult.CardCountrystringnonullObsolete
extraResult.CardFullnamestringnonullObsolete
extraResult.CardThreeDSecureEnrolledstringnonullObsolete
extraResult.ThreeDSecureVersionstringno0Obsolete
extraResult.ThreeDSGlobalStatusstringnonullObsolete
extraResult.VersionstringnonullObsolete
extraResult.CardTypestringnonullObsolete
TermsAndConditions
ValidationDate
date-timeYesyyyy-mm-ddThh:mm:ss.xxxxxxxSame value than the post
Datedate-timeYestrue/falseUTC (FR)
Refundsstringfalse-Details of the refund

Get All top-up

GET /api/v1.1/users/{userid}/payins/cardpayments


IMPORTANT

When The GET /api/v1.1/users/{userid}/payins/cardpayments API is called without additional parameters (startDate, endDate)it will return the user top-ups starting 30 days before the current date until the current date.


The maximum timeframe between startDate and endDate is 31 days.


If the timeframe exceeds 31 days then an exception (http/400) will be raised by the API.

{
"code": 1,
"errorMessage": "Unknown technical error, please contact Xpollens support. Max date range allowed is 31 days.",
"title": "Technical error",
"priority": 2,
"date": "2024-06-17T15:04:39.3684193Z",
"operationId": "f7903cd3b34ef856bfdf493d4ad65f9f",
"httpStatusCode": 400
}

Refund a top-up

Top-up reimbursement may be total or partial.
This reimbursement allows you to return to the original situation in terms of creditlimit, as if the initial operation had not taken place.

Post refund

POST /api/v1.1/users/{userid}/payins/cardpayments/{orderId}/payments/{paymentid}/refunds
where orderId = orderId of the original transaction
and paymentId = paymentId of the original transaction

NameTypeRequiredRestrictionDescription
idstringObsoleteObsoleteObsolete
amountstringMandatory- Cents
- Can not be higher than the original amount
Amount of the refund
feestringObsoleteObsoleteObsolete
orderIdstringMandatoryUnique orderIdYour orderId for the refund
statusstringObsolete-Obsolete

Note: If the cancellation is made on the same day, before the merchant discount, then there is only one transaction, with the status Refund.
In the opposite case, two operations will exist: the original operation with Completed status, and the Refund operation with status Completed and Rtransaction = true

Response

Response

NameTypeTo useValueDescription
IdstringnoObsoleteXpollens internal transaction id
OrderIdstringYes-transaction orderId
AmountstringYesXX.XXAmount €
FeestringnoObsoleteObsolete
StatusstringYes1refund status completed
PaymentDatestringYesUTC+3date of the refund
OriginalPayment.IdstringnoObsoleteObsolete
OriginalPayment.OrderIdstringYes-initial top-up
OriginalPayment.HrefstringnoObsoleteObsolete
Typestringno1Obsolete

Error codes

MessageError
Insufficient balance
{
"Code": 110,
"ErrorMessage": "Votre solde est insuffisant pour effectuer ce virement. Veuillez saisir un autre montant.",
"Title": "Opération non autorisée",
"Priority": 2,
"Date": "2024-04-25T09:39:57.3326109Z",
"OperationId": "2cb1cd79829d041fe2fd0c4c5274ce03"
}
Status of the top-up is not "Completed"
{
"Code": 364,
"ErrorMessage": "Opération invalide",
"Title": "L'opération ne peut pas aboutir",
"Priority": 2,
"Date": "2024-04-25T09:46:57.8817933Z",
"OperationId": "7b2e38c3ac31db9d1256aea67f7b7b7f"
}
Refund orderId already exists
{
"Code": 364,
"ErrorMessage": "Opération invalide",
"Title": "L'opération ne peut pas aboutir",
"Priority": 2,
"Date": "2024-04-25T09:46:57.8817933Z",
"OperationId": "7b2e38c3ac31db9d1256aea67f7b7b7f"
}
Refund amount = 0
{
"Code": 704,
"ErrorMessage": "Paramètre(s) d'appel manquant(s) ({0}). amount is invalid",
"Title": "L'opération ne peut pas aboutir",
"Priority": 2,
"Date": "2024-05-15T13:50:27.452768Z",
"OperationId": "bcb194d1af237f8bab8c1697c41bf67c"
}
Sum of refunds > initial transaction amount
{
"Code": 706,
"ErrorMessage": "Le montant du remboursement dépasse le montant de l'opération originale.",
"Title": "L'opération ne peut pas aboutir",
"Priority": 2,
"Date": "2024-05-15T13:48:34.9307117Z",
"OperationId": "74204d2cabbcdac8293458f5a0a07404"
}
Top-up already refunds through Payplug BackOffice
{
"Code": 707,
"ErrorMessage": "{0}",
"Title": "L'opération ne peut pas aboutir",
"Priority": 2,
"Date": "2024-05-07T15:26:20.9242088Z",
"OperationId": "1ff1458942d8c1f1914cfe27640abf4e"
}
Transaction already refunded totally
{
"Code": 708,
"ErrorMessage": "Statut du paiement incohérent",
"Title": "L'opération ne peut pas aboutir",
"Priority": 2,
"Date": "2024-04-25T09:43:53.2930334Z",
"OperationId": "57591d396a793b2156053840cec15ee8"
}

How to test

Sandbox

1- Get a HF TOKEN

On test environments, you can either use the integrated payment HTML page provided by Dalenys or use the following API to get an HFToken

POST https://secure-test.be2bill.com/hosted-fields/service/tokenize

with the following parameters (x-www-form-urlencoded) :

CARDCODE=4464215790990001
CARDVALIDITYDATE=06/24
CARDCVV=123
SELECTEDBRAND=visa
APIKEYID=<provided on demand>

cUrl example

curl -X POST -k -H 'Content-Type: application/x-www-form-urlencoded' \ 
-i 'https://secure-test.be2bill.com/hosted-fields/service/tokenize' \
--data 'CARDCODE=4464215790990001&CARDVALIDITYDATE=06/24&CARDCVV=123&SELECTEDBRAND=visa&APIKEYID=<PROVIDED ON DEMAND>'

Response code

{
"EXECCODE": "0000",
"MESSAGE": "Operation succeeded.",
"HFTOKEN": "7016e7df-04ef-4c92-83e2-8c5d1155c2b6",
"CARDTYPE": "VISA",
"CARDVALIDITYDATE": "06-24",
"CARDCODE": "446421XXXXXX0001",
"SELECTEDBRAND": "visa",
"BINTYPE": "Consumer",
"BINBRANDS": [
{
"BRAND": "VISA",
"SERVICETYPE": "Debit"
}
],
"BINNETWORK": "VISA"
}

2- Create a top_up with

POST {{URLT}}/v1.1/payins/cardpayments

{
"OrderId": "{{orderId_TOPUP_1}}",
"UrlReturn": "http://rest-integ.s-money.net/HostedFieldsApp/v2/ProcessTopUp",
"Payer": {
"Name": "Jean DUPONT",
"Email": "jean_dupont@gmail.com",
"UserAgent": "Mozilla/5.0 CK={​​}​​ (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko",
"UrlReferrer": "https://www.s-money.fr?cart=473",
"IpAddress": "127.0.0.1"
},
"subscriptionTopUp": false,
"Card": {
"HFToken":"{{HFTOKEN}}",
"AppCardId": "CB_{{orderId_TOPUP_1}}"
},
"TermsAndConditionsValidationDate": "2022-05-17T17:00:48.0255806+01:00",
"Payments": [
{
"OrderId": "payment_{{orderId_TOPUP_1}}",
"Amount": 100, //cents
"Fee": 0, // cents
"Beneficiary": {
"AppAccountId": "{{accountId}}"
}
}
]
}

3- Validate 3DS

On postman, click on visualize > Inspect vizualisation > copy link address
Paste it in your browser.
Validate 3DS.


4- Create a refund

POST {{URLT}}/V1.1/users/{{accountId}}/payins/cardpayments/{{orderIdTOPUP_1}}/payments/payment{{orderId_TOPUP_1}}/refunds

{
"orderid" : "orderId_refund",
"amount" : {amount} //cents
}

Production

When the alphatests are launched, the Payplug library and url configurations need to be modified. Ask your Customer Integration Manager.


FAQ

Can I access to the Payplug backoffice?

No, you don't have access. Only xpollens employees have access.

After a top-up, how to redirect my enduser from the 3DS page to the application.

You need to fill the UrlReturn in the post.

Can I customise the 3DS page?

No, you can only modify the logo and the merchant name.

I can't find my top-ups

The GET /api/v1.1/users/{userid}/payins/cardpayments has some limitations regarding the timeframe and the maximum number of records it can return.

Please see the note here for more detailed information : Get All top-ups