curl --request GET \
--url https://api.scrip.dev/v1/participants/{id}/rollforward \
--header 'X-API-Key: <api-key>'import requests
url = "https://api.scrip.dev/v1/participants/{id}/rollforward"
headers = {"X-API-Key": "<api-key>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {'X-API-Key': '<api-key>'}};
fetch('https://api.scrip.dev/v1/participants/{id}/rollforward', 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.scrip.dev/v1/participants/{id}/rollforward",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"X-API-Key: <api-key>"
],
]);
$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.scrip.dev/v1/participants/{id}/rollforward"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("X-API-Key", "<api-key>")
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.scrip.dev/v1/participants/{id}/rollforward")
.header("X-API-Key", "<api-key>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.scrip.dev/v1/participants/{id}/rollforward")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["X-API-Key"] = '<api-key>'
response = http.request(request)
puts response.read_body{
"data": [
{
"asset_id": "550e8400-e29b-41d4-a716-446655440000",
"asset_name": "Loyalty Points",
"asset_symbol": "POINTS",
"bucket_movements_net": "0.00",
"closing_balance": "1295.00",
"debited": "40.00",
"expired": "0.00",
"forfeited": "15.00",
"holds_voided": "0.00",
"issuance_returns": "30.00",
"issued": "300.00",
"opening_balance": "1250.00",
"redeemed": "150.00",
"redemption_receipts": "0.00",
"redemption_reversals": "20.00",
"reversal_clawbacks": "100.00",
"scale": 2,
"transfers_net": "-20.00"
}
],
"from": "2026-01-01T00:00:00Z",
"pagination": {
"has_more": true,
"next_cursor": "YWJjMTIz"
},
"participant_id": "550e8400-e29b-41d4-a716-446655440002",
"to": "2026-01-31T23:59:59.999999Z"
}{
"code": "bad_request",
"details": {
"expected": "<string>",
"field": "<string>",
"fields": [
{
"expected": "<unknown>",
"field": "<string>",
"message": "This field is required",
"reason": "required",
"received": "<string>"
}
],
"reason": "invalid",
"received": "<string>"
},
"message": "Invalid request parameters"
}{
"code": "unauthorized",
"details": {
"expected": "<string>",
"field": "<string>",
"fields": [
{
"expected": "<unknown>",
"field": "<string>",
"message": "This field is required",
"reason": "required",
"received": "<string>"
}
],
"reason": "invalid",
"received": "<string>"
},
"message": "Missing or invalid credentials"
}{
"code": "forbidden",
"details": {
"expected": "<string>",
"field": "<string>",
"fields": [
{
"expected": "<unknown>",
"field": "<string>",
"message": "This field is required",
"reason": "required",
"received": "<string>"
}
],
"reason": "invalid",
"received": "<string>"
},
"message": "Insufficient permissions for this action"
}{
"code": "not_found",
"details": {
"expected": "<string>",
"field": "<string>",
"fields": [
{
"expected": "<unknown>",
"field": "<string>",
"message": "This field is required",
"reason": "required",
"received": "<string>"
}
],
"reason": "invalid",
"received": "<string>"
},
"message": "Resource not found"
}{
"code": "internal_error",
"message": "An internal error occurred"
}Get participant rollforward
Returns one participant’s period rollforward per asset: opening balance, closing balance, and the movement decomposed by journal action type (issued, redeemed, expired, transfers, and so on). Lines are netted per journal entry and sum exactly to closing minus opening, with no residual plug. These are the figures a card program prints in the rewards box of a statement. Balances cover all buckets (AVAILABLE, HELD, DEFERRED). The window selects entries by posting time (the journal entry’s created_at), inclusive on both bounds, the same as the participant statement. The echoed from and to preserve the request’s fractional seconds, so replaying them returns identical figures.
curl --request GET \
--url https://api.scrip.dev/v1/participants/{id}/rollforward \
--header 'X-API-Key: <api-key>'import requests
url = "https://api.scrip.dev/v1/participants/{id}/rollforward"
headers = {"X-API-Key": "<api-key>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {'X-API-Key': '<api-key>'}};
fetch('https://api.scrip.dev/v1/participants/{id}/rollforward', 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.scrip.dev/v1/participants/{id}/rollforward",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"X-API-Key: <api-key>"
],
]);
$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.scrip.dev/v1/participants/{id}/rollforward"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("X-API-Key", "<api-key>")
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.scrip.dev/v1/participants/{id}/rollforward")
.header("X-API-Key", "<api-key>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.scrip.dev/v1/participants/{id}/rollforward")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["X-API-Key"] = '<api-key>'
response = http.request(request)
puts response.read_body{
"data": [
{
"asset_id": "550e8400-e29b-41d4-a716-446655440000",
"asset_name": "Loyalty Points",
"asset_symbol": "POINTS",
"bucket_movements_net": "0.00",
"closing_balance": "1295.00",
"debited": "40.00",
"expired": "0.00",
"forfeited": "15.00",
"holds_voided": "0.00",
"issuance_returns": "30.00",
"issued": "300.00",
"opening_balance": "1250.00",
"redeemed": "150.00",
"redemption_receipts": "0.00",
"redemption_reversals": "20.00",
"reversal_clawbacks": "100.00",
"scale": 2,
"transfers_net": "-20.00"
}
],
"from": "2026-01-01T00:00:00Z",
"pagination": {
"has_more": true,
"next_cursor": "YWJjMTIz"
},
"participant_id": "550e8400-e29b-41d4-a716-446655440002",
"to": "2026-01-31T23:59:59.999999Z"
}{
"code": "bad_request",
"details": {
"expected": "<string>",
"field": "<string>",
"fields": [
{
"expected": "<unknown>",
"field": "<string>",
"message": "This field is required",
"reason": "required",
"received": "<string>"
}
],
"reason": "invalid",
"received": "<string>"
},
"message": "Invalid request parameters"
}{
"code": "unauthorized",
"details": {
"expected": "<string>",
"field": "<string>",
"fields": [
{
"expected": "<unknown>",
"field": "<string>",
"message": "This field is required",
"reason": "required",
"received": "<string>"
}
],
"reason": "invalid",
"received": "<string>"
},
"message": "Missing or invalid credentials"
}{
"code": "forbidden",
"details": {
"expected": "<string>",
"field": "<string>",
"fields": [
{
"expected": "<unknown>",
"field": "<string>",
"message": "This field is required",
"reason": "required",
"received": "<string>"
}
],
"reason": "invalid",
"received": "<string>"
},
"message": "Insufficient permissions for this action"
}{
"code": "not_found",
"details": {
"expected": "<string>",
"field": "<string>",
"fields": [
{
"expected": "<unknown>",
"field": "<string>",
"message": "This field is required",
"reason": "required",
"received": "<string>"
}
],
"reason": "invalid",
"received": "<string>"
},
"message": "Resource not found"
}{
"code": "internal_error",
"message": "An internal error occurred"
}from and to. The response has one row for each asset the participant has used by to. Each row gives opening_balance, closing_balance, and how the balance changed, split into named amounts such as issued, redeemed, redemption_reversals, and expired. Use it to print the rewards summary on a cardholder’s statement for one billing cycle without classifying statement rows yourself.
from and to are required. Both bounds are inclusive and select entries by the posting’s created_at, the same way the participant statement does. The response repeats from and to exactly as you sent them, including fractional seconds. Pass asset_id to return one asset.
For every row, the amounts add up to closing_balance - opening_balance. Every change is counted in one of them, and if the ledger contains activity they cannot cover, the request fails instead of returning a wrong figure. Balances include AVAILABLE, HELD, and DEFERRED, so bucket_movements_net is always 0, while transfers_net can be positive or negative. A settlement for less than the pending amount shows the difference in issuance_returns; it does not count as issued and then returned.
Authorizations
API key passed in the X-API-Key header.
Path Parameters
Participant ID
Query Parameters
Period start (inclusive, RFC 3339)
Period end (inclusive, RFC 3339)
Filter to a single asset
Response
Participant rollforward
Period rollforward of one participant's balances, one row per asset. Every line is attributed to journal action types; lines sum exactly to closing − opening per row (no plug line).
Rollforward rows, one per asset the participant has ledger activity in at or before to
Show child attributes
Show child attributes
Period start (inclusive, RFC 3339), echoed from the request with any fractional seconds preserved, so replaying the echoed bounds returns the same figures
"2026-01-01T00:00:00Z"
Pagination metadata for list responses
Show child attributes
Show child attributes
Participant the rollforward covers
"550e8400-e29b-41d4-a716-446655440002"
Period end (inclusive, RFC 3339), echoed from the request with any fractional seconds preserved, so replaying the echoed bounds returns the same figures
"2026-01-31T23:59:59.999999Z"