Last reviewed 2026-09-05Skill version 0.1.0Provisional
Prove that the money of this refund went back to the payer. The refund reached the status COMPLETED. A 201 Created answer with the status PENDING is an object that exists and not money that went back.
Refund the captured payment to the payer and let the money move back.
What is the subject and the action?
Member
Value
Subject type
paypal.refund
Subject identity
refund_id = $action.result.id
Canonical effect
money.refund
Provider operation
POST /v2/payments/captures/{capture_id}/refund
Idempotency
idempotency_key through PayPal-Request-Id, retry is safe
How does the evidence correlate with this operation?
Strategy
Assurance
Keys
Required
resource_id
strong
refund_id from $action.result.id
no
resource_id
weak
capture_id from $input.capture_id
no
fingerprint
weak
capture_id from $input.capture_id; amount from $input.amount
no
Which evidence does the contract require?
Minimum evidence level E2. An independent channel is required. Minimum channels: 1.
Channel
Level
Independence
Verifier
Description
refund_readback
E2
provider readback
http
Read the refund from the Payments API. A condition path is $observed.refund_readback.status, and the amount sits at $observed.refund_readback.amount.value as a string.
capture_refunded_events
E3
provider event
webhook
The PAYMENT.CAPTURE.REFUNDED events of the intended captured payment, since the operation started. The webhook verifier returns {events, count, latest, earliest, types, duplicates_dropped}. A count above one shows a second refund of the same capture.
Which conditions must all hold for VERIFIED?
Condition
Meaning
Path
Operator
Expected
Evidence
refund_present
The Payments API holds the refund that the refund response named.
$observed.refund_readback.id
eq
$action.result.id
refund_readback
refund_amount_matches
The refunded amount equals the requested amount. PayPal states the value as a string, so this is a string comparison and it normalizes nothing.
$observed.refund_readback.amount.value
eq
$input.amount
refund_readback
refund_currency_matches
The currency of the refunded amount equals the requested currency.
$observed.refund_readback.amount.currency_code
eq
$input.currency_code
refund_readback
refund_created_in_window
PayPal made the refund after the operation started.
$observed.refund_readback.create_time
time_after
$operation.created_at
refund_readback
refund_on_intended_capture
At least one PAYMENT.CAPTURE.REFUNDED event names the captured payment that the intent named. The refund resource names no capture, so this event is the only tie between the two.
$observed.capture_refunded_events.count
gte
1
capture_refunded_events
refund_status_completed
The refund states the status COMPLETED. That is the only status that proves that the money went back.
$observed.refund_readback.status
eq
COMPLETED
refund_readback
Which conditions give CONTRADICTED?
Condition
Class
Reason
Path
Operator
Expected
refund_amount_mismatch
wrong amount
PayPal refunded a different amount than the intent stated.
$observed.refund_readback.amount.value
ne
$input.amount
refund_currency_mismatch
wrong amount
PayPal refunded a different currency than the intent stated.
$observed.refund_readback.amount.currency_code
ne
$input.currency_code
refund_predates_operation
pre existing state
The refund is older than the operation. It proves nothing.
$observed.refund_readback.create_time
time_before
$operation.created_at
duplicate_refund_present
duplicate side effect
PayPal refunded the captured payment more than once since the operation started. Do not retry.
$observed.capture_refunded_events.count
gt
1
Which observed states map to a verdict before completion?
Rule
Match
Verdict
Reason
refund_failed
$observed.refund_readback.status eq "FAILED"
FAILED
The settlement process of the bank did not issue the refund. Retry with the first request id.
refund_still_pending
$observed.refund_readback.status eq "PENDING"
PENDING
The refund is pending. The money did not move back. The runtime observes again.
How long does the runtime observe?
Timing member
Value
Initial delay
2000 ms
Poll interval
5000 ms
Backoff
exponential factor 2, max 300000 ms
Maximum attempts
900
Timeout
259200000 ms
Stale read window
20000 ms
On timeout
UNVERIFIABLE (evidence_unavailable_before_timeout), escalated to a person