A hold is a compliance check that has not finished. The movement is neither done nor failed — it is paused, and it will resume or stop depending on the result.
It is worth handling as its own case, because the two things a flow usually does with an unfinished movement are both wrong here: retrying creates a second one, and treating it as failed tells your customer something that is not true yet.
On a deposit
A held deposit sits in KYT_PENDING. From there it either returns to where it was before the hold, or moves to KYT_REJECTED.
KYT_REJECTED is deliberately not FAILED. A failure is technical; this is a decision, and keeping them apart is what makes the record readable afterwards. Only a compliance decision moves it, and there are two: the money goes back to the sender as REFUNDED, or the rejection is withdrawn and the deposit is released to COMPLETED with the money where it is.
A held deposit blocks every payout from that account while it lasts. A payout that will not start, on an account that looks funded, is worth checking for this before assuming your integration is at fault.
On a payout
A held payout sits in KYT_PENDING, or in IN_REVIEW when the hold is a manual check rather than an automatic one.
Both reach you only on payout.status_changed — there is no dedicated event for either, so an integration subscribed to the named events sees the payout leave PROCESSING and learns nothing more.
Who releases it
Not you, and not through the API. A hold is cleared by the check completing, or by a compliance decision at Kira. There is no endpoint that releases one, and retrying the movement does not affect it.
What you can do:
- Show it as pending, not as failed and not as done.
- Answer any request for information raised alongside it. Where a hold is waiting on information, that is what ends the wait.
- Do not retry. Retrying with the same idempotency key returns the same held movement; retrying with a fresh one creates a second one that will be held for the same reason.
Testing a hold
Both endings are reachable in sandbox and resolve on their own, without anyone at Kira. Forcing outcomes has the values — one pair of cents holds and then approves, another holds and then rejects.
Test them together. The interesting failure is not in either ending; it is in the code that runs while the movement is paused and assumes it will resume.