Statuses And Lifecycles

Every status Kyshi can return, what it means, and what your system should do about it.

Kyshi objects move through defined states. This page is the complete reference for every status your integration can receive.

Treat any status not listed here as unrecognised: log it, do not give value, and check back with the verification endpoint for that object.

Transaction Status

Returned as status on transactions, charges, and collection records.

StatusMeaningWhat you should do
PENDINGThe payment has been created but no final result has arrived.Wait. Do not give value.
SUCCESSThe payment completed and funds are recognised.Give value, once.
FAILEDThe payment did not complete.Do not give value. Let the customer retry.
IN_REVIEWThe payment needs manual review before it can be finalised.Do not give value. The status will change without you retrying.
REVERSALA previously recognised payment was reversed.Reclaim value if you already released it.
COLLECTEDFunds were collected against the record.Treat as an accounting state, not a fulfilment signal. Verify before giving value.

PENDING is the only state that is guaranteed to change. IN_REVIEW resolves on Kyshi's side, so polling harder will not speed it up.

Virtual Account Collection Status

Returned as collectionStatus on virtual accounts and their collection transactions. This is the status most integrations forget to handle, because it covers the cases where the customer does not pay exactly what you asked for.

StatusMeaningWhat you should do
AWAITINGAccount created, no payment received yet. This is the default on creation.Show the account details to the customer.
PARTIALThe customer paid less than the expected amount.Do not fulfil. Ask for the balance, or refund.
COMPLETEDThe expected amount was paid.Fulfil.
OVERPAIDThe customer paid more than the expected amount.Fulfil, then handle the excess. The excess is tracked separately.
EXPIREDThe account or charge window lapsed before payment.Issue a new account if the customer still wants to pay.
REVIEWThe payment needs manual review.Do not fulfil. See below.

A collection is routed to REVIEW when any of the following is true:

  • the payment arrived after the charge had already expired
  • a payment arrived on an account that already recorded a successful transaction
  • the account had no expected amount set

PARTIAL and OVERPAID are normal, not exceptional. Bank transfers are initiated by the customer in their own banking app, so you cannot constrain the amount they send. Build for both before you go live.

Payment Link Status

StatusMeaning
PENDINGLink created, not yet paid.
OPENEDThe customer opened the link but has not completed payment.
SUCCESSPayment completed.
FAILEDPayment attempted and failed.
COLLECTEDFunds collected against the link.

OPENED is useful for abandonment metrics. It is not a payment signal.

Subscription Status

StatusMeaningWhat you should do
PENDINGCreated, first charge not yet settled.Wait before granting access.
ACTIVEBilling normally.Grant access.
PAST_DUEA renewal failed and retries are in progress.Decide your grace policy. Access is your call, not Kyshi's.
NON_RENEWINGWill not renew at period end, but is still active until then.Keep access until the period ends.
COMPLETEDReached its invoice or payment limit and ended normally.Revoke access at period end.
CANCELLEDEnded before its natural end.Revoke access.

NON_RENEWING and CANCELLED are different. A NON_RENEWING subscription is still owed service for the period the customer already paid for.

Subscription Payment Attempt Status

Each billing attempt against an invoice records its own status.

StatusMeaning
PENDINGAttempt in flight.
SUCCEEDEDThe attempt collected the money.
FAILEDThe attempt did not collect. See Failure Codes.
REQUIRES_ACTIONThe customer must do something, such as complete authentication.

REQUIRES_ACTION is not a failure. The attempt is waiting on the customer, so retrying it from your side will not help; the customer has to act.

Handling Unknown Statuses

New statuses can be added. Write your status handling so that anything unrecognised falls through to a safe default:

switch (transaction.status) {
  case 'SUCCESS':
    return fulfil(transaction);
  case 'FAILED':
  case 'REVERSAL':
    return doNotFulfil(transaction);
  default:
    // PENDING, IN_REVIEW, COLLECTED, or anything new.
    return waitAndVerifyLater(transaction);
}

Never treat an unknown status as success.


Did this page help you?