Mark a Payment Operation as Failed
Record a ticket or terminal payment attempt as failed when it did not succeed. This updates the existing payment operation only; it does not charge the customer, settle the ticket, or create output jobs.
In this article
Use this guide when the Harbor Soho team needs to keep a failed terminal or adapter payment attempt visible in the TPV record without treating it as a customer payment.
The action can be triggered from the ticket payment screen or from the terminal operations panel. The backend records `failed_at` in UTC the first time the operation becomes failed and stores the optional error message sent by the app or terminal runtime.
Before you start
- The operator is signed in to Harbor Demo Group with Harbor Soho as the active location.
- The operator has `tpv:use` for Harbor Soho. The backend update also accepts `tpv:manage`, but these UI screens require `tpv:use`.
- A `tpv_payment_operation` already exists for the active `location_id`.
- For the ticket payment screen, open the route with `TPV_TICKET_ID`, `TPV_TERMINAL_ID` and `TPV_STAFF_ID` from the GB documentation runtime.
- For the terminal operations panel, the TPV has an active service session and an actionable operation visible for the selected terminal.
Instructions
- 1.
Open the payment operation
Open the ticket payment screen for the Harbor Soho ticket, or open the TPV floor screen and use More TPV actions to reach Payment operations for this terminal. Locate the operation that represents the failed attempt.
- 2.
Check that the failure action is available
Confirm that the operation is still actionable and in the current terminal scope. If `claimed_by_terminal_id` is present, it must match the selected terminal. Completed and cancelled operations do not show the failure buttons in the UI.
- 3.
Mark the operation failed
Press the failed-operation button. In the current captures this appears as `Marcar fallida` on the ticket payment screen and `Fallida` in the terminal operations panel. The app updates the existing operation with `status: "failed"`, terminal context when available, and the default manual failure message.
- 4.
Confirm the failed state
Check that the operation now shows failed status and, where displayed, the saved error message. The first transition to failed sets `failed_at`; later failed updates can change mutable fields but do not overwrite that timestamp.
Validations and limits
- The UI blocks these screens unless the operator has `tpv:use` for the active location.
- The effective `operationId` comes from `PUT /api/app/{orgId}/{locationId}/tpv-payment-operations/{operationId}`, not from the request body.
- The operation must exist and belong to the same `location_id` as the current route context.
- The backend normalises `status` and accepts only `pending`, `claimed`, `requires_action`, `completed`, `failed` or `cancelled`.
- If `terminal_id` is sent, it must resolve to a valid terminal, derived terminal, or valid location user acting as a terminal.
- If `request_payload` or `response_payload` is sent, it must be a JSON object.
- The backend does not require `error_message`; do not present the message as mandatory.
- The failed branch updates only `tpv_payment_operation`. It does not create `ticket_payment`, `ticket_payment_allocation` or `tpv_output_job` records.
Expected result
The existing payment operation is persisted as failed, with a backend-owned `failed_at` timestamp and any saved error message. The ticket remains unsettled by this action, no customer payment is recorded, and the TPV operation lists refresh to show the updated state.