Add the CardCorp iframe checkout to your website and collect metered payments

Learn the payment flow for a metered payments integration. In this model, the customer pays the initial payment with the iframe checkout, and then you collect recurring payments based on customer usage until the order is cancelled.


1. Create the checkout in the payment gateway

The first step is to perform a POST request to the payment gateway to create a checkout, with the payment type, amount, currency, and required attributes.

Here is an example request to create a checkout for the initial payment of a metered order.

curl https://eu-test.oppwa.com/v1/checkouts \
-H "Accept: application/json" \
-H "Content-Type: application/x-www-form-urlencoded; charset=UTF-8" \
-d "entityId={channelId}" \
-d "amount=20.07" \
-d "currency=EUR" \
-d "paymentType=DB" \
-d "integrity=true" \
-d "merchantTransactionId=P130" \
-d "billing.street1=Ave. Diagonal 611" \
-d "billing.city=Barcelona" \
-d "billing.country=ES" \
-d "billing.postcode=08028" \
-d "standingInstruction.type=UNSCHEDULED" \
-d "standingInstruction.mode=INITIAL" \
-d "standingInstruction.source=CIT" \
-d "standingInstruction.expiry=9999-12-31" \
-d "standingInstruction.recurringType=STANDING_ORDER" \
-d "createRegistration=true" \
-d "[email protected]" \
-d "customer.ip=2001:8a0:7f4b:1b00:dd4e:2bf6:1fb8:56af" \
-d "customer.givenName=John" \
-d "customer.surname=Smith" \
-d "customer.phone=34667666666" \
-d "customer.merchantCustomerId=CUST01" \
-d "threeDSecure.challengeIndicator=04" \
-d "customParameters[StoreCredentialType]=CIT" \
-d "customParameters[CRMCustomerID]=CRM CUST01" \
-d "customParameters[MeteredId]=M-00100" \
-d "customParameters[PaymentType]=Metered" \
-d "customParameters[3DS2_enrolled]=true" \
-d "customParameters[3DS2_flow]=challenge" \
-d "testMode=EXTERNAL" \
-H "Authorization: Bearer {auth_token}"

Replace the example values with your values and replace the {channelId} and {auth_token} with your API credentials.

Here are some notes about the parameters in this request

ParametersNotes
paymentTypeCan be DB ("debit") or PA ("preauthorization"). For PA, use the back-office API to capture the payment.
merchantTransactionIdWe recommend that you provide a unique identifier for each transaction.
billing addressThe billing address is required if you use 3DS verification; otherwise, it is recommended.
standingInstruction.typeSet to UNSCHEDULEDto specify an order with recurring payments that may be at irregular intervals.
standingInstruction.modeSet to INITIALto specify the first payment where you are saving a card
standingInstruction.sourceSet to CITto specify a customer-initiated transaction.
standingInstruction.expirySet to 9999-12-31to create a subscription order that is valid until cancelled.
standingInstruction.recurringTypeSet to STANDING_ORDER for a usage-based metered order.
createRegistrationSet to trueto save the customer's card for future payments.
customer detailsWe recommend you supply customer details, including a unique identifier for each customer.
threeDSecure.challengeIndicatorThe recommended value is 04. This means that 3DS is mandated in your region, and it tells the issuer to define the challenge type.
customParametersWe recommend that you add custom parameters to uniquely identify the transaction initiation type, customer, order, and purchase type. The custom data you send in these parameters will be returned in the payment response. You can use these parameters to pair and match information from the payment gateway with your business systems. You can create an unlimited number of unique and properly-named custom parameters.

When you are testing your integration, you can use the following parameters.

ParametersNotes
customParameters[3DS2_enrolled][3DS2_enrolled]This parameter is for the test environment only. Set to true for any card to specify that the card is enrolled in 3DS. Or, instead of the 3DS test parameters, you can use 3DS test cards.
customParameters[3DS2_flow][3DS2_flow]This parameter is for the test environment only. Set to challenge to force a 3DS challenge, or frictionless. Or, instead of the 3DS test parameters, you can use 3DS test cards.
testModeThis parameter is for the test environment only. Set to EXTERNAL to send the transaction to the acquirer's test environment. Set to INTERNAL to process the transaction in the gateway only.

For more details of 3DS testing, see the gateway 3DS testing guide

For full details of all the parameters, see Checkout request attributes.

Your successful request will receive a JSON response.

Response Example:

