Appearance
Subscriber - Billing
Base URL:
https://your-domain.com
The signed-in subscriber's own invoices, payments and wallet ledger. Paging, the 404 rule, money and date formats are described under Conventions.
Subscriber Invoices
List the subscriber's invoices, newest first. Deleted invoices are not listed.
| Property | Value |
|---|---|
| Endpoint | Subscriber Invoices |
| Method | GET |
| URL | /api/v1/subscriber/invoices |
| Authentication | Bearer Token (Subscriber) |
Request Headers:
| Header | Value | Required |
|---|---|---|
Accept | application/json | Yes |
Authorization | Bearer subscriber-token | Yes |
Query Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
page | integer | No | Page number (default 1) |
per_page | integer | No | Items per page, 1 to 50 (default 20) |
Request Body: None
Success Response (200 OK):
json
{
"status": "success",
"data": [
{
"id": 2041,
"number": "a3f9c1d27b8e4",
"status": "partial",
"package_name": "Home Fiber 40",
"period_start": "2026-10-02T10:12:00+06:00",
"period_end": "2026-11-01T23:59:00+06:00",
"due_date": null,
"total": 1050,
"paid": 550,
"due": 500,
"created_at": "2026-10-02T10:12:00+06:00"
}
],
"meta": {
"current_page": 1,
"last_page": 1,
"per_page": 20,
"total": 1
}
}Field notes:
numberis the invoice's activation reference.statusis one ofactive,disabled,paid,partial,due,reverted, orunknownwhen the invoice has no status.period_startandperiod_endare the service period the invoice covers;due_dateis the billing due date. Each isnullwhen not set.totalis the invoice amount less any migration credit;dueistotal - paid, never below 0.
Error Response (401 Unauthorized):
json
{
"message": "Unauthenticated."
}Code Examples:
bash
curl -X GET "https://your-domain.com/api/v1/subscriber/invoices?page=1&per_page=20" \
-H "Accept: application/json" \
-H "Authorization: Bearer your-auth-token"php
<?php
require 'vendor/autoload.php';
use GuzzleHttp\Client;
$client = new Client(['base_uri' => 'https://your-domain.com']);
$response = $client->request('GET', '/api/v1/subscriber/invoices', [
'headers' => [
'Accept' => 'application/json',
'Authorization' => 'Bearer your-auth-token',
],
'query' => [
'page' => 1,
'per_page' => 20,
],
]);
$data = json_decode($response->getBody(), true);
print_r($data);javascript
const BASE_URL = 'https://your-domain.com';
const TOKEN = 'your-auth-token';
const params = new URLSearchParams({
page: 1,
per_page: 20,
});
const response = await fetch(`${BASE_URL}/api/v1/subscriber/invoices?${params}`, {
method: 'GET',
headers: {
Accept: 'application/json',
Authorization: `Bearer ${TOKEN}`,
},
});
const data = await response.json();
console.log(data);python
import requests
BASE_URL = "https://your-domain.com"
TOKEN = "your-auth-token"
response = requests.get(
f"{BASE_URL}/api/v1/subscriber/invoices",
headers={
"Accept": "application/json",
"Authorization": f"Bearer {TOKEN}",
},
params={
"page": 1,
"per_page": 20,
},
)
data = response.json()
print(data)go
package main
import (
"fmt"
"io"
"net/http"
"net/url"
)
const baseURL = "https://your-domain.com"
const token = "your-auth-token"
func main() {
endpoint := baseURL + "/api/v1/subscriber/invoices"
q := url.Values{}
q.Set("page", "1")
q.Set("per_page", "20")
endpoint += "?" + q.Encode()
req, _ := http.NewRequest("GET", endpoint, nil)
req.Header.Set("Accept", "application/json")
req.Header.Set("Authorization", "Bearer "+token)
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
fmt.Println(resp.StatusCode, string(body))
}rust
use reqwest::Client;
const BASE_URL: &str = "https://your-domain.com";
const TOKEN: &str = "your-auth-token";
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = Client::new();
let response = client
.get(format!("{BASE_URL}/api/v1/subscriber/invoices"))
.header("Accept", "application/json")
.bearer_auth(TOKEN)
.query(&[
("page", "1"),
("per_page", "20"),
])
.send()
.await?;
let data: serde_json::Value = response.json().await?;
println!("{data:#}");
Ok(())
}Subscriber Invoice Details
Get one of the subscriber's invoices with its fee breakdown and linked payment.
| Property | Value |
|---|---|
| Endpoint | Subscriber Invoice Details |
| Method | GET |
| URL | /api/v1/subscriber/invoices/{id} |
| Authentication | Bearer Token (Subscriber) |
Request Headers:
| Header | Value | Required |
|---|---|---|
Accept | application/json | Yes |
Authorization | Bearer subscriber-token | Yes |
Path Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
id | integer | Yes | Invoice ID |
Request Body: None
Success Response (200 OK):
json
{
"status": "success",
"data": {
"id": 2041,
"number": "a3f9c1d27b8e4",
"status": "partial",
"package_name": "Home Fiber 40",
"period_start": "2026-10-02T10:12:00+06:00",
"period_end": "2026-11-01T23:59:00+06:00",
"due_date": null,
"total": 1050,
"paid": 550,
"due": 500,
"created_at": "2026-10-02T10:12:00+06:00",
"package_fee": 1000,
"extra_fee_total": 50,
"activation_extra_fee_total": 0,
"extra_services_total": 0,
"discount": 0,
"payment": {
"id": 881,
"transaction_id": "a3f9c1d27b8e4_5c21ab",
"amount": 550,
"method": 11,
"method_label": "Bkash",
"reverted": false,
"withdrawal": false,
"note": null,
"paid_at": "2026-10-02T10:12:00+06:00"
}
}
}Field notes:
- The list fields, plus the same breakdown as the portal's invoice page:
package_fee + extra_fee_total + activation_extra_fee_total + extra_services_total - discount = total. paymentis the invoice's payment (same shape as Subscriber Payment Details), ornullwhen there is none.
Error Response (404 Not Found):
json
{
"status": "error",
"message": "Not Found"
}Code Examples:
bash
curl -X GET "https://your-domain.com/api/v1/subscriber/invoices/1" \
-H "Accept: application/json" \
-H "Authorization: Bearer your-auth-token"php
<?php
require 'vendor/autoload.php';
use GuzzleHttp\Client;
$client = new Client(['base_uri' => 'https://your-domain.com']);
$invoiceId = 1;
$response = $client->request('GET', "/api/v1/subscriber/invoices/{$invoiceId}", [
'headers' => [
'Accept' => 'application/json',
'Authorization' => 'Bearer your-auth-token',
],
]);
$data = json_decode($response->getBody(), true);
print_r($data);javascript
const BASE_URL = 'https://your-domain.com';
const TOKEN = 'your-auth-token';
const invoiceId = 1;
const response = await fetch(`${BASE_URL}/api/v1/subscriber/invoices/${invoiceId}`, {
method: 'GET',
headers: {
Accept: 'application/json',
Authorization: `Bearer ${TOKEN}`,
},
});
const data = await response.json();
console.log(data);python
import requests
BASE_URL = "https://your-domain.com"
TOKEN = "your-auth-token"
invoice_id = 1
response = requests.get(
f"{BASE_URL}/api/v1/subscriber/invoices/{invoice_id}",
headers={
"Accept": "application/json",
"Authorization": f"Bearer {TOKEN}",
},
)
data = response.json()
print(data)go
package main
import (
"fmt"
"io"
"net/http"
"strconv"
)
const baseURL = "https://your-domain.com"
const token = "your-auth-token"
func main() {
invoiceId := 1
endpoint := baseURL + "/api/v1/subscriber/invoices/" + strconv.Itoa(invoiceId)
req, _ := http.NewRequest("GET", endpoint, nil)
req.Header.Set("Accept", "application/json")
req.Header.Set("Authorization", "Bearer "+token)
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
fmt.Println(resp.StatusCode, string(body))
}rust
use reqwest::Client;
const BASE_URL: &str = "https://your-domain.com";
const TOKEN: &str = "your-auth-token";
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = Client::new();
let invoice_id = 1;
let response = client
.get(format!("{BASE_URL}/api/v1/subscriber/invoices/{invoice_id}"))
.header("Accept", "application/json")
.bearer_auth(TOKEN)
.send()
.await?;
let data: serde_json::Value = response.json().await?;
println!("{data:#}");
Ok(())
}Subscriber Payments
List the subscriber's payments, newest first, with totals across all of them.
| Property | Value |
|---|---|
| Endpoint | Subscriber Payments |
| Method | GET |
| URL | /api/v1/subscriber/payments |
| Authentication | Bearer Token (Subscriber) |
Request Headers:
| Header | Value | Required |
|---|---|---|
Accept | application/json | Yes |
Authorization | Bearer subscriber-token | Yes |
Query Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
page | integer | No | Page number (default 1) |
per_page | integer | No | Items per page, 1 to 50 (default 20) |
Request Body: None
Success Response (200 OK):
json
{
"status": "success",
"data": [
{
"id": 881,
"transaction_id": "a3f9c1d27b8e4_5c21ab",
"amount": 550,
"method": 11,
"method_label": "Bkash",
"reverted": false,
"withdrawal": false,
"note": null,
"paid_at": "2026-10-02T10:12:00+06:00"
},
{
"id": 812,
"transaction_id": "7d04be19a6c32",
"amount": -100,
"method": 1,
"method_label": "Cash",
"reverted": false,
"withdrawal": true,
"note": "Refund of overpayment",
"paid_at": "2026-09-20T16:40:00+06:00"
}
],
"meta": {
"current_page": 1,
"last_page": 1,
"per_page": 20,
"total": 2
},
"summary": {
"net_paid": 450,
"received": 550,
"withdrawn": -100,
"reverted": 0
}
}Field notes:
methodis the stored payment method code andmethod_labelits name as the admin panel shows it (for example1Cash,2Cheque,4Subscriber Balance,11Bkash,12SSLCommerz). Unlisted codes show asOthers.revertedistruewhen the payment was reversed with its invoice. A reverted payment is still listed but is not counted innet_paid.withdrawalistruefor a negative amount (money paid back to the subscriber).summarycovers all the subscriber's payments, not only the current page:receivedis the sum of positive payments,withdrawnthe sum of withdrawals (negative),net_paid = received + withdrawn, andrevertedthe sum of reverted payments.
Error Response (401 Unauthorized):
json
{
"message": "Unauthenticated."
}Code Examples:
bash
curl -X GET "https://your-domain.com/api/v1/subscriber/payments?page=1&per_page=20" \
-H "Accept: application/json" \
-H "Authorization: Bearer your-auth-token"php
<?php
require 'vendor/autoload.php';
use GuzzleHttp\Client;
$client = new Client(['base_uri' => 'https://your-domain.com']);
$response = $client->request('GET', '/api/v1/subscriber/payments', [
'headers' => [
'Accept' => 'application/json',
'Authorization' => 'Bearer your-auth-token',
],
'query' => [
'page' => 1,
'per_page' => 20,
],
]);
$data = json_decode($response->getBody(), true);
print_r($data);javascript
const BASE_URL = 'https://your-domain.com';
const TOKEN = 'your-auth-token';
const params = new URLSearchParams({
page: 1,
per_page: 20,
});
const response = await fetch(`${BASE_URL}/api/v1/subscriber/payments?${params}`, {
method: 'GET',
headers: {
Accept: 'application/json',
Authorization: `Bearer ${TOKEN}`,
},
});
const data = await response.json();
console.log(data);python
import requests
BASE_URL = "https://your-domain.com"
TOKEN = "your-auth-token"
response = requests.get(
f"{BASE_URL}/api/v1/subscriber/payments",
headers={
"Accept": "application/json",
"Authorization": f"Bearer {TOKEN}",
},
params={
"page": 1,
"per_page": 20,
},
)
data = response.json()
print(data)go
package main
import (
"fmt"
"io"
"net/http"
"net/url"
)
const baseURL = "https://your-domain.com"
const token = "your-auth-token"
func main() {
endpoint := baseURL + "/api/v1/subscriber/payments"
q := url.Values{}
q.Set("page", "1")
q.Set("per_page", "20")
endpoint += "?" + q.Encode()
req, _ := http.NewRequest("GET", endpoint, nil)
req.Header.Set("Accept", "application/json")
req.Header.Set("Authorization", "Bearer "+token)
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
fmt.Println(resp.StatusCode, string(body))
}rust
use reqwest::Client;
const BASE_URL: &str = "https://your-domain.com";
const TOKEN: &str = "your-auth-token";
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = Client::new();
let response = client
.get(format!("{BASE_URL}/api/v1/subscriber/payments"))
.header("Accept", "application/json")
.bearer_auth(TOKEN)
.query(&[
("page", "1"),
("per_page", "20"),
])
.send()
.await?;
let data: serde_json::Value = response.json().await?;
println!("{data:#}");
Ok(())
}Subscriber Payment Details
Get one of the subscriber's payments.
| Property | Value |
|---|---|
| Endpoint | Subscriber Payment Details |
| Method | GET |
| URL | /api/v1/subscriber/payments/{id} |
| Authentication | Bearer Token (Subscriber) |
Request Headers:
| Header | Value | Required |
|---|---|---|
Accept | application/json | Yes |
Authorization | Bearer subscriber-token | Yes |
Path Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
id | integer | Yes | Payment ID |
Request Body: None
Success Response (200 OK):
json
{
"status": "success",
"data": {
"id": 881,
"transaction_id": "a3f9c1d27b8e4_5c21ab",
"amount": 550,
"method": 11,
"method_label": "Bkash",
"reverted": false,
"withdrawal": false,
"note": null,
"paid_at": "2026-10-02T10:12:00+06:00"
}
}Error Response (404 Not Found):
json
{
"status": "error",
"message": "Not Found"
}Code Examples:
bash
curl -X GET "https://your-domain.com/api/v1/subscriber/payments/1" \
-H "Accept: application/json" \
-H "Authorization: Bearer your-auth-token"php
<?php
require 'vendor/autoload.php';
use GuzzleHttp\Client;
$client = new Client(['base_uri' => 'https://your-domain.com']);
$paymentId = 1;
$response = $client->request('GET', "/api/v1/subscriber/payments/{$paymentId}", [
'headers' => [
'Accept' => 'application/json',
'Authorization' => 'Bearer your-auth-token',
],
]);
$data = json_decode($response->getBody(), true);
print_r($data);javascript
const BASE_URL = 'https://your-domain.com';
const TOKEN = 'your-auth-token';
const paymentId = 1;
const response = await fetch(`${BASE_URL}/api/v1/subscriber/payments/${paymentId}`, {
method: 'GET',
headers: {
Accept: 'application/json',
Authorization: `Bearer ${TOKEN}`,
},
});
const data = await response.json();
console.log(data);python
import requests
BASE_URL = "https://your-domain.com"
TOKEN = "your-auth-token"
payment_id = 1
response = requests.get(
f"{BASE_URL}/api/v1/subscriber/payments/{payment_id}",
headers={
"Accept": "application/json",
"Authorization": f"Bearer {TOKEN}",
},
)
data = response.json()
print(data)go
package main
import (
"fmt"
"io"
"net/http"
"strconv"
)
const baseURL = "https://your-domain.com"
const token = "your-auth-token"
func main() {
paymentId := 1
endpoint := baseURL + "/api/v1/subscriber/payments/" + strconv.Itoa(paymentId)
req, _ := http.NewRequest("GET", endpoint, nil)
req.Header.Set("Accept", "application/json")
req.Header.Set("Authorization", "Bearer "+token)
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
fmt.Println(resp.StatusCode, string(body))
}rust
use reqwest::Client;
const BASE_URL: &str = "https://your-domain.com";
const TOKEN: &str = "your-auth-token";
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = Client::new();
let payment_id = 1;
let response = client
.get(format!("{BASE_URL}/api/v1/subscriber/payments/{payment_id}"))
.header("Accept", "application/json")
.bearer_auth(TOKEN)
.send()
.await?;
let data: serde_json::Value = response.json().await?;
println!("{data:#}");
Ok(())
}Subscriber Ledger
List the subscriber's wallet ledger lines, newest first.
| Property | Value |
|---|---|
| Endpoint | Subscriber Ledger |
| Method | GET |
| URL | /api/v1/subscriber/ledger |
| Authentication | Bearer Token (Subscriber) |
Request Headers:
| Header | Value | Required |
|---|---|---|
Accept | application/json | Yes |
Authorization | Bearer subscriber-token | Yes |
Query Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
page | integer | No | Page number (default 1) |
per_page | integer | No | Items per page, 1 to 50 (default 20) |
Request Body: None
Success Response (200 OK):
json
{
"status": "success",
"data": [
{
"id": 99120,
"transaction_id": "a3f9c1d27b8e4",
"type": "deducted",
"amount": -1000,
"balance": 350,
"note": "Package activation: Home Fiber 40",
"invoice_id": 2041,
"payment_id": null,
"created_at": "2026-10-02T10:12:00+06:00"
},
{
"id": 99104,
"transaction_id": "e81c07fa52d93",
"type": "topup",
"amount": 1350,
"balance": 1350,
"note": null,
"invoice_id": null,
"payment_id": 879,
"created_at": "2026-10-02T10:05:00+06:00"
}
],
"meta": {
"current_page": 1,
"last_page": 4,
"per_page": 20,
"total": 63
}
}Field notes:
typeis one of:topup: money added to the wallet.deducted: money taken from the wallet (negativeamount).invoice_paid: an invoice paid by cash, cheque or similar; linked to both the invoice and the payment, and the balance does not change.withdraw: a withdrawal.invoice: an invoice line.profit: a profit line.other: any other ledger type.
balanceis the wallet balance after this line.invoice_idandpayment_idlink the line to an invoice or payment, or arenull.
Error Response (401 Unauthorized):
json
{
"message": "Unauthenticated."
}Code Examples:
bash
curl -X GET "https://your-domain.com/api/v1/subscriber/ledger?page=1&per_page=20" \
-H "Accept: application/json" \
-H "Authorization: Bearer your-auth-token"php
<?php
require 'vendor/autoload.php';
use GuzzleHttp\Client;
$client = new Client(['base_uri' => 'https://your-domain.com']);
$response = $client->request('GET', '/api/v1/subscriber/ledger', [
'headers' => [
'Accept' => 'application/json',
'Authorization' => 'Bearer your-auth-token',
],
'query' => [
'page' => 1,
'per_page' => 20,
],
]);
$data = json_decode($response->getBody(), true);
print_r($data);javascript
const BASE_URL = 'https://your-domain.com';
const TOKEN = 'your-auth-token';
const params = new URLSearchParams({
page: 1,
per_page: 20,
});
const response = await fetch(`${BASE_URL}/api/v1/subscriber/ledger?${params}`, {
method: 'GET',
headers: {
Accept: 'application/json',
Authorization: `Bearer ${TOKEN}`,
},
});
const data = await response.json();
console.log(data);python
import requests
BASE_URL = "https://your-domain.com"
TOKEN = "your-auth-token"
response = requests.get(
f"{BASE_URL}/api/v1/subscriber/ledger",
headers={
"Accept": "application/json",
"Authorization": f"Bearer {TOKEN}",
},
params={
"page": 1,
"per_page": 20,
},
)
data = response.json()
print(data)go
package main
import (
"fmt"
"io"
"net/http"
"net/url"
)
const baseURL = "https://your-domain.com"
const token = "your-auth-token"
func main() {
endpoint := baseURL + "/api/v1/subscriber/ledger"
q := url.Values{}
q.Set("page", "1")
q.Set("per_page", "20")
endpoint += "?" + q.Encode()
req, _ := http.NewRequest("GET", endpoint, nil)
req.Header.Set("Accept", "application/json")
req.Header.Set("Authorization", "Bearer "+token)
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
fmt.Println(resp.StatusCode, string(body))
}rust
use reqwest::Client;
const BASE_URL: &str = "https://your-domain.com";
const TOKEN: &str = "your-auth-token";
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = Client::new();
let response = client
.get(format!("{BASE_URL}/api/v1/subscriber/ledger"))
.header("Accept", "application/json")
.bearer_auth(TOKEN)
.query(&[
("page", "1"),
("per_page", "20"),
])
.send()
.await?;
let data: serde_json::Value = response.json().await?;
println!("{data:#}");
Ok(())
}