Not every payment goes through: the card has no money left, it is blocked, or the bank says no. Then the payment provider answers 402 Payment Required with an error instead of a payment. Our provider declines every amount over 1000 and answers {"error": "card_declined"}. There is no "id" in it, and a Go map gives nil for a missing key, so the shop today saves the order as paid with no payment id and answers 201 for money that never moved.
Check the status code first. Before you use another service's answer, look at response.StatusCode. A 402 is a normal answer for http.Post, not an error. The same idea with the supplier and a product it doesn't sell:
response, _ := http.Get(supplier + "/stock/99")
defer response.Body.Close()
if response.StatusCode == 404 {
writeJSON(w, 404, map[string]string{"error": "Unknown product"})
return
}
A declined card is not a bug in your shop, so the answer is not 500. It is not 502 either: the provider worked and gave a clear answer. Answer 402 yourself, pass the provider's reason on, and return before the UPDATE, so the order stays pending and the customer can try another card. writeJSON alone doesn't end the handler: without the return, the order would still be marked paid.
POST /orders/9/pay → 402 {"error": "Payment declined", "reason": "card_declined"}
GET /orders/9 → 200 {…, "payment_id": null, "status": "pending", "total": 1250}
POST /orders/8/pay → 201 {"amount": 80, "order_id": 8, "payment_id": "pay_1"}
Your task: in the handler for POST /orders/{id}/pay, right after decoding the provider's answer into payment, check whether the provider answered 402. If it did, answer "Payment declined" with 402, pass the provider's "error" on under "reason", and stop the handler.
Assignment
Follow the Coding Tutorial to handle a declined card in POST /orders/{id}/pay.
Hint
The provider's reason is payment["error"]; the answer needs a map[string]any. A return ends the handler, so with the if above the UPDATE, a declined order is never marked paid.
Free plan: 30 tutor messages. PRO is unlimited.
