There are two workflows for card storage. 

OPTION 1 - Card storage with a checkout
OPTION 2 - Card storage without a checkout


If your workflow is :

  •  Customer adds card
  •  Your systems store card token
  •  When the amount is due, the stored card is billed


Please see sample code below - please refer to our technical documentation for conclusive instructions:


Customer adds card



curl https://eu-test.oppwa.com/v1/payments \

entityId=8a8294174e735d0c014e78cf26461790

amount=1.00

currency=ZAR

paymentBrand=VISA

paymentType=PA

card.number= 4111111111111111

card.holder=Jane Jones

card.expiryMonth=05

card.expiryYear=2020

card.cvv=123

standingInstruction.mode=INITIAL

standingInstruction.type=UNSCHEDULED

standingInstruction.source=CIT

createRegistration=true

shopperResultUrl=https://peachpayments.docs.oppwa.com/tutorials/server-to-server


This will validate the card and once validated, store the card details and return a payload.


This R1.00 PA is done to check that the card being added is valid, before you store the card for future billing.


This R1.00 amount should return to the customer's account after a period ; i.e, their balance will increase by R1.00 when the PA falls away (period differs from bank to bank).


If this R1.00 PA is not done, first of all the card storage transaction cannot be 3DSecure authenticated and secondly, you may store cards that cannot be billed at a later stage. This does not ensure that you can charge the full amount (since most likely the basket value would be greater than R1.00), but it at least checks with the bank that the card is valid.


Your systems store card token


The payload (response from our systems) will include a registrationID, which you can save as the token of the card. You can then make payments on this stored card by referencing its token. Please only store the token in your database if the PA transaction is successful


When amount is due, stored card is billed


curl https://eu-test.oppwa.com/v1/registrations/{id}/payments \

-d "entityId=XXXXXXXXXXXXXXXXXXXXXXXXXXX" \

-d "amount=92.00" \

-d "currency=ZAR" \

-d "standingInstruction.mode=REPEATED" \

-d "standingInstruction.type=UNSCHEDULED" \

-d "standingInstruction.source=MIT" \

-H "Authorization: Bearer XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX=="


Please note that the entity ID here should be the recurring entityID -d "authentication.entityId=XXXXXXXX" \

IF you were only supplied one entityID, as long as the recurringType parameter indicates REPEATED, this will still direct the transaction to skip 3DSecure


HOW TO MAKE 3DSECURE SUBSEQUENT PAYMENTS ON STORED CARDS / TOKENS


If you would want to take the subsequent payments through 3DSecure, then you would use the 3DSecure entityID and remove the standingInstruction.mode=REPEATED, standingInstruction.type=UNSCHEDULED and standingInstruction.source=MIT 
parameters. This will make sure the transaction triggers an OTP for 3DSecure authentication, rather than skip 3DSecure as required for subscription models, with no customer interaction.

In this case, you would have


curl https://eu-test.oppwa.com/v1/registrations/{id}/payments \

-d "entityId=XXXXXXXXXXXXXXXXXXXXXXXXXXX" \

-d "amount=92.00" \

-d "currency=ZAR" \

-d "paymentType=DB" \

-d "standingInstruction.mode=REPEATED" \

-d "standingInstruction.type=UNSCHEDULED" \

-d "standingInstruction.source=MIT" \

-H "Authorization: Bearer XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX=="


Please note that the entity ID here should be the 3DSECURE entityID -d "entityId=XXXXXXXX" \

If you only have one entityID, this will by default be the 3DSecure entityID.


Please see how to handle the 3DSecure redirect 
here