Create a billing group
curl --request POST \
--url https://api-eu.flexportal.io/v1/billing-groups \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--header 'Tenant-ID: <tenant-id>' \
--data '
{
"customerId": "cust_abc123",
"groupName": "Acme Corp - IT Department",
"billingDay": 15,
"rentalIds": [
"rental_001",
"rental_002",
"rental_003"
],
"notes": "Net 30 payment terms agreed"
}
'import requests
url = "https://api-eu.flexportal.io/v1/billing-groups"
payload = {
"customerId": "cust_abc123",
"groupName": "Acme Corp - IT Department",
"billingDay": 15,
"rentalIds": ["rental_001", "rental_002", "rental_003"],
"notes": "Net 30 payment terms agreed"
}
headers = {
"Tenant-ID": "<tenant-id>",
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {
'Tenant-ID': '<tenant-id>',
Authorization: 'Bearer <token>',
'Content-Type': 'application/json'
},
body: JSON.stringify({
customerId: 'cust_abc123',
groupName: 'Acme Corp - IT Department',
billingDay: 15,
rentalIds: ['rental_001', 'rental_002', 'rental_003'],
notes: 'Net 30 payment terms agreed'
})
};
fetch('https://api-eu.flexportal.io/v1/billing-groups', 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/billing-groups",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'customerId' => 'cust_abc123',
'groupName' => 'Acme Corp - IT Department',
'billingDay' => 15,
'rentalIds' => [
'rental_001',
'rental_002',
'rental_003'
],
'notes' => 'Net 30 payment terms agreed'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json",
"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"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api-eu.flexportal.io/v1/billing-groups"
payload := strings.NewReader("{\n \"customerId\": \"cust_abc123\",\n \"groupName\": \"Acme Corp - IT Department\",\n \"billingDay\": 15,\n \"rentalIds\": [\n \"rental_001\",\n \"rental_002\",\n \"rental_003\"\n ],\n \"notes\": \"Net 30 payment terms agreed\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Tenant-ID", "<tenant-id>")
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api-eu.flexportal.io/v1/billing-groups")
.header("Tenant-ID", "<tenant-id>")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"customerId\": \"cust_abc123\",\n \"groupName\": \"Acme Corp - IT Department\",\n \"billingDay\": 15,\n \"rentalIds\": [\n \"rental_001\",\n \"rental_002\",\n \"rental_003\"\n ],\n \"notes\": \"Net 30 payment terms agreed\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api-eu.flexportal.io/v1/billing-groups")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Tenant-ID"] = '<tenant-id>'
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"customerId\": \"cust_abc123\",\n \"groupName\": \"Acme Corp - IT Department\",\n \"billingDay\": 15,\n \"rentalIds\": [\n \"rental_001\",\n \"rental_002\",\n \"rental_003\"\n ],\n \"notes\": \"Net 30 payment terms agreed\"\n}"
response = http.request(request)
puts response.read_body{
"success": true,
"message": "<string>",
"billingGroup": {
"billingGroupId": "<string>",
"tenantId": "<string>",
"customerId": "<string>",
"groupName": "<string>",
"billingDay": 14,
"totalMonthlyAmount": 1,
"currency": "<string>",
"status": "active",
"createdBy": "<string>",
"createdAt": "<string>",
"updatedAt": "<string>",
"rentalIds": [],
"activeRentalCount": 0,
"notes": "<string>"
}
}{
"error": {
"code": "<string>",
"message": "<string>"
}
}Billing Groups
Create Billing Group
Creates a new billing group for consolidated B2B billing. Groups multiple subscriptions under one customer for a single monthly invoice. All subscriptions in the group are billed on the same day each month.
POST
/
v1
/
billing-groups
Create a billing group
curl --request POST \
--url https://api-eu.flexportal.io/v1/billing-groups \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--header 'Tenant-ID: <tenant-id>' \
--data '
{
"customerId": "cust_abc123",
"groupName": "Acme Corp - IT Department",
"billingDay": 15,
"rentalIds": [
"rental_001",
"rental_002",
"rental_003"
],
"notes": "Net 30 payment terms agreed"
}
'import requests
url = "https://api-eu.flexportal.io/v1/billing-groups"
payload = {
"customerId": "cust_abc123",
"groupName": "Acme Corp - IT Department",
"billingDay": 15,
"rentalIds": ["rental_001", "rental_002", "rental_003"],
"notes": "Net 30 payment terms agreed"
}
headers = {
"Tenant-ID": "<tenant-id>",
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {
'Tenant-ID': '<tenant-id>',
Authorization: 'Bearer <token>',
'Content-Type': 'application/json'
},
body: JSON.stringify({
customerId: 'cust_abc123',
groupName: 'Acme Corp - IT Department',
billingDay: 15,
rentalIds: ['rental_001', 'rental_002', 'rental_003'],
notes: 'Net 30 payment terms agreed'
})
};
fetch('https://api-eu.flexportal.io/v1/billing-groups', 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/billing-groups",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'customerId' => 'cust_abc123',
'groupName' => 'Acme Corp - IT Department',
'billingDay' => 15,
'rentalIds' => [
'rental_001',
'rental_002',
'rental_003'
],
'notes' => 'Net 30 payment terms agreed'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json",
"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"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api-eu.flexportal.io/v1/billing-groups"
payload := strings.NewReader("{\n \"customerId\": \"cust_abc123\",\n \"groupName\": \"Acme Corp - IT Department\",\n \"billingDay\": 15,\n \"rentalIds\": [\n \"rental_001\",\n \"rental_002\",\n \"rental_003\"\n ],\n \"notes\": \"Net 30 payment terms agreed\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Tenant-ID", "<tenant-id>")
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api-eu.flexportal.io/v1/billing-groups")
.header("Tenant-ID", "<tenant-id>")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"customerId\": \"cust_abc123\",\n \"groupName\": \"Acme Corp - IT Department\",\n \"billingDay\": 15,\n \"rentalIds\": [\n \"rental_001\",\n \"rental_002\",\n \"rental_003\"\n ],\n \"notes\": \"Net 30 payment terms agreed\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api-eu.flexportal.io/v1/billing-groups")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Tenant-ID"] = '<tenant-id>'
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"customerId\": \"cust_abc123\",\n \"groupName\": \"Acme Corp - IT Department\",\n \"billingDay\": 15,\n \"rentalIds\": [\n \"rental_001\",\n \"rental_002\",\n \"rental_003\"\n ],\n \"notes\": \"Net 30 payment terms agreed\"\n}"
response = http.request(request)
puts response.read_body{
"success": true,
"message": "<string>",
"billingGroup": {
"billingGroupId": "<string>",
"tenantId": "<string>",
"customerId": "<string>",
"groupName": "<string>",
"billingDay": 14,
"totalMonthlyAmount": 1,
"currency": "<string>",
"status": "active",
"createdBy": "<string>",
"createdAt": "<string>",
"updatedAt": "<string>",
"rentalIds": [],
"activeRentalCount": 0,
"notes": "<string>"
}
}{
"error": {
"code": "<string>",
"message": "<string>"
}
}Overview
Create a billing group to consolidate multiple subscriptions into a single monthly invoice. This is ideal for B2B customers with multiple devices who prefer simplified billing.Billing groups are typically used for business customers. Individual customers usually have separate billing per subscription.
Request Fields
| Field | Required | Description |
|---|---|---|
customerId | Yes | Business customer ID |
groupName | Yes | Display name for the group |
rentalIds | Yes | Array of subscription IDs to include |
billingDay | Yes | Day of month for billing (1-28) |
Example Request
{
"customerId": "cust_abc123",
"groupName": "Acme Corp - IT Department",
"rentalIds": [
"sub_001",
"sub_002",
"sub_003"
],
"billingDay": 15
}
What Happens
When you create a billing group:- Group created with specified subscriptions
- Subscriptions linked to the billing group
- Future payments consolidated to billing day
- Monthly total calculated automatically
Billing Day Selection
Choose a billing day that works for the customer:| Day | Typical Use |
|---|---|
| 1 | Start of month billing |
| 15 | Mid-month billing |
| 25-28 | End of month (use 28 for all-month compatibility) |
Use 28 or lower for billing day to ensure it exists in all months. Days 29-31 may cause issues in shorter months.
Example: Create Group for New Business Customer
async function setupBusinessBilling(customerId, groupName, subscriptionIds) {
// Verify all subscriptions belong to this customer
for (const subId of subscriptionIds) {
const sub = await getSubscription(subId);
if (sub.customerId !== customerId) {
throw new Error(`Subscription ${subId} belongs to different customer`);
}
}
// Create billing group
return await createBillingGroup({
customerId,
groupName,
rentalIds: subscriptionIds,
billingDay: 1 // Bill on 1st of each month
});
}
Error Handling
| Error Code | Cause | Solution |
|---|---|---|
CUSTOMER_NOT_FOUND | Invalid customer ID | Verify customer exists |
SUBSCRIPTION_NOT_FOUND | Invalid subscription ID | Verify subscription IDs |
SUBSCRIPTION_DIFFERENT_CUSTOMER | Subscription belongs to different customer | Only group same-customer subscriptions |
INVALID_BILLING_DAY | Day must be 1-28 | Use valid billing day |
Related Endpoints
- List Billing Groups - View all groups
- Update Billing Group - Add/remove subscriptions
- Get Customer - Verify business customer
Authorizations
API key obtained from FlexPortal dashboard
Headers
Your tenant identifier
Body
application/json
Was this page helpful?