Skip to content

Payment

In this guide, we will walk you through how to initialize a purchase and complete the transaction for both SVOD: Subscription-based Video on Demand and Transactional Video-On-Demand (TVOD) services.

The prerequisite for this guide is that the viewer needs to be logged in (see End-User Authentication).

With our APIs, you have the flexibility to construct the purchase flow according to your preferences. However, in this guide, we will demonstrate a specific flow when a user is logged in and attempts to access an asset they currently lack access to. This triggers the initiation of the purchase flow as outlined below.

![1169](/images/readme/wNDaGZRwR5adkcr3Y3Vt_Screenshot 2016-03-29 12.36.03.png “Screenshot 2016-03-29 12.36.03.png”)

The steps of this guide will go through the process of Initializing a purchase, creating an order, and then completing the order doing a transaction.

To begin the purchase flow, we present the product groups available for the user. For SVOD, this can include different subscription plans, while for TVOD, it represents individual content for rental or purchase.

To begin, present the product groups that the client can choose from based on the assetId or categoryId the user is trying to access. Fetch the most relevant product groups from the API using the following curl:

curl -X GET \
-H "Accept: application/json" \
"https://api.yoursite.com/api/:platform/asset/:assetId/productgroups"
curl -X GET \
-H "Accept: application/json" \
"https://api.yoursite.com/api/:platform/category/:categoryId/productgroups"
{
"productGroups": {
"productgroup": {
"@id": "(productgroupid)",
"@uri": "/api/(platform)/productgroup/(productgroupid)",
"description": "Dansk Filmskat",
"name": "Dansk Filmskat",
"sortIndex": 1,
"categories": {
"@uri": "/api/(platform)/productgroup/(productgroupid)/categories"
},
"accessType": "PAID",
"metadata": {
"@uri": "/api/metadata/productgroup/(productgroupid)"
},
"products": {
"@uri": "/api/(platform)/productgroup/(productgroupid)/products"
},
"saleStatus": "ENABLED",
"checkAccessForProgramRelations": false
}
}
}
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<productGroups>
<productgroup id="289" uri="/api/web/productgroup/289">
<description>Dansk Filmskat</description>
<name>Dansk Filmskat</name>
<sortIndex>1</sortIndex>
<categories uri="/api/web/productgroup/289/categories"/>
<accessType>PAID</accessType>
<metadata uri="/api/metadata/productgroup/289"/>
<products uri="/api/web/productgroup/289/products"/>
<saleStatus>ENABLED</saleStatus>
<checkAccessForProgramRelations>false</checkAccessForProgramRelations>
</productgroup>
</productGroups>

API reference: Get product groups for Asset

Based on the assetId or categoryId the user is trying to access, you now have the information needed to present the product group options to the users.

If there is only one product group, you may skip displaying product groups and proceed to show available products for that group. Otherwise, let the user choose a product group and continue with the API request to select products for the chosen group.

