Start learning free

LESSON 107 OF 173 · BACKEND: PAYMENTS AND OTHER SERVICES

Take a Payment

Practice

A shop never handles card numbers itself. A payment provider does: the shop asks it, through its API, to charge an amount, and the provider answers with the payment it made. Ours lives at the address in payments, already written for you.

Sending JSON to another API in Go takes a few lines: json.Marshal a map into bytes, http.Post them, then decode the answer. Here a shop asks a gift-card service for a card worth 25:

body, _ := json.Marshal(map[string]any{"value": 25, "customer_id": 4})
response, _ := http.Post(gifts+"/cards", "application/json", bytes.NewReader(body))
defer response.Body.Close()
var card map[string]any
json.NewDecoder(response.Body).Decode(&card)
fmt.Println(card["id"])

Two rules. The amount comes from your own database, never from the customer's request: nobody gets to choose their own price. And the shop saves the provider's payment id in the order: it links the order to the provider's record of the money, so you can look the payment up, or refund it, later. Paying is a POST, because it changes things, and it answers 201.

The provider answers like {"id": "pay_1", "status": "succeeded", "amount": 80, "order_id": 8}. Your shop must answer:

GET /orders/8        →  200  {"customer_id": 5, "id": 8, "ordered": "2026-06-02", "payment_id": null, "status": "pending", "total": 80}
POST /orders/8/pay   →  201  {"amount": 80, "order_id": 8, "payment_id": "pay_1"}
GET /orders/8        →  200  {"customer_id": 5, "id": 8, "ordered": "2026-06-02", "payment_id": "pay_1", "status": "paid", "total": 80}
POST /orders/10/pay  →  201  {"amount": 21, "order_id": 10, "payment_id": "pay_2"}
POST /orders/99/pay  →  404  {"error": "Order not found"}

Your task: add POST /orders/{id}/pay. Find the order (404 if there is none), ask the provider at payments+"/payments" to charge its Total, save status = 'paid' and the payment id in the order, and answer 201.


Assignment
Follow the Coding Tutorial to build the route that pays an order through the payment provider.


Hint
Use findOrder as the route for one order does: it also adds up the Total. Decode the provider's answer into a map[string]any. db.Exec saves the UPDATE right away: no commit needed. Go refuses to compile a variable that is never used, so the app only runs again once the answer's body is closed.


STEP 1 OF 12
    Ctrl + Enter to check