Analytics
Get Dunning Overview
Retrieve a summary of dunning performance including retry counts, recovery rates, and per-action breakdowns.
GET
/
v1
/
analytics
/
dunning
/
overview
Dunning retry overview
curl --request GET \
--url https://billing.example.com/v1/analytics/dunning/overview \
--header 'Authorization: Bearer <token>'import requests
url = "https://billing.example.com/v1/analytics/dunning/overview"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://billing.example.com/v1/analytics/dunning/overview', 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://billing.example.com/v1/analytics/dunning/overview",
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://billing.example.com/v1/analytics/dunning/overview"
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://billing.example.com/v1/analytics/dunning/overview")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://billing.example.com/v1/analytics/dunning/overview")
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{
"total_retries": 123,
"total_successes": 123,
"success_rate": 0.5
}{
"error": {
"code": "BAD_REQUEST",
"message": "<string>"
}
}Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
start_date | string | No | ISO 8601 date. Filters results from this date onward. Defaults to 30 days ago. |
end_date | string | No | ISO 8601 date. Filters results up to this date. Defaults to today. |
Example Request
curl -X GET "https://api.recurso.dev/v1/analytics/dunning/overview?start_date=2026-05-01&end_date=2026-06-01" \
-H "Authorization: Bearer rsk_live_7f3a9b2c1d4e8f0a"
Response
{
"total_retries": 1247,
"successful_retries": 843,
"recovery_rate": 0.676,
"period": {
"start": "2026-05-01T00:00:00Z",
"end": "2026-06-01T00:00:00Z"
},
"by_action": [
{
"action_id": "retry_payment",
"attempts": 680,
"successes": 512,
"success_rate": 0.753
},
{
"action_id": "send_reminder_email",
"attempts": 342,
"successes": 198,
"success_rate": 0.579
},
{
"action_id": "card_update_request",
"attempts": 155,
"successes": 89,
"success_rate": 0.574
},
{
"action_id": "escalate_to_phone",
"attempts": 70,
"successes": 44,
"success_rate": 0.629
}
]
}
Notes
- The
recovery_rateis the ratio ofsuccessful_retriestototal_retriesacross all dunning actions. - Each entry in
by_actionrepresents a distinct dunning action configured in your dunning campaigns. - Success is defined as the customer resolving the failed payment within the dunning window.
Use this endpoint alongside the dunning weights endpoint to understand which actions the system is learning to prioritize.
⌘I
Dunning retry overview
curl --request GET \
--url https://billing.example.com/v1/analytics/dunning/overview \
--header 'Authorization: Bearer <token>'import requests
url = "https://billing.example.com/v1/analytics/dunning/overview"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://billing.example.com/v1/analytics/dunning/overview', 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://billing.example.com/v1/analytics/dunning/overview",
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://billing.example.com/v1/analytics/dunning/overview"
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://billing.example.com/v1/analytics/dunning/overview")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://billing.example.com/v1/analytics/dunning/overview")
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{
"total_retries": 123,
"total_successes": 123,
"success_rate": 0.5
}{
"error": {
"code": "BAD_REQUEST",
"message": "<string>"
}
}