{
  "result":{
    "code":"000.200.100",
    "description":"successfully created checkout"
  },
  "buildNumber":"d7f3057c29b9a26d5151336767387bb393720d7e@2024-10-14 09:16:49 +0000",
  "timestamp":"2024-10-15 15:16:31+0000",
  "ndc":"FB76D9A1B7D1CAC70A03923F903F74FB.uat01-vm-tx03",
  "id":"FB76D9A1B7D1CAC70A03923F903F74FB.uat01-vm-tx03",
  "integrity":"sha384-/j1gGQsS/nAgGp9u7LjRlD7nwA3h+yXS5aEP/vbzrbpgPWuRDhCuFok3J8lWVC3X"
}

From this response, you will need the value of the id and integrity for the next step.


2. Create the payment form on your web page

To create the payment form on your web page, add the following lines of JavaScript and HTML and enter the following variables.

  1. This script gets the checkout from the payment gateway. Replace the {checkoutId} with the value of the id and replace {integrity} with the value of integrity from the response in Step 1. Replace anonymous with the address of your website that loads the COPYandPAY checkout.
<script 
        src="https://eu-test.oppwa.com/v1/paymentWidgets.js?checkoutId={checkoutId}"
        integrity="{integrity}"
        crossorigin="anonymous">
</script>
  1. This HTML displays the checkout. The shopperResultUrl is a page on your site where customers should be redirected after payment processing.
<form action="{shopperResultUrl}" class="paymentWidgets" data-brands="VISA MASTER"></form>

For example, a checkout script could look like this.

<script src="https://eu-test.oppwa.com/v1/paymentWidgets.js?checkoutId=702B930F656317E0D29A22D195F75A59.uat01-vm-tx03"
        integrity="sha384-KnYRC1jbE3C9SMGbJ5eU2Gx+AM9PCaApfqS6lk8MpPlvk9jIii4PFu297dPu4wcy"
        crossorigin="https://example.com">
</script>

For example, your checkout HTML could look as follows.

<form action="https://myshop.example.com/paid" class="paymentWidgets" data-brands="VISA MASTER"></form>

You can use the same checkout ID multiple times to retrieve a valid payment form. The checkout expires in 30 minutes, and after it expires, you must renew the checkout. Send a new request to create a checkout and use the new checkoutId to create the payment form again.

👍

Customise the payment widget

To customise the payment widget to match the look of your own site, see this customisation guide and the advanced options guide.

You can also add extra fields to this form, for example, to obtain the customer details during checkout.

To display some sample customisations, go to demo checkouts. You can obtain the code for the demo checkouts at Demo checkouts on GitHub.

Here is an example of a basic iframe customisation.

Basic iframe customisation

Basic iframe customisation



3. Get payment status from the checkout in the gateway

When the payment has been processed, CardCorp will redirect the customer to your shopperResultUrl.

To get the payment status, make a GET request to the payment link of your checkout in the gateway, as follows.

curl -G https://eu-test.oppwa.com/v1/checkouts/{id}/payment \
-d "entityId=8ac7a4ca73522ba8017353bdfb9b0639" \
-H "Authorization: Bearer {auth_token}"

Replace the {id}and the {auth_token} with your values.

Here is an example of the result of a successful initial payment for a metered order.

