Skip to content

Send reservationId on settle and map final 409 hold refusals - #8

Merged
splinterone merged 2 commits into
mainfrom
cursor/settle-reservation-refusals-a6e2
Oct 8, 2026
Merged

splinterone merged 2 commits into
mainfrom
cursor/settle-reservation-refusals-a6e2

Conversation

@splinterone

@splinterone splinterone commented Oct 8, 2026 •

Copy link
Copy Markdown
Owner

What this is

Draft only. Not merged, not published. Still 0.2.0, because that version is not on npm yet (0.1.1 is the published one).

When you have a reservation id, settle sends reservationId. Optional on wardpass_settle_payment and on WardPassClient.settlePayment. Leave it out and the field is absent.

How a settle response is read

The gateway puts the machine code in code and a reason in errorReason. Example: 409 { success: false, errorReason: "settlement_in_progress", code: "settlement_unknown", idempotencyKey, retryAfterMs }. This client maps code, then errorReason, then error, so an older gateway that only sent error still works.

Response What you get
409 reservation_awaiting_approval Pending, not an error. The payment is waiting on human approval. Retry later with the same idempotency key. Same approval id comes back while it is waiting. reservationId is passed through.
409 settlement_unknown outcome_unknown. Retry only with the same idempotency key. retryAfterMs, when present, is how long to wait.
409 with no code, or a code this client does not recognize (including settlement_in_progress on an older body) outcome_unknown. Same retry rule.
409 final hold refusals isError, plain English, one request. Do not invent a new idempotency key.
404 reservation_not_found Final refusal when you named a reservation. A 404 here is not a dropped connection.

Final 409 codes: reservation_already_settled, reservation_released, reservation_expired, reservation_not_open, reservation_passport_mismatch, reservation_bound_to_other_payment, amount_exceeds_hold, amount_below_hold, reservation_agent_mismatch. A later gateway may answer another agent's id with the same 404 reservation_not_found. Both stay final.

HTTP 200 failure bodies stay denials. A screening miss or a per-payment cap refusal is not an unknown outcome.

Tests

node --test: 35 passed, 0 failed. That covers each final code, 404 reservation_not_found with a reservationId, reservation_awaiting_approval as pending, the code / errorReason / error order, and retryAfterMs on settlement_unknown. No network. CI is Node 18 and 20.

What a 0.1.1 user would notice

Nothing, until they upgrade. screenBeforeSettle and assertScreenAllow are unchanged. 0.1.1 has no settle helper.

Open in Web Open in Cursor 

cursoragent and others added 2 commits October 8, 2026 06:42
0.2.0 is still unpublished, so this stays on that version. A reservation id from reserve, an approval, or the caller is sent on settle. Final hold refusals are errors you do not retry with a new idempotency key. settlement_unknown and an unrecognized 409 stay retryable with the same key.

Co-authored-by: splinterone <splinterone@users.noreply.github.com>
The machine code is code, then errorReason, then error. 404 reservation_not_found is a final refusal. reservation_awaiting_approval stays pending and tells you to retry the same idempotency key. settlement_unknown keeps retryAfterMs.

Co-authored-by: splinterone <splinterone@users.noreply.github.com>
@splinterone
splinterone marked this pull request as ready for review October 8, 2026 07:45
@splinterone
splinterone merged commit e785051 into main Oct 8, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants