Get a subscription
curl --request GET \
--url https://api-eu.flexportal.io/v1/subscriptions/{subscriptionId} \
--header 'Authorization: Bearer <token>' \
--header 'Tenant-ID: <tenant-id>'import requests
url = "https://api-eu.flexportal.io/v1/subscriptions/{subscriptionId}"
headers = {
"Tenant-ID": "<tenant-id>",
"Authorization": "Bearer <token>"
}
response = requests.get(url, headers=headers)
print(response.text)const options = {
method: 'GET',
headers: {'Tenant-ID': '<tenant-id>', Authorization: 'Bearer <token>'}
};
fetch('https://api-eu.flexportal.io/v1/subscriptions/{subscriptionId}', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api-eu.flexportal.io/v1/subscriptions/{subscriptionId}",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Tenant-ID: <tenant-id>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api-eu.flexportal.io/v1/subscriptions/{subscriptionId}"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("Tenant-ID", "<tenant-id>")
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://api-eu.flexportal.io/v1/subscriptions/{subscriptionId}")
.header("Tenant-ID", "<tenant-id>")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api-eu.flexportal.io/v1/subscriptions/{subscriptionId}")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["Tenant-ID"] = '<tenant-id>'
request["Authorization"] = 'Bearer <token>'
response = http.request(request)
puts response.read_body{
"rentalId": "<string>",
"tenantId": "<string>",
"assetSerialNumber": "<string>",
"customerId": "<string>",
"sku": "<string>",
"productName": "<string>",
"monthlyAmount": 123,
"currency": "<string>",
"status": "active",
"originalContractLength": 123,
"contractLength": 123,
"startDate": "<string>",
"orderId": "<string>",
"customerEmail": "<string>",
"customerName": "<string>",
"createdAt": "<string>",
"updatedAt": "<string>",
"createdBy": "<string>",
"productId": "<string>",
"variantId": "<string>",
"productImageUrl": "<string>",
"billingGroupId": "<string>",
"endDate": "<string>",
"nextBillingDate": "<string>",
"lastModifiedDate": "<string>",
"extensionHistory": [
{
"extensionMonths": 60,
"oldContractLength": 60,
"newContractLength": 60,
"oldMonthlyAmount": 1,
"newMonthlyAmount": 1,
"extendedBy": {
"userId": "<string>",
"email": "<string>",
"displayName": "<string>",
"role": "<string>",
"memberId": "<string>"
},
"oldEndDate": "<string>",
"newEndDate": "<string>",
"extendedAt": "<string>",
"reason": "<string>",
"notes": "<string>"
}
],
"actualMonthsRented": 123,
"monthsSaved": 123,
"listPrice": 123,
"listPriceSource": "variant",
"listPriceCapturedAt": "<string>",
"acquisitionCost": 123,
"acquisitionCostSource": "variant",
"acquisitionCostCapturedAt": "<string>",
"totalCollected": 123,
"costRecoveryPercent": 123,
"currentProfit": 123,
"breakevenMonths": 123,
"hasReachedBreakeven": true,
"recoveryStatus": "profitable",
"replacementHistory": [
{
"oldSerialNumber": "<string>",
"newSerialNumber": "<string>",
"reason": "<string>",
"replacedBy": {
"userId": "<string>",
"email": "<string>",
"displayName": "<string>",
"role": "<string>",
"memberId": "<string>"
},
"replacedAt": "<string>",
"damageAssessment": "<string>",
"insuranceClaim": true,
"notes": "<string>"
}
],
"buyoutDetails": {
"buyoutPrice": 1,
"calculationMethod": "auto_calculated",
"reason": "customer_request",
"processedBy": {
"userId": "<string>",
"email": "<string>",
"displayName": "<string>",
"role": "<string>",
"memberId": "<string>"
},
"buyoutDate": "<string>",
"calculationBreakdown": {
"remainingMonths": 60,
"remainingMonthsPayment": 1,
"listPricePercentage": 123,
"listPriceAmount": 1,
"flatFee": 1
},
"notes": "<string>"
},
"earlyReturnDetails": {
"fee": 1,
"feeWaived": true,
"calculationMethod": "auto_calculated",
"returnCondition": "excellent",
"reason": "<string>",
"processedBy": {
"userId": "<string>",
"email": "<string>",
"displayName": "<string>",
"role": "<string>",
"memberId": "<string>"
},
"returnedAt": "<string>",
"calculationBreakdown": {
"method": "remaining_months",
"remainingMonths": 60,
"gracePeriodApplied": true,
"daysFromStart": 1825
},
"damageAssessment": "<string>",
"notes": "<string>"
},
"cancellationDetails": {
"reason": "customer_request",
"processedBy": {
"userId": "<string>",
"email": "<string>",
"displayName": "<string>",
"role": "<string>",
"memberId": "<string>"
},
"cancelledAt": "<string>",
"notes": "<string>"
},
"upgradeFromRentalId": "<string>",
"customFields": {},
"notes": "<string>"
}{
"error": {
"code": "<string>",
"message": "<string>"
}
}Subscriptions
Get Subscription
Retrieves a specific subscription by ID.
GET
/
v1
/
subscriptions
/
{subscriptionId}
Get a subscription
curl --request GET \
--url https://api-eu.flexportal.io/v1/subscriptions/{subscriptionId} \
--header 'Authorization: Bearer <token>' \
--header 'Tenant-ID: <tenant-id>'import requests
url = "https://api-eu.flexportal.io/v1/subscriptions/{subscriptionId}"
headers = {
"Tenant-ID": "<tenant-id>",
"Authorization": "Bearer <token>"
}
response = requests.get(url, headers=headers)
print(response.text)const options = {
method: 'GET',
headers: {'Tenant-ID': '<tenant-id>', Authorization: 'Bearer <token>'}
};
fetch('https://api-eu.flexportal.io/v1/subscriptions/{subscriptionId}', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api-eu.flexportal.io/v1/subscriptions/{subscriptionId}",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Tenant-ID: <tenant-id>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api-eu.flexportal.io/v1/subscriptions/{subscriptionId}"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("Tenant-ID", "<tenant-id>")
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://api-eu.flexportal.io/v1/subscriptions/{subscriptionId}")
.header("Tenant-ID", "<tenant-id>")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api-eu.flexportal.io/v1/subscriptions/{subscriptionId}")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["Tenant-ID"] = '<tenant-id>'
request["Authorization"] = 'Bearer <token>'
response = http.request(request)
puts response.read_body{
"rentalId": "<string>",
"tenantId": "<string>",
"assetSerialNumber": "<string>",
"customerId": "<string>",
"sku": "<string>",
"productName": "<string>",
"monthlyAmount": 123,
"currency": "<string>",
"status": "active",
"originalContractLength": 123,
"contractLength": 123,
"startDate": "<string>",
"orderId": "<string>",
"customerEmail": "<string>",
"customerName": "<string>",
"createdAt": "<string>",
"updatedAt": "<string>",
"createdBy": "<string>",
"productId": "<string>",
"variantId": "<string>",
"productImageUrl": "<string>",
"billingGroupId": "<string>",
"endDate": "<string>",
"nextBillingDate": "<string>",
"lastModifiedDate": "<string>",
"extensionHistory": [
{
"extensionMonths": 60,
"oldContractLength": 60,
"newContractLength": 60,
"oldMonthlyAmount": 1,
"newMonthlyAmount": 1,
"extendedBy": {
"userId": "<string>",
"email": "<string>",
"displayName": "<string>",
"role": "<string>",
"memberId": "<string>"
},
"oldEndDate": "<string>",
"newEndDate": "<string>",
"extendedAt": "<string>",
"reason": "<string>",
"notes": "<string>"
}
],
"actualMonthsRented": 123,
"monthsSaved": 123,
"listPrice": 123,
"listPriceSource": "variant",
"listPriceCapturedAt": "<string>",
"acquisitionCost": 123,
"acquisitionCostSource": "variant",
"acquisitionCostCapturedAt": "<string>",
"totalCollected": 123,
"costRecoveryPercent": 123,
"currentProfit": 123,
"breakevenMonths": 123,
"hasReachedBreakeven": true,
"recoveryStatus": "profitable",
"replacementHistory": [
{
"oldSerialNumber": "<string>",
"newSerialNumber": "<string>",
"reason": "<string>",
"replacedBy": {
"userId": "<string>",
"email": "<string>",
"displayName": "<string>",
"role": "<string>",
"memberId": "<string>"
},
"replacedAt": "<string>",
"damageAssessment": "<string>",
"insuranceClaim": true,
"notes": "<string>"
}
],
"buyoutDetails": {
"buyoutPrice": 1,
"calculationMethod": "auto_calculated",
"reason": "customer_request",
"processedBy": {
"userId": "<string>",
"email": "<string>",
"displayName": "<string>",
"role": "<string>",
"memberId": "<string>"
},
"buyoutDate": "<string>",
"calculationBreakdown": {
"remainingMonths": 60,
"remainingMonthsPayment": 1,
"listPricePercentage": 123,
"listPriceAmount": 1,
"flatFee": 1
},
"notes": "<string>"
},
"earlyReturnDetails": {
"fee": 1,
"feeWaived": true,
"calculationMethod": "auto_calculated",
"returnCondition": "excellent",
"reason": "<string>",
"processedBy": {
"userId": "<string>",
"email": "<string>",
"displayName": "<string>",
"role": "<string>",
"memberId": "<string>"
},
"returnedAt": "<string>",
"calculationBreakdown": {
"method": "remaining_months",
"remainingMonths": 60,
"gracePeriodApplied": true,
"daysFromStart": 1825
},
"damageAssessment": "<string>",
"notes": "<string>"
},
"cancellationDetails": {
"reason": "customer_request",
"processedBy": {
"userId": "<string>",
"email": "<string>",
"displayName": "<string>",
"role": "<string>",
"memberId": "<string>"
},
"cancelledAt": "<string>",
"notes": "<string>"
},
"upgradeFromRentalId": "<string>",
"customFields": {},
"notes": "<string>"
}{
"error": {
"code": "<string>",
"message": "<string>"
}
}Overview
Retrieve complete details for a single subscription, including full cost recovery metrics, lifecycle history, and payment information. This endpoint returns the most comprehensive view of a subscription.Common Use Cases
- Subscription Detail Page: Display complete subscription information
- Cost Recovery Analysis: Review profitability and breakeven analysis
- Lifecycle Tracking: View extension, upgrade, and replacement history
- Support Inquiries: Get full context during customer support
Cost Recovery Details
The response includes detailed profitability metrics:{
"costRecovery": {
"acquisitionCost": 1800.00,
"listPrice": 2499.00,
"totalCollected": 1548.00,
"costRecoveryPercent": 86.0,
"breakevenMonth": 14,
"monthsActive": 12,
"monthsRemaining": 12,
"projectedTotalCollection": 3096.00,
"projectedMargin": 1296.00,
"projectedMarginPercent": 72.0
}
}
| Metric | Description |
|---|---|
acquisitionCost | What you paid for the asset |
listPrice | MSRP/retail price |
totalCollected | Total payments collected so far |
costRecoveryPercent | (Collected / Cost) × 100 |
breakevenMonth | Month when cost will be fully recovered |
monthsActive | How long subscription has been active |
monthsRemaining | Months until contract ends |
projectedTotalCollection | Expected total at contract end |
projectedMargin | Expected profit at contract end |
Lifecycle History
Subscriptions track all lifecycle events:{
"extensionHistory": [
{
"extendedAt": "2025-06-15T10:30:00Z",
"extensionMonths": 6,
"previousEndDate": "2025-06-30",
"newEndDate": "2025-12-31",
"reason": "Customer requested extension"
}
],
"replacementHistory": [
{
"replacedAt": "2025-03-10T14:00:00Z",
"previousSerialNumber": "SN123456",
"newSerialNumber": "SN789012",
"reason": "Device malfunction"
}
]
}
Subscription Details
Key fields in the response:| Field | Description |
|---|---|
subscriptionId | Unique identifier |
status | Current status |
customerId | Customer ID |
orderId | Original order ID |
sku | Product variant SKU |
productName | Product display name |
serialNumber | Current asset serial number |
startDate | Contract start date |
endDate | Contract end date |
contractLength | Duration in months |
monthlyAmount | Monthly billing amount |
nextBillingDate | Next scheduled payment date |
billingGroupId | B2B billing group (if applicable) |
Example: Display Subscription Summary
async function getSubscriptionSummary(subscriptionId) {
const sub = await getSubscription(subscriptionId);
const isProfitable = sub.costRecovery.costRecoveryPercent >= 100;
const monthsToBreakeven = sub.costRecovery.breakevenMonth - sub.costRecovery.monthsActive;
return {
product: sub.productName,
customer: sub.customerId,
status: sub.status,
monthlyPayment: `€${sub.monthlyAmount}`,
contractPeriod: `${sub.startDate} to ${sub.endDate}`,
costRecovery: `${sub.costRecovery.costRecoveryPercent.toFixed(1)}%`,
isProfitable,
monthsToBreakeven: isProfitable ? 0 : monthsToBreakeven,
extensions: sub.extensionHistory?.length || 0,
replacements: sub.replacementHistory?.length || 0
};
}
Related Endpoints
- List Subscriptions - Browse all subscriptions
- Extend Subscription - Extend the contract
- Upgrade Subscription - Upgrade to new device
- Buyout Subscription - Convert to purchase
- Calculate Buyout - Get buyout price
Authorizations
API key obtained from FlexPortal dashboard
Headers
Your tenant identifier
Path Parameters
The subscription ID
Response
Subscription details
Available options:
active, cancelled, ended_completed, ended_buyout, ended_upgrade, ended_early_return Show child attributes
Show child attributes
Available options:
variant, manual, order_override, estimated, unknown Available options:
variant, manual, order_override, list_price, unknown Available options:
profitable, recovering, at_risk, no_data Show child attributes
Show child attributes
Show child attributes
Show child attributes
Show child attributes
Show child attributes
Show child attributes
Show child attributes
Show child attributes
Show child attributes
Was this page helpful?