{
  "id":"8ac7a4a1916782af019169e39ef61818",
  "registrationId":"8ac7a49f916780e0019169e39e1713ac",
  "processingEntityId":"{channelId}",
  "paymentType":"DB",
  "paymentBrand":"MASTER",
  "amount":"25.00",
  "currency":"EUR",
  "descriptor":"7446.8562.7815 ECOMChannel",
  "merchantTransactionId":"P130",
  "recurringType":"INITIAL",
  "result":{
    "cvvResponse":"U",
    "code":"000.100.112",
    "description":"Request successfully processed in 'Merchant in Connector Test Mode'"
  },
  "resultDetails":{
    "ExtendedDescription":"Approved",
    "usedChallengeIndicator":"04",
    "clearingInstituteName":"SecureTrading Omnipay Demo",
    "ConnectorTxID1":"099495||true|UMCC525071   ||0819|189| ||RECURRING|80||false|true|false|812|",
    "connectorId":"423209099495",
    "ConnectorTxID3":"423209099495|00|||1||0819090703|||||||||||||Berlin|",
    "ConnectorTxID2":"558420||8ac7a0b491675775019169e3d25a097e",
    "AcquirerResponse":"00",
    "reconciliationId":"7446.8562.7815",
    "CardholderInitiatedTransactionID":"MCC5250710819",
    "SchemeResponseCode":"00"
  },
  "card":{
    "bin":"520000",
    "binCountry":"MY",
    "last4Digits":"0049",
    "holder":"John Smith",
    "expiryMonth":"02",
    "expiryYear":"2027",
    "issuer":{
      "bank":"PUBLIC BANK BERHAD",
      "website":"HTTPS://WWW.PBEBANK.COM/",
      "phone":"1-800-22-5555"
    },
    "type":"CREDIT",
    "level":"STANDARD",
    "country":"MY",
    "maxPanLength":"16",
    "binType":"PERSONAL",
    "regulatedFlag":"N"
  },
  "customer":{
    "givenName":"John",
    "surname":"Smith",
    "merchantCustomerId":"CUST01",
    "phone":"34667666666",
    "email":"[email protected]",
    "ip":"2001:8a0:7f4b:1b00:dd4e:2bf6:1fb8:56af"
  },
  "billing":{
    "street1":"Calle Principal 123",
    "city":"Barcelona",
    "postcode":"08123",
    "country":"ES"
  },
  "threeDSecure":{
    "eci":"02",
    "version":"2.1.0",
    "dsTransactionId":"9b8b228e-feba-434e-a954-08ed1b154edb",
    "challengeMandatedIndicator":"N",
    "transactionStatusReason":"17",
    "acsTransactionId":"06e3eb8a-8732-456c-9e9e-c52bd99d33cf",
    "cardHolderInfo":"",
    "authType":"01",
    "flow":"challenge",
    "authenticationTimestamp":"202408190907",
    "authenticationStatus":"Y",
    "acsReferenceNumber":"b04ea28d11294692a29f63d2f5c84bfc",
    "dsReferenceNumber":"13db2d60d08c4f6b83de194ca5245e57",
    "purchaseDate":"20240819090650"
  },
  "customParameters":{
    "StandingInstructionAPI":"true",
    "SHOPPER_EndToEndIdentity":"1b34e2b5c05526374108fc47dfd00a311f997dbdb35c2a9e5f7a1408e18b96a4",
    "CTPE_DESCRIPTOR_TEMPLATE":"",
    "PaymentType":"Metered",
    "CRMCustomerID":"CRM CUST01",
    "StoredCredentialType":"CIT",
    "3DS2_flow":"challenge",
    "StandingInstruction":"UNSCHEDULED",
    "3DS2_enrolled":"true",
    "MeteredId":"M-00100",
    "StoreCredentialType":"CIT"
  },
  "risk":{
    "score":"0"
  },
  "buildNumber":"58e6de7e1e6a0b42807a3a291ebd50fa46ba3ff9@2024-08-19 00:42:32 +0000",
  "timestamp":"2024-08-19 09:07:03+0000",
  "ndc":"374F736C08602E71675610C05928A121.uat01-vm-tx02",
  "standingInstruction":{
    "source":"CIT",
    "type":"UNSCHEDULED",
    "mode":"INITIAL",
    "initialTransactionId":"MCC5250710819",
    "expiry":"9999-12-31",
    "recurringType":"STANDING_ORDER"
  },
  "source":"OPPUI",
  "paymentMethod":"CC",
  "shortId":"7446.8562.7815"
}

To interpret the payment response, see Transaction results.

To collect a repeated payment for a metered order, you will need the card registrationId and the CardholderInitiatedTransactionID from the payment resultDetails.

There is a request limit for payment status calls, after which the gateway will reduce your access to the endpoint with throttling. You can send two (2) GET payment requests per minute for each checkout ID.

When you get the payment response status, compare the returned values with the expected values for the following fields: ID(s), amount, currency, brand, and type.

After a payment response status is successful, you cannot use the checkout identifier again. So if you need to get the status, use the Transaction Reports endpoint with the payment id. You will also need the id to manage the payment with the Backoffice API. See Backoffice API operations.


4. Collect a repeated payment for a metered order

After you have taken an initial payment and saved the customer's card, you can use the payments API to collect repeated payments for a metered order. You will need the cardholder-initiated transaction identifier from the initial payment.

Perform a POST request to the payment gateway to collect a repeated payment for a metered order.

curl https://eu-test.oppwa.com/v1/registrations/{registrationId}/payments \
-H "Accept: application/json" \
-H "Content-Type: application/x-www-form-urlencoded; charset=UTF-8" \
-d "entityId={channelId}" \
-d "amount=20.08" \
-d "currency=EUR" \
-d "paymentType=DB" \
-d "merchantTransactionId=P131" \
-d "standingInstruction.type=UNSCHEDULED" \
-d "standingInstruction.mode=REPEATED" \
-d "standingInstruction.source=MIT" \
-d "standingInstruction.recurringType=STANDING_ORDER" \
-d "standingInstruction.initialTransactionId={CardholderInitiatedTransactionID}" \
-d "customer.ip=2001:8a0:7f4b:1b00:dd4e:2bf6:1fb8:56af" \
-d "customParameters[CRMCustomerID]=CUST01" \
-d "customParameters[MeteredID]=M-00100" \
-d "customParameters[TransactionID]=P-00006000" \
-d "customParameters[StoreCredentialType]=MIT" \  
-d "testMode=EXTERNAL" \
-H "Authorization: Bearer {auth_token}"