curl -X GET \
-H "Accept: application/json" \
"https://api.yoursite.com/api/:platform/productgroup/:productgroupId/products
{
"products": {
"product": [
{
"@id": "(productid)",
"@uri": "/api/(platform)/productgroup/(productgroupid)/products/(productid)",
"paymentPlan": {
"@id": "47",
"name": "6 months",
"period": 16070400,
"paymentType": "SUBSCRIPTION"
},
"description": "45 kr. / month",
"enabled": true,
"minimumPeriods": 1,
"price": 270,
"productGroupId": 289,
"sortIndex": 1,
"productPaymentsUri": {
"@uri": "/api/(platform)/productgroup/(productgroupid)/products/(productid)/productPayments"
},
"currency": "DKK",
"productStatus": "ENABLED"
},
{
"@id": "(productid)",
"@uri": "/api/(platform)/productgroup/(productgroupid)/products/(productid)",
"paymentPlan": {
"@id": "1",
"name": "1 måned",
"period": 2678400,
"paymentType": "SUBSCRIPTION"
},
"description": "49 kr / month",
"enabled": false,
"minimumPeriods": 1,
"price": 49,
"productGroupId": 289,
"sortIndex": 0,
"productPaymentsUri": {
"@uri": "/api/(platform)/productgroup/(productgroupid)/products/(productid)/productPayments"
},
"currency": "DKK",
"productStatus": "DISABLED"
},
{
"@id": "(productid)",
"@uri": "/api/(platform)/productgroup/(productgroupid)/products/(productid)",
"paymentPlan": {
"@id": "53",
"name": "12 months",
"period": 32140800,
"paymentType": "SUBSCRIPTION"
},
"description": "39 kr. / month",
"enabled": true,
"minimumPeriods": 1,
"price": 468,
"productGroupId": 289,
"sortIndex": 2,
"productPaymentsUri": {
"@uri": "/api/(platform)/productgroup/(productgroupid)/products/(productid)/productPayments"
},
"currency": "DKK",
"productStatus": "ENABLED"
},
{
"@id": "(productid)",
"@uri": "/api/(platform)/productgroup/(productgroupid)/products/(productid)",
"paymentPlan": {
"@id": "1",
"name": "1 month",
"period": 2678400,
"paymentType": "SUBSCRIPTION"
},
"description": "0 kr. ",
"enabled": true,
"minimumPeriods": 0,
"price": 49,
"productGroupId": 289,
"sortIndex": 0,
"productPaymentsUri": {
"@uri": "/api/(platform)/productgroup/(productgroupid)/products/(productid)/productPayments"
},
"currency": "DKK",
"productStatus": "ENABLED"
}
]
}
}

Having fetched the products for the selected product group, you now have a list of available product options for your client to display. If there is only one product available, consider directing the user directly to the payment options. Otherwise, proceed with the API call to get the payment information for the product.

curl -X GET \
-H "Accept: application/json" \
"https://api.yoursite.com/api/:platform/productgroup/:productgroupId/products/:productId/productPayments"
{
"productPayments": {
"productPayment": {
"@id": "(productpaymentid)",
"@uri": "/api/(platform)/productgroup/(productgroupid)/products/(productid)/productPayments/(productpaymentid)",
"description": "Dansk Filmskat 6 months",
"detailedDescription": "Spar 8%",
"enabled": true,
"initPeriod": 16070400,
"initPrice": 270,
"discountedPrice": 270,
"recurringPrice": 270,
"recurringDiscountedPrice": 270,
"paymentProviderId": 4,
"productId": 5442,
"sortIndex": 1,
"productPaymentStatus": "ENABLED",
"paymentObjectUri": {
"@uri": "/api/(platform)/productgroup/(productgroupid)/products/(productid)/productPayments/(productpaymentid)/payment"
}
}
}
}

API reference: Product Payments

In the above call, you can see this is a subscription that lasts for a period of 6 months (the period is in seconds) where it will auto-renew at the end of the period. Again, if there is only one payment option available, you can continue to the payment step instead of displaying options.

By always skipping steps that have only one element, the purchase flow can be dynamically adjusted to be as easy as possible for the client. Best case they go directly from the asset to the payment page with product information etc displayed.

The final request that’s part of the purchase flow is the one that will give you information about the payment methods as seen in the curl example below.

curl -X GET \
-H "Accept: application/json" \
"https://api.yoursite.com/api/:platform/productgroup/:productgroupId/products/:productId/productpayments/:productpaymentId/payment"
{
"payment": {
"callbackUri": {
"@uri": "/api/(platform)/order/callback"
},
"initializeUri": {
"@uri": "/api/(platform)/order"
},
"url": "https://nordiskfilm.altapaysecure.com/",
"name": "AltaPay",
"paymentMethod": "CREDITCARD"
}
}

API reference: Payment object

In the response above the payment method is “CREDITCARD” - this is all you need to build the form that the user has to fill in. The specifics depend on the provider and payment method, so the form will be different in each case.
Other possible values for payment methods are as follows:

  • CREDITCARD, (The only one we cover in this guide)
  • SMS, (In-house SMS payment)
  • CREDENTIALS, (The user can provide additional credentials to authenticate the use of the partner’s invoice system)
  • REDIRECT, (Indicates that the payment method relies on a redirect payment model, and the client only needs to forward to the provided URL. This is common for credit card payments.)
  • VOUCHER,
  • ONE_CLICK_BUY,
  • ONE_CLICK_BUY_PIN, (one-click-buy that requires pin code validation)
  • INVOICE;

