Checkout with Subscription
Checkout is ideal when you have the traditional shopping cart checkout, where you want to have Upodi return the prices continuously as the cart changes and in the end gets committed
When dealing with a subscription purchase in a Webshop or other type of application, you need to be able to present the final price, the VAT, the available add-on purchases among other things in a shopping cart. This is also in order to be able to tokenize the payment method with the correct amount up-front and do the first purchase, allowing quick rejection in cases where the purchase is being rejected by the payment service provider.
This guide assumes you have already created and configured your Product Plan and you know how to create a Customer.
Idempotency key
Checkout relies on you using the idempotency-key header, which in this case really helps with never sending a sign-up request twice. See Idempotency.
Step 1: Send the Checkout request
Find the Checkout Endpoint documentation here.
curl --location --request PUT 'https://api-front.upodi.io/Checkout' \
--header 'X-version: {version}' \
--header 'Authorization: Bearer {apiKey}' \
--header 'Idempontecy-key: {uniqueKey}' \
--header 'Content-Type: application/json' \
--data-raw '{
"CustomerID" : "guid, required",
"Currency": "string, required",
"Subscription" : {
"ProductPlanID" : "guid, required",
"SubscriptionNumber": "string?",
"StartDate": "datetime?",
"DiscountCode": "string?"
}
}'
CustomerID
: The customer object you want to subscribe. Important in order to know Taxation (VAT).
Currency
: The chosen currency for the purchase in format "EUR".
Subscription
: If the checkout includes a subscription purchase include the subscription object.
ProductPlanID
: The product plan the customer is about to subscribe to.
SubscriptionNumber
: Optional leave out to auto-assign.
StartDate
: Optional only include this if start date is not now.
DiscountCode
: Optional apply a discount code.
The response you get is the full checkout object:
{
"CustomerID" : "guid",
"Currency": "EUR",
"FirstChargeOption" : "integer",
"Subscription": {
"ProductPlanID": "guid",
"StartDate": "2022-02-22 11:47:53.543",
"SendActivationEmail": false,
"Charges": [
{
"ProductPlanChargeID" : "guid",
"Quantity" : "1",
"UnitPrice" : "50",
"Skip" : "false",
"ChargeDate" : "2022-02-22 11:47:53.543"
},
{
"ProductPlanChargeID" : "guid",
"Quantity" : "0",
"UnitPrice" : "100",
"Skip" : false,
"ChargeDate" : "2022-02-22 11:47:53.543"
}
],
},
"Payment": {
"Source": "subscriptionToken",
"Gateway": "string",
"MakeDefault": "bool?"
}
"Result": {
"SummaryInvoice": {
"InvoiceDate: "2022-02-22 11:47:53.543",
.....
}
}
}
The structure of the checkout object
Apart from the parameters you already specified yourself there's going to be a few new ones here.
Charges
: This contains all the item-purchases initially with all the quantities and unitprices from your configuration. Overwrite quantity and/or unitprice to change the checkout result. Skip
is a boolean to control the first billing cycle of each charge as chosen in FirstCharge
:
Payment
: Optional The possibility to fill in the customers' tokenized payment method. Not needed before the final commit made in step 4.
SummaryInvoice
: This is a complete invoice example if the checkout was to be committed. The invoice object is read only meaning all changes to the first purchase would happen through manipulating the Charges
and hereby getting a new Summary Invoice result.
Step 2: Optional change the quantities and prices
You can change the checkout basket of the customer anytime you want and nothing is committed in these PUT
requests.
curl --location --request PUT 'https://api-front.upodi.io/Checkout' \
--header 'X-version: {version}' \
--header 'Authorization: Bearer {apiKey}' \
--header 'Idempontecy-key: {uniqueKey}' \
--header 'Content-Type: application/json' \
--data-raw '{
"CustomerID" : "guid",
"Currency": "EUR",
"Subscription": {
"ProductPlanID": "guid",
"SubscriptionNumber": "SUB-20000053",
"StartDate": "2022-02-22 11:47:53.543",
"SendActivationEmail": false,
"Charges": [
{
"ProductPlanChargeID" : "guid",
"Quantity" : "1",
"UnitPrice" : "50",
"Skip" : "false",
"ChargeDate" : "2022-02-22 11:47:53.543"
},
{
"ProductPlanChargeID" : "guid",
"Quantity" : "1",
"UnitPrice" : "100",
"Skip" : "false",
"ChargeDate" : "2022-02-22 11:47:53.543"
}
]
},
}'
The response would be a new result with an updated Invoice
according to the new Items
changes.
Step 3: Input the customer's payment method
Depending on the customer's chosen payment method you might have to prepare the payment method as a token fx. if the payment method is a credit card. Read more on how to do that in our Credit Cards section and for your specific provider or a Wallet type payment method.
In this example we continue using Nets Easy:
curl --location -g --request POST 'https://api.dibspayment.eu/v1/payments' \
--header 'Authorization: {NetsEasySecretKey}' \
--header 'Content-Type: application/json' \
--header 'Idempontecy-key: {uniqueKey}' \
--header 'Accept: application/json' \
--data-raw '{
"order": {
"items": [
{
"reference": "{invoiceline.sku}",
"name": "{invoiceline.title}",
"quantity": 1.0,
"unit": "pc",
"unitPrice": 50,
"taxRate": 2500,
"taxAmount": 12.5,
"grossTotalAmount": 62.5,
"netTotalAmount": 50
},
{
"reference": "{invoiceline.sku}",
"name": "{invoiceline.title}",
"quantity": 1.0,
"unit": "pc",
"unitPrice": 100,
"taxRate": 2500,
"taxAmount": 25,
"grossTotalAmount": 125,
"netTotalAmount": 100
}
],
"amount": 162.5,
"currency": "EUR"
},
"checkout": {
"termsUrl": "http://ourterms.com",
"merchantHandlesConsumerData": true,
"charge": false,
"returnUrl": "https://example.com/confirmation"
},
"subscription": {
"endDate": "2060-07-18T00:00:00+00:00",
"interval": 0
}
}'
Where the payment provider supports it do avoid actually charging the payment. Here chosen by Charge
set to false
. Refer to your payment service provider to know how and if this is possible for your provider. The Items
section of the payment call here contains all the invoice lines from the SummaryInvoice
result from earlier.
This enables Upodi to be able to go in and find the authorization and then capture it in the next step.
Step 4: Post the checkout to Upodi with payment object
curl --location --request POST 'https://api-front.upodi.io/Checkout' \
--header 'X-version: {version}' \
--header 'Authorization: Bearer {apiKey}' \
--header 'Idempontecy-key: {uniqueKey}' \
--header 'Content-Type: application/json' \
--data-raw '{
"CustomerID" : "guid",
"Currency": "EUR",
"PaymentFailureStrategy": 2,
"FirstChargeOption": 0,
"Payment": {
"Source": "{\"SubscriptionId\":\"{SubscriptionId}\",\"PaymentId\":\"{PaymentId}\"}",
"Gateway": "dibs_easy",
"MakeDefault": "true"
},
"Subscription": {
"ProductPlanID": "guid",
"StartDate": "2022-02-22 11:47:53.543",
"SendActivationEmail": false,
"Charges": [
{
"ProductPlanChargeID" : "guid",
"Quantity" : "1",
"UnitPrice" : "50",
"TotalVat": "12.5",
"Skip" : "false",
"StartDate" : "2022-02-22 11:47:53.543"
},
{
"ProductPlanChargeID" : "guid",
"Quantity" : "1",
"UnitPrice" : "100",
"TotalVat": "25",
"Skip" : false,
"StartDate" : "2022-02-22 11:47:53.543"
}
]
}
}'
Source
is filled in with the SubscriptionId
from Nets Easy in this case and the PaymentId
. For other providers refer to the individual docs to find our what goes in source.
Other optional POST parameters
When you do the final commit there's a few options available, which affects the way the checkout is handled.
PaymentFailureStrategy
: Optional Send 2
if you don't want failed or abandoned payments to be created in Upodi. Will instead return an error directly. Default is 1
which would create the signup regardles of a failed payment.
FirstChargeOption
: Optional Option to skip the first payment attempt in a subscription or invoice purchase in the checkout if you fx. perform the payment outside of Upodi. Just send 0
to actually attempt the payment in Upodi with the payment, which is also the default if not provided.
SendActivationEmail
: Optional if configured in your email template set you can choose to send an email upon activation.
If the payment was successful you receive a 200
response along with an entire JSON body containing both the values you input but also the now committed Invoice
object and the newly created PaymentMethod
object. In case of payment failure it depends on your choice of PaymentFailureStrategy
.
Updated 9 months ago