Replace the example values with your values and replace the {channelId} and {auth_token} with your API credentials, and replace the {CardholderInitiatedTransactionID}with the value from your initial transaction.

Here are some notes about the parameters in this request.

ParametersNotes
paymentTypeCan be DB ("debit") or PA ("preauthorization"). For PA, use the back-office API to capture the payment.
merchantTransactionIdWe recommend that you provide a unique identifier for each transaction.
standingInstruction.typeSet to UNSCHEDULEDto specify that you may collect recurring payments at irregular intervals.
standingInstruction.modeSet to REPEATEDto specify a repeated payment using a saved card
standingInstruction.sourceSet to MITto specify a merchant-initiated transaction where the customer is not present.
standingInstruction.recurringTypeSet to STANDING_ORDER for a usage-based metered order.
CardHolderInitiatedTransactionIDUse the value of the CardHolderInitiatedTransactionID that you obtained from the results of the initial payment.
customer detailsWe recommend that you supply the customer's IP address.
customParametersWe recommend that you add custom parameters to uniquely identify the transaction initiation type, customer, order, and purchase type. The custom data you send in these parameters will be returned in the payment response. You can use these parameters to pair and match information from the payment gateway with your business systems. You can create an unlimited number of unique and properly-named custom parameters.

When you are testing your integration, you can use the following parameters.

ParameterNotes
testModeThis parameter is for the test environment only. Set to EXTERNAL to send the transaction to the acquirer's test environment. Set to INTERNAL to process the transaction in the gateway only.

For full details of all the parameters, see Gateway API reference.

You will receive a JSON response like the one below, which shows an approved payment. The important response information is the result code and descriptionfrom the gateway. For more details, see Gateway payment result codes.

{
  "id": "8ac7a4a0913518ad01913699bce8350e",
  "paymentType": "DB",
  "amount": "50.00",
  "currency": "EUR",
  "descriptor": "9657.4052.4575 ECOMChannel ",
  "merchantTransactionId": "P159",
  "result": {
    "code": "000.100.112",
    "description": "Request successfully processed in 'Merchant in Connector Test Mode'"
  },
  "resultDetails": {
    "ExtendedDescription": "Approved",
    "clearingInstituteName": "SecureTrading Omnipay Demo",
    "ConnectorTxID1": "877217||false| MCC634761   ||0809|| ||RECURRING|01||true|true|true|012|1",
    "ConnectorTxID3": "422210877217|00|||1||0809100530|||||||||||||Berlin|",
    "connectorId": "422210877217",
    "ConnectorTxID2": "305373||8ac7a0b49133d47401913699be020bc8",
    "AcquirerResponse": "00",
    "reconciliationId": "9657.4052.4575",
    "merchantAccountId": "8ac7a4c890fc748b0190fe70998c0248",
    "CardholderInitiatedTransactionID": "MCC6347610809",
    "SchemeResponseCode": "00"
  },
  "customer": {
    "ip": "2001:8a0:7f4b:1b00:dd4e:2bf6:1fb8:56af"
  },
  "customParameters": {
    "CRMCustomerID": "CUST01",
    "MeteredID": "M-00100",
    "StoreCredentialType": "MIT",
    "TransactionID": "P-00006021"
  },
  "risk": {
    "score": "0"
  },
  "buildNumber": "174903ec91870d5654938dd40f55da3b35036b23@2024-08-08 12:50:27 +0000",
  "timestamp": "2024-08-09 10:05:31+0000",
  "ndc": "8ac7a4c890fc748b0190fe6ad56b0241_8312a1d9c2fc4011ba07d9a5c9c4a85d",
  "standingInstruction": {
    "source": "MIT",
    "type": "UNSCHEDULED",
    "mode": "REPEATED",
    "initialTransactionId": "MCC6347610809",
    "recurringType": "STANDING_ORDER"
  },
  "source": "OPP",
  "paymentMethod": "CC",
  "shortId": "9657.4052.4575"
}

To interpret the payment response, see Transaction results. You can also use the id to manage the payment with the Backoffice API. See Backoffice API operations.


View the full technical integration guide

The integration guide provides a comprehensive playground with code samples in all major programming languages.

Integration Guide. For request data you can use in the playground, see Gateway playground request data for COPYandPAY.

Questions? - Sign up on our website and talk to our payment experts to learn more about integrating our iFrame checkout.