Once the client has chosen the payment method (e.g., “CREDITCARD”), initialize the purchase flow by creating an order using the provided curl request.

curl -X POST \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{
"order": {
"userId": "(userid)",
"productPaymentId": "(productpaymentid)",
"categoryId":"(categoryid)"
}
}' "https://api.yoursite.com/api/(platform)/order/"
{
"order": {
"accessEndDate": "2016-04-22T18:04:10.310Z",
"autorenewStatus": "NOT_STARTED",
"currency": "DKK",
"earliestEndDate": "2016-04-22T15:04:10.310Z",
"endDate": "2016-04-22T15:04:10.310Z",
"id": (orderid),
"ip": "customer-ip",
"payment": {
"name": "CREDITCARD"
},
"period": 2678400,
"platformId": (platformid),
"price": 270.0,
"productGroupId": (productgroupid),
"productId": (productid),
"productName": "Dansk Filmskat 6 months",
"productPaymentId": (productpaymentid),
"startDate": "2016-03-22T15:04:10.310Z",
"status": "INITIALIZE",
"userId": (userid)
}
}

API reference: Create order - 2 step flow

The response will include the order details, indicating that the subscription is initialized but will not start until the order is completed.

Step 6: Supplying a Timezone (for Monthly Renewal)

Section titled “Step 6: Supplying a Timezone (for Monthly Renewal)”

This section is only applicable for subscriptions that renew monthly.

For subscriptions that renew monthly, you can handle timezone differences by supplying a named timezone when creating the order. Alternatively, configure a default timezone using the property api.payment.order.renewal.default.timezone.

When an order is configured with a monthly period (P1M), we have to perform date calculations to figure out when the user should be billed. Since we operate in UTC time by default, some edge cases can appear if the user is located at a different timezone.

For example, if a user in timezone America/Los_Angeles buys a subscription on 30.04 23:15, that is 01.05 06:15 UTC.

The expected billing cycle for the user is 30.05, 30.06, 30.07, but it is in fact 30.05, 29.06, 30.07 when assuming UTC as the timezone.

To fix this issue, it’s possible to supply a named timezone when creating the order

{
"order": {
"timeZone": "America/Los_Angeles"
[...]
}
}

Depending on the payment method and provider we want to complete the order, in this case, we are using a payment method of “CREDITCARD” and need to supply relevant information to the payment provider in the form of the card number, expiration month, expiration year and CVC code.

We do a PUT to the same endpoint we initialized the order and give the payload orderid, productpaymentid and userid along with the payment information.

curl -X PUT \
-H "Accept: application/json" \
-H "Authorization: Bearer (token)" \
-H "Content-Type: application/json" \
-d '{
"order": {
"userId": "(userid)",
"id": "(orderid)",
"productPaymentId": "(productpaymentid)",
"payment": {
"paymentMethod": "CREDITCARD",
"cardNumber": "1111111111111111",
"expireMonth": "11",
"expireYear": "19",
"cvc": "123"
}
}
}' "https://api.yoursite.com/api/(platform)/order/"
{
"order": {
"accessEndDate": "2016-04-22T18:04:10.310Z",
"autorenewStatus": "ACTIVE",
"currency": "DKK",
"earliestEndDate": "2016-04-22T15:04:10.310Z",
"endDate": "2016-04-22T15:04:10.310Z",
"id": 1005,
"ip": "customer-ip",
"price": 270.0,
"productGroupId": 289,
"productId": 5442,
"productName": "Dansk Filmskat 6 months",
"productPaymentId": 4630,
"startDate": "2016-03-22T15:04:10.310Z",
"userId": 12043,
"period": "2678400",
"platformId": "1",
"orderRef": "M69NJL5XH8Y5ZO8UJ",
"status": "ACTIVE"
}
}

API reference: Complete order/1-step flow create order

The response will confirm an active subscription that will auto-renew at the end of the access end-date.

By following these steps, you can seamlessly handle payment transactions and add SVOD or TVOD capabilities to your streaming service.