curl --request GET \
--url https://api.paygentic.io/v0/profitability \
--header 'Authorization: Bearer <token>'import requests
url = "https://api.paygentic.io/v0/profitability"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://api.paygentic.io/v0/profitability', 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.paygentic.io/v0/profitability",
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>"
],
]);
$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.paygentic.io/v0/profitability"
req, _ := http.NewRequest("GET", url, nil)
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.paygentic.io/v0/profitability")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.paygentic.io/v0/profitability")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Bearer <token>'
response = http.request(request)
puts response.read_body{
"object": "profitability_summary",
"currency": "<string>",
"rows": [
{
"customerId": "<string>",
"customerName": "<string>",
"netRevenue": "<string>",
"totalCost": "<string>",
"profit": "<string>",
"marginPct": "<string>",
"costData": "recorded"
}
],
"customerCount": 1,
"emptyCustomerCount": 1,
"unloadedCustomerCount": 1,
"emptyCustomers": [
{
"customerId": "<string>",
"customerName": "<string>",
"netRevenue": "<string>",
"totalCost": "<string>",
"profit": "<string>",
"marginPct": "<string>",
"costData": "recorded"
}
],
"warnings": [
"<string>"
],
"revenueRange": {
"from": "2023-11-07T05:31:56Z",
"to": "2023-11-07T05:31:56Z"
},
"costRange": "<unknown>"
}{
"message": "The requested resource was not found",
"error": "not_found"
}{
"message": "The requested resource was not found",
"error": "not_found"
}{
"message": "The requested resource was not found",
"error": "not_found"
}{
"message": "The requested resource was not found",
"error": "not_found"
}Get profitability summary
Returns a per-customer profitability summary for a merchant over a date range. Each row aggregates revenue (invoices issued in the period, whatever their status since, less refunds, both excluding tax; the same figure /v0/revenue reports), cost (from metered cost discovery), profit, and margin. Customers are ranked by profit descending and capped at topN; the remainder is rolled into a single self-consistent ‘Other’ row whose revenue, cost, and profit reflect the same set of customers. Rows are joined against the merchant’s customer list, so meter subjects that match no customer are dropped. Soft-deleted customers with revenue or cost in the period are folded into a single ‘deleted’ row, which always comes last, after ‘Other’, and takes no top-N slot.
curl --request GET \
--url https://api.paygentic.io/v0/profitability \
--header 'Authorization: Bearer <token>'import requests
url = "https://api.paygentic.io/v0/profitability"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://api.paygentic.io/v0/profitability', 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.paygentic.io/v0/profitability",
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>"
],
]);
$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.paygentic.io/v0/profitability"
req, _ := http.NewRequest("GET", url, nil)
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.paygentic.io/v0/profitability")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.paygentic.io/v0/profitability")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Bearer <token>'
response = http.request(request)
puts response.read_body{
"object": "profitability_summary",
"currency": "<string>",
"rows": [
{
"customerId": "<string>",
"customerName": "<string>",
"netRevenue": "<string>",
"totalCost": "<string>",
"profit": "<string>",
"marginPct": "<string>",
"costData": "recorded"
}
],
"customerCount": 1,
"emptyCustomerCount": 1,
"unloadedCustomerCount": 1,
"emptyCustomers": [
{
"customerId": "<string>",
"customerName": "<string>",
"netRevenue": "<string>",
"totalCost": "<string>",
"profit": "<string>",
"marginPct": "<string>",
"costData": "recorded"
}
],
"warnings": [
"<string>"
],
"revenueRange": {
"from": "2023-11-07T05:31:56Z",
"to": "2023-11-07T05:31:56Z"
},
"costRange": "<unknown>"
}{
"message": "The requested resource was not found",
"error": "not_found"
}{
"message": "The requested resource was not found",
"error": "not_found"
}{
"message": "The requested resource was not found",
"error": "not_found"
}{
"message": "The requested resource was not found",
"error": "not_found"
}Authorizations
API key authentication
Query Parameters
Merchant whose customers to summarize Unique identifier for an organization
^org_[a-zA-Z0-9]+$Start of the time range (ISO 8601 format)
End of the time range (ISO 8601 format)
Number of top customers (by profit) to return individually. The rest are rolled into a single 'Other' row.
1 <= x <= 100ISO 4217 currency code to scope the summary. Defaults to the merchant's primary currency.
3When true, leave customers with neither revenue nor cost in the period out of rows. They are dropped before ranking, so they take no top-N slot and are not folded into the 'Other' row. emptyCustomerCount says how many there are either way.
When true, also return in emptyCustomers the customers counted in emptyCustomerCount that rows does not carry, so a caller can show the complete customer list.
Response
Profitability summary
Object type identifier
"profitability_summary"ISO 4217 currency code applied to revenue and cost values
Top-N customer rows by profit descending, optionally followed by a single 'Other' row when more than topN customers contributed. Soft-deleted customers appear only through the 'deleted' row, which comes last, never by name. With excludeEmpty=true, customers with neither revenue nor cost in the period are left out.
101Show child attributes
Show child attributes
The merchant's customers this summary scored, whether or not they made a row.
x >= 0Customers with neither revenue nor cost in the period, counted whether or not excludeEmpty left them out of rows. Null when a cost read failed: their cost was never established, so none is counted and excludeEmpty leaves nobody out.
x >= 0Customers rows does not carry because a cost read failed (see warnings) and they had no revenue in the period. Null when every cost read settled.
x >= 0The customers emptyCustomerCount counts that rows does not carry, either as a row or folded into the 'Other' row, sorted by name, each reading zero with a null margin. Present only when includeEmpty=true and the count is answered. They are never ranked, never part of the top-N and never folded into the 'Other' row.
Show child attributes
Show child attributes
Non-fatal warnings collected during cost discovery (e.g. an individual cost query failed). Empty array on a clean run.
100Where the caller's revenue actually lies in time. Scoped by the same filters as the request (merchant, and where given customer, subscription and currency), so it is not an account-wide statement. Present only when the selected range returned nothing. An object carries the bounds of the real revenue; null means no revenue under these filters at any time; an absent field means the extent was not resolved, because the result was not empty or because the lookup failed. An absent field must never be read as an absence. The bounds may span more than this endpoint's maximum queryable range, so clamp before re-querying.
Show child attributes
Show child attributes
Where the caller's cost data actually lies in time. Present only when the selected range returned no cost. An object carries the bounds of the real cost events; null means the caller has no cost event at any time; an absent field means the extent was not resolved, because the result was not empty, because the lookup failed, or because the metering service does not serve the bounds method. An absent field must never be read as an absence.
Was this page helpful?