curl --request POST \
--url https://api.scrip.dev/v1/events/{id}/reverse \
--header 'Content-Type: application/json' \
--header 'X-API-Key: <api-key>' \
--data '
{
"idempotency_key": "refund-order-456-1",
"fraction": "0.5",
"reason": "partial refund",
"shortfall_policy": "report"
}
'import requests
url = "https://api.scrip.dev/v1/events/{id}/reverse"
payload = {
"idempotency_key": "refund-order-456-1",
"fraction": "0.5",
"reason": "partial refund",
"shortfall_policy": "report"
}
headers = {
"X-API-Key": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'X-API-Key': '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({
idempotency_key: 'refund-order-456-1',
fraction: '0.5',
reason: 'partial refund',
shortfall_policy: 'report'
})
};
fetch('https://api.scrip.dev/v1/events/{id}/reverse', 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/events/{id}/reverse",
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([
'idempotency_key' => 'refund-order-456-1',
'fraction' => '0.5',
'reason' => 'partial refund',
'shortfall_policy' => 'report'
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"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"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.scrip.dev/v1/events/{id}/reverse"
payload := strings.NewReader("{\n \"idempotency_key\": \"refund-order-456-1\",\n \"fraction\": \"0.5\",\n \"reason\": \"partial refund\",\n \"shortfall_policy\": \"report\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("X-API-Key", "<api-key>")
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.scrip.dev/v1/events/{id}/reverse")
.header("X-API-Key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"idempotency_key\": \"refund-order-456-1\",\n \"fraction\": \"0.5\",\n \"reason\": \"partial refund\",\n \"shortfall_policy\": \"report\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.scrip.dev/v1/events/{id}/reverse")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["X-API-Key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"idempotency_key\": \"refund-order-456-1\",\n \"fraction\": \"0.5\",\n \"reason\": \"partial refund\",\n \"shortfall_policy\": \"report\"\n}"
response = http.request(request)
puts response.read_body{
"created_at": "2026-07-20T10:30:00Z",
"event_id": "550e8400-e29b-41d4-a716-446655440000",
"fraction": "0.5",
"id": "550e8400-e29b-41d4-a716-446655440000",
"idempotency_key": "refund-order-456-1",
"ineligible_entries": [
{
"journal_entry_id": "550e8400-e29b-41d4-a716-446655440000",
"reason": "SETTLEMENT_SHAPED"
}
],
"lines": [
{
"asset_id": "550e8400-e29b-41d4-a716-446655440000",
"ledger_entity_id": "550e8400-e29b-41d4-a716-446655440000",
"original_amount": "54.25",
"original_journal_entry_id": "550e8400-e29b-41d4-a716-446655440000",
"recovered_amount": "27.13",
"requested_amount": "27.13",
"reversal_journal_entry_id": "550e8400-e29b-41d4-a716-446655440000",
"shortfall_amount": "0"
}
],
"reason": "partial refund",
"shortfall_policy": "report",
"state_changes": [
{
"changed_at": "2024-01-15T10:30:00Z",
"entity_id": "550e8400-e29b-41d4-a716-446655440000",
"entity_type": "PARTICIPANT",
"key": "lifetime_spend",
"new_value": "575",
"old_value": "500",
"operation": "set",
"program_id": "550e8400-e29b-41d4-a716-446655440002",
"rule_id": "550e8400-e29b-41d4-a716-446655440001",
"state_type": "counter"
}
],
"status": "COMPLETED"
}{
"created_at": "2026-07-20T10:30:00Z",
"event_id": "550e8400-e29b-41d4-a716-446655440000",
"fraction": "0.5",
"id": "550e8400-e29b-41d4-a716-446655440000",
"idempotency_key": "refund-order-456-1",
"ineligible_entries": [
{
"journal_entry_id": "550e8400-e29b-41d4-a716-446655440000",
"reason": "SETTLEMENT_SHAPED"
}
],
"lines": [
{
"asset_id": "550e8400-e29b-41d4-a716-446655440000",
"ledger_entity_id": "550e8400-e29b-41d4-a716-446655440000",
"original_amount": "54.25",
"original_journal_entry_id": "550e8400-e29b-41d4-a716-446655440000",
"recovered_amount": "27.13",
"requested_amount": "27.13",
"reversal_journal_entry_id": "550e8400-e29b-41d4-a716-446655440000",
"shortfall_amount": "0"
}
],
"reason": "partial refund",
"shortfall_policy": "report",
"state_changes": [
{
"changed_at": "2024-01-15T10:30:00Z",
"entity_id": "550e8400-e29b-41d4-a716-446655440000",
"entity_type": "PARTICIPANT",
"key": "lifetime_spend",
"new_value": "575",
"old_value": "500",
"operation": "set",
"program_id": "550e8400-e29b-41d4-a716-446655440002",
"rule_id": "550e8400-e29b-41d4-a716-446655440001",
"state_type": "counter"
}
],
"status": "COMPLETED"
}{
"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": "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": "conflict",
"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 already exists or state conflict"
}{
"code": "unprocessable",
"details": {
"expected": "<string>",
"field": "<string>",
"fields": [
{
"expected": "<unknown>",
"field": "<string>",
"message": "This field is required",
"reason": "required",
"received": "<string>"
}
],
"reason": "invalid",
"received": "<string>"
},
"message": "Business rule violation"
}{
"code": "internal_error",
"message": "An internal error occurred"
}Reverse an event's awards
Reverse rewards credited by a completed event’s rules.
curl --request POST \
--url https://api.scrip.dev/v1/events/{id}/reverse \
--header 'Content-Type: application/json' \
--header 'X-API-Key: <api-key>' \
--data '
{
"idempotency_key": "refund-order-456-1",
"fraction": "0.5",
"reason": "partial refund",
"shortfall_policy": "report"
}
'import requests
url = "https://api.scrip.dev/v1/events/{id}/reverse"
payload = {
"idempotency_key": "refund-order-456-1",
"fraction": "0.5",
"reason": "partial refund",
"shortfall_policy": "report"
}
headers = {
"X-API-Key": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'X-API-Key': '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({
idempotency_key: 'refund-order-456-1',
fraction: '0.5',
reason: 'partial refund',
shortfall_policy: 'report'
})
};
fetch('https://api.scrip.dev/v1/events/{id}/reverse', 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/events/{id}/reverse",
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([
'idempotency_key' => 'refund-order-456-1',
'fraction' => '0.5',
'reason' => 'partial refund',
'shortfall_policy' => 'report'
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"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"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.scrip.dev/v1/events/{id}/reverse"
payload := strings.NewReader("{\n \"idempotency_key\": \"refund-order-456-1\",\n \"fraction\": \"0.5\",\n \"reason\": \"partial refund\",\n \"shortfall_policy\": \"report\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("X-API-Key", "<api-key>")
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.scrip.dev/v1/events/{id}/reverse")
.header("X-API-Key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"idempotency_key\": \"refund-order-456-1\",\n \"fraction\": \"0.5\",\n \"reason\": \"partial refund\",\n \"shortfall_policy\": \"report\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.scrip.dev/v1/events/{id}/reverse")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["X-API-Key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"idempotency_key\": \"refund-order-456-1\",\n \"fraction\": \"0.5\",\n \"reason\": \"partial refund\",\n \"shortfall_policy\": \"report\"\n}"
response = http.request(request)
puts response.read_body{
"created_at": "2026-07-20T10:30:00Z",
"event_id": "550e8400-e29b-41d4-a716-446655440000",
"fraction": "0.5",
"id": "550e8400-e29b-41d4-a716-446655440000",
"idempotency_key": "refund-order-456-1",
"ineligible_entries": [
{
"journal_entry_id": "550e8400-e29b-41d4-a716-446655440000",
"reason": "SETTLEMENT_SHAPED"
}
],
"lines": [
{
"asset_id": "550e8400-e29b-41d4-a716-446655440000",
"ledger_entity_id": "550e8400-e29b-41d4-a716-446655440000",
"original_amount": "54.25",
"original_journal_entry_id": "550e8400-e29b-41d4-a716-446655440000",
"recovered_amount": "27.13",
"requested_amount": "27.13",
"reversal_journal_entry_id": "550e8400-e29b-41d4-a716-446655440000",
"shortfall_amount": "0"
}
],
"reason": "partial refund",
"shortfall_policy": "report",
"state_changes": [
{
"changed_at": "2024-01-15T10:30:00Z",
"entity_id": "550e8400-e29b-41d4-a716-446655440000",
"entity_type": "PARTICIPANT",
"key": "lifetime_spend",
"new_value": "575",
"old_value": "500",
"operation": "set",
"program_id": "550e8400-e29b-41d4-a716-446655440002",
"rule_id": "550e8400-e29b-41d4-a716-446655440001",
"state_type": "counter"
}
],
"status": "COMPLETED"
}{
"created_at": "2026-07-20T10:30:00Z",
"event_id": "550e8400-e29b-41d4-a716-446655440000",
"fraction": "0.5",
"id": "550e8400-e29b-41d4-a716-446655440000",
"idempotency_key": "refund-order-456-1",
"ineligible_entries": [
{
"journal_entry_id": "550e8400-e29b-41d4-a716-446655440000",
"reason": "SETTLEMENT_SHAPED"
}
],
"lines": [
{
"asset_id": "550e8400-e29b-41d4-a716-446655440000",
"ledger_entity_id": "550e8400-e29b-41d4-a716-446655440000",
"original_amount": "54.25",
"original_journal_entry_id": "550e8400-e29b-41d4-a716-446655440000",
"recovered_amount": "27.13",
"requested_amount": "27.13",
"reversal_journal_entry_id": "550e8400-e29b-41d4-a716-446655440000",
"shortfall_amount": "0"
}
],
"reason": "partial refund",
"shortfall_policy": "report",
"state_changes": [
{
"changed_at": "2024-01-15T10:30:00Z",
"entity_id": "550e8400-e29b-41d4-a716-446655440000",
"entity_type": "PARTICIPANT",
"key": "lifetime_spend",
"new_value": "575",
"old_value": "500",
"operation": "set",
"program_id": "550e8400-e29b-41d4-a716-446655440002",
"rule_id": "550e8400-e29b-41d4-a716-446655440001",
"state_type": "counter"
}
],
"status": "COMPLETED"
}{
"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": "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": "conflict",
"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 already exists or state conflict"
}{
"code": "unprocessable",
"details": {
"expected": "<string>",
"field": "<string>",
"fields": [
{
"expected": "<unknown>",
"field": "<string>",
"message": "This field is required",
"reason": "required",
"received": "<string>"
}
],
"reason": "invalid",
"received": "<string>"
},
"message": "Business rule violation"
}{
"code": "internal_error",
"message": "An internal error occurred"
}COMPLETED event’s rules credited. Recovery targets the lots the original awards created, where that value is still held by the originally credited participant or group; anything already spent, expired, transferred, or currently held is reported as shortfall_amount, never forced. Scrip caps cumulative reversals at each original award, so repeated partial reversals cannot claw back more than was earned.
Omit fraction to reverse all remaining value, or pass a decimal string like "0.5" to reverse that share of every award line. A request that exceeds an award’s remaining reversible value returns 409 Conflict instead of clamping. The response reports each award line’s requested, recovered, and shortfall amounts, lists any of the event’s credit entries that are not reversible (with reasons), and includes the event’s state changes. State changes are never reverted; send a compensating event if your program logic requires it.
Authorizations
API key passed in the X-API-Key header.
Path Parameters
Event ID
Body
Reversal details
Required. The same key replays the original result; a different payload under the same key is rejected.
1 - 255"refund-order-456-1"
Fraction of each original award to reverse, as a decimal string greater than 0 and at most 1. Omit to reverse all remaining value.
"0.5"
Optional context recorded on the reversal and its ledger entries.
500"partial refund"
Shortfall handling policy. V1 supports report only; omitted defaults to report.
report "report"
Response
Duplicate request (idempotency key matched, returns existing record)
"2026-07-20T10:30:00Z"
"550e8400-e29b-41d4-a716-446655440000"
"0.5"
"550e8400-e29b-41d4-a716-446655440000"
"refund-order-456-1"
CREDIT entries of the event this reversal did not process, with reasons
Show child attributes
Show child attributes
Per original award line accounting
Show child attributes
Show child attributes
"partial refund"
report "report"
The original event's state changes (counters, tags, attributes, tiers). Reversals never revert state automatically; send a compensating event if your program logic requires it.
Show child attributes
Show child attributes
"COMPLETED"