The recovery ledger is the money history of a case: funds identified, freezes, payment plans, settlements, payments received, costs and remittances. RecovAI uses it to work out how much has been recovered and how much is still owed.
GET /cases/{id}/recoveriesRead only API key
curl https://api.recovai.ai/cases/5b0e2c1a-7d4f-4c2b-9a61-2f8e3d4c5b6a/recoveries \
-H "X-API-Key: $RECOVAI_API_KEY "
$ch = curl_init ( 'https://api.recovai.ai/cases/5b0e2c1a-7d4f-4c2b-9a61-2f8e3d4c5b6a/recoveries' );
CURLOPT_CUSTOMREQUEST => 'GET' ,
CURLOPT_RETURNTRANSFER => true ,
CURLOPT_HTTPHEADER => [ 'X-API-Key: ' . getenv ( 'RECOVAI_API_KEY' )],
$status = curl_getinfo ($ch, CURLINFO_RESPONSE_CODE );
$result = json_decode ($body, true );
throw new RuntimeException ($result[ 'error' ] . ': ' . ($result[ 'details' ] ?? '' ));
const res = await fetch ( 'https://api.recovai.ai/cases/5b0e2c1a-7d4f-4c2b-9a61-2f8e3d4c5b6a/recoveries' , {
headers: { 'X-API-Key' : process.env. RECOVAI_API_KEY },
const data = await res. json ();
if ( ! res.ok) throw new Error ( `${ data . error }: ${ data . details ?? ''}` );
"https://api.recovai.ai/cases/5b0e2c1a-7d4f-4c2b-9a61-2f8e3d4c5b6a/recoveries" ,
headers = { "X-API-Key" : os.environ[ "RECOVAI_API_KEY" ]},
raise RuntimeError ( f " { data[ 'error' ] } : { data.get( 'details' , '' ) } " )
"id" : "c3d4e5f6-a7b8-4c9d-8e0f-1a2b3c4d5e6f" ,
"case_id" : "5b0e2c1a-7d4f-4c2b-9a61-2f8e3d4c5b6a" ,
"type" : "partial_recovery" ,
"label" : "Partial recovery received" ,
"occurred_at" : "2026-10-10T00:00:00.000Z" ,
"details" : { "payment_method" : "ach" , "reference" : "PMT-0001" },
"idempotency_key" : "servicing-PMT-0001" ,
"evidence_document" : null ,
"created_at" : "2026-10-14T16:20:00.000Z"
"awaiting_remittance" : 12000 ,
"remaining_balance" : 36250 ,
actor is null for entries recorded with an API key.
Field
Meaning
identified, frozen, redirected
Totals of funds_identified, freeze and redirect entries.
committed
Total of payment_plan and settlement entries.
recovered
Total of partial_recovery and full_recovery entries.
costs, remitted
Totals of cost and remittance entries.
net_recovered
recovered minus costs.
awaiting_remittance
recovered not yet remitted.
remaining_balance
Case balance minus recovered, never below 0.
recovery_rate
recovered as a percentage of the case balance.
active_entries
Entries counted in the totals.
reversal_count
Entries that have been reversed. Reversed entries are left out of every total.
POST /cases/{id}/recoveriesChanges data API key
Field
Type
Required
Description
type
string
yes
One of the entry types .
amount
number
yes
USD, at least 0.01, two decimals at most.
currency
string
Only USD.
occurred_at
timestamp
When it happened. Defaults to now; cannot be in the future.
payment_method
string
ach, wire, check, card, processor_transfer or other.
reference
string
Your payment or transaction reference.
counterparty
string
Who paid or was paid.
note
string
Up to 4,000 characters.
evidence_document_id
UUID
A document on this case that proves the entry.
submission_id
UUID
The notice this recovery came from, if any.
idempotency_key
string
8–100 characters. Re-sending with the same key returns the original entry instead of recording it twice.
curl https://api.recovai.ai/cases/5b0e2c1a-7d4f-4c2b-9a61-2f8e3d4c5b6a/recoveries \
-H "X-API-Key: $RECOVAI_API_KEY " \
-H "Content-Type: application/json" \
"type": "partial_recovery",
"occurred_at": "2026-10-10T00:00:00Z",
"idempotency_key": "servicing-PMT-0001"
$ch = curl_init ( 'https://api.recovai.ai/cases/5b0e2c1a-7d4f-4c2b-9a61-2f8e3d4c5b6a/recoveries' );
CURLOPT_CUSTOMREQUEST => 'POST' ,
CURLOPT_RETURNTRANSFER => true ,
CURLOPT_POSTFIELDS => json_encode ([
'type' => 'partial_recovery' ,
'occurred_at' => '2026-10-10T00:00:00Z' ,
'payment_method' => 'ach' ,
'reference' => 'PMT-0001' ,
'idempotency_key' => 'servicing-PMT-0001' ,
CURLOPT_HTTPHEADER => [ 'X-API-Key: ' . getenv ( 'RECOVAI_API_KEY' ), 'Content-Type: application/json' ],
$status = curl_getinfo ($ch, CURLINFO_RESPONSE_CODE );
$result = json_decode ($body, true );
throw new RuntimeException ($result[ 'error' ] . ': ' . ($result[ 'details' ] ?? '' ));
const res = await fetch ( 'https://api.recovai.ai/cases/5b0e2c1a-7d4f-4c2b-9a61-2f8e3d4c5b6a/recoveries' , {
headers: { 'X-API-Key' : process.env. RECOVAI_API_KEY , 'Content-Type' : 'application/json' },
"type" : "partial_recovery" ,
"occurred_at" : "2026-10-10T00:00:00Z" ,
"idempotency_key" : "servicing-PMT-0001"
const data = await res. json ();
if ( ! res.ok) throw new Error ( `${ data . error }: ${ data . details ?? ''}` );
"https://api.recovai.ai/cases/5b0e2c1a-7d4f-4c2b-9a61-2f8e3d4c5b6a/recoveries" ,
headers = { "X-API-Key" : os.environ[ "RECOVAI_API_KEY" ]},
"type" : "partial_recovery" ,
"occurred_at" : "2026-10-10T00:00:00Z" ,
"idempotency_key" : "servicing-PMT-0001" ,
raise RuntimeError ( f " { data[ 'error' ] } : { data.get( 'details' , '' ) } " )
The new entry, plus the whole ledger (entries, summary, currency) as in Read the ledger . A replayed request returns 200 OK with "replayed": true.
Status
error
Meaning
400
invalid_submission
submission_id is not on this case.
400
invalid_evidence
evidence_document_id is not on this case.
409
case_closed
A closed case only accepts partial_recovery, full_recovery, cost and remittance.
409
idempotency_conflict
The key was already used for a different entry.
422
future_ledger_date
occurred_at is in the future.
422
remittance_exceeds_recovery
You cannot remit more than has been recovered.
Entries cannot be edited or deleted. To correct one, reverse it and record a new entry.
POST /recoveries/{id}/reverseChanges data API key
Cancels a ledger entry by adding a linked reversal entry. The original stays visible in the history but no longer counts in any total.
Field
Type
Required
Description
reason
string
yes
Why it is being reversed, 3–2,000 characters. Shown on the case timeline.
curl https://api.recovai.ai/recoveries/c3d4e5f6-a7b8-4c9d-8e0f-1a2b3c4d5e6f/reverse \
-H "X-API-Key: $RECOVAI_API_KEY " \
-H "Content-Type: application/json" \
"reason": "Payment returned by the bank (NSF)."
$ch = curl_init ( 'https://api.recovai.ai/recoveries/c3d4e5f6-a7b8-4c9d-8e0f-1a2b3c4d5e6f/reverse' );
CURLOPT_CUSTOMREQUEST => 'POST' ,
CURLOPT_RETURNTRANSFER => true ,
CURLOPT_POSTFIELDS => json_encode ([
'reason' => 'Payment returned by the bank (NSF).' ,
CURLOPT_HTTPHEADER => [ 'X-API-Key: ' . getenv ( 'RECOVAI_API_KEY' ), 'Content-Type: application/json' ],
$status = curl_getinfo ($ch, CURLINFO_RESPONSE_CODE );
$result = json_decode ($body, true );
throw new RuntimeException ($result[ 'error' ] . ': ' . ($result[ 'details' ] ?? '' ));
const res = await fetch ( 'https://api.recovai.ai/recoveries/c3d4e5f6-a7b8-4c9d-8e0f-1a2b3c4d5e6f/reverse' , {
headers: { 'X-API-Key' : process.env. RECOVAI_API_KEY , 'Content-Type' : 'application/json' },
"reason" : "Payment returned by the bank (NSF)."
const data = await res. json ();
if ( ! res.ok) throw new Error ( `${ data . error }: ${ data . details ?? ''}` );
"https://api.recovai.ai/recoveries/c3d4e5f6-a7b8-4c9d-8e0f-1a2b3c4d5e6f/reverse" ,
headers = { "X-API-Key" : os.environ[ "RECOVAI_API_KEY" ]},
"reason" : "Payment returned by the bank (NSF)." ,
raise RuntimeError ( f " { data[ 'error' ] } : { data.get( 'details' , '' ) } " )
The new reversal entry (with type: "reversal" and reverses_id pointing at the original), plus the whole updated ledger.
Status
error
Meaning
404
recovery_not_found
No such entry in your workspace.
409
already_reversed
The entry was already reversed.
409
reversal_not_reversible
A reversal cannot be reversed; record a new entry instead.
Value
Meaning
funds_identified
Funds found that could be recovered.
freeze
Funds frozen.
redirect
Payments redirected.
payment_plan
A payment plan agreed.
settlement
A settlement agreed.
partial_recovery
Money received, part of the balance.
full_recovery
Money received, the full balance.
cost
A cost incurred on the case.
remittance
Money passed on to the client.