Start learning free

LESSON 108 OF 173 · BACKEND: PAYMENTS AND OTHER SERVICES

Declined Cards

Practice

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 as Payment only tells TypeScript what to expect: it never checks the answer. So payment.id is undefined, the UPDATE fails with it and the customer gets an error page.

Check the status first. Before you use another service's answer, look at response.status. The same idea with the supplier and a product it doesn't sell:

const response = await fetch(SUPPLIER + "/stock/99");
if (response.status === 404) {
  return res.status(404).json({ error: "Unknown product" });
}
const data = await response.json() as SupplierStock;

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.

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 pay route, right after const payment = await response.json() as Payment;, check whether the provider answered 402. If it did, answer "Payment declined" with 402, and pass the provider's error on under reason.


Assignment
Follow the Coding Tutorial to handle a declined card in POST /orders/:orderId/pay.


Hint
The provider's reason is payment.error: the type Payment now has error?: string;, where the ? says only a declined payment has it. A return ends the function, so with the if above the UPDATE, a declined order is never marked paid.


STEP 1 OF 2
    Ctrl + Enter to check