CodeGym /Các khóa học /ChatGPT Apps /ACP / Instant Checkout: tiêu chuẩn và triển khai của nó t...

ACP / Instant Checkout: tiêu chuẩn và triển khai của nó trong ChatGPT

ChatGPT Apps
Mức độ , Bài học
Có sẵn

1. Vì sao cần ACP và vì sao nó không chỉ là “một REST API nữa”

Nếu nhìn một cách hoài nghi, ACP trông như một tập hợp các HTTP endpoint và cấu trúc JSON thông thường: một /checkout_sessions nào đó, vài webhook, vài token. Rất dễ nghĩ: “OK, lại thêm một API tùy biến từ một nền tảng nữa”. Nhưng ý tưởng của ACP sâu hơn thế.

ACP được thiết kế như một giao thức mở để tương tác giữa ba bên: nền tảng AI (ví dụ, ChatGPT), commerce‑backend của bạn và nhà cung cấp dịch vụ thanh toán (PSP). Mục tiêu của nó — chuẩn hóa cách mô tả sản phẩm và giá, cách AI thông báo ý định mua hàng của người dùng, cách tạo một phiên checkout, cách thực thi thanh toán và cách tất cả các bên biết được trạng thái cuối cùng.

Ý chính: cùng một backend của merchant, khi triển khai ACP, về tiềm năng có thể hoạt động không chỉ với ChatGPT mà còn với các nền tảng LLM khác hỗ trợ tiêu chuẩn này. Tức là bạn không viết một “API dành riêng cho ChatGPT”, bạn đang triển khai một giao thức tích hợp commerce thế hệ tiếp theo.

Instant Checkout trong ChatGPT là bản triển khai lớn đầu tiên của tiêu chuẩn ACP. ChatGPT tuân thủ giao thức này, gọi các endpoint ACP của bạn và hiển thị UI đẹp cho người dùng, nhưng luật chơi được mô tả trong các đặc tả ACP, chứ không phải “ma thuật GPT” nào đó ẩn trong một hộp đen.

2. Ba trụ cột của ACP: Product Feed, Agentic Checkout, Delegated Payment

ACP có ba đặc tả chính mà chúng ta sẽ thường xuyên nhắc đến:

Đặc tả Phụ trách điều gì Áp dụng thế nào trong GiftGenius
Product Feed Spec Định dạng và các trường của product feed (SKU, giá, tồn kho, liên kết, cờ). Feed JSON/CSV về quà tặng được OpenAI lập chỉ mục.
Agentic Checkout Hợp đồng REST cho checkout_session: tạo, cập nhật, hoàn tất. ACP backend của chúng ta: các endpoint /checkout_sessions và webhooks.
Delegated Payment Cách dữ liệu thanh toán được truyền cho merchant dưới dạng token ủy quyền. Làm việc với Stripe Shared Payment Token khi hoàn tất thanh toán.

Chúng ta đã phân tích Product Feed trong các bài trước. Giờ chúng ta quan tâm đến hai khối cuối: Agentic CheckoutDelegated Payment.

Quan trọng là tách bạch ba tầng:

  1. Tiêu chuẩn (SPEC). Tài liệu chính thức mô tả cần có những trường và endpoint nào, trạng thái nào hợp lệ và bạn cam kết những bảo đảm gì.
  2. Mẫu kiến trúc (ARCH). Ví dụ, quyết định lưu SKU và đơn hàng ở các bảng riêng, dựng một service bọc quanh ACP hoặc dùng hàng đợi cho webhooks. Đây là thực hành tốt, nhưng không phải là một phần của tiêu chuẩn.
  3. Triển khai cụ thể (ví dụ GiftGenius). Đây là dự án học tập của chúng ta: cấu trúc bảng, tên kiểu trong TypeScript, cách ghi log đơn hàng, v.v. Tất cả chỉ là ví dụ, không phải tài liệu quy phạm.

Chúng tôi sẽ liên tục nhấn mạnh nơi SPEC kết thúc và kiến trúc của bạn bắt đầu — để tránh tình huống “tôi thấy trong bài có trường persona_tags và tưởng đó là một phần của đặc tả chính thức”.

3. Checkout session từ bên trong: cấu trúc và trạng thái

Đối tượng trung tâm của Agentic Checkout Spec — đó là checkout_session trên backend của bạn. Về logic, nó là trạng thái của một lần mua: gồm những sản phẩm nào, tổng tiền bao nhiêu, các tùy chọn giao/fulfillment ra sao và nỗ lực thanh toán hiện đang ở trạng thái nào.

Đặc tả mô tả các trường bắt buộc của checkout_session đại khái như sau (câu chữ được đơn giản hóa và rút gọn so với bản gốc):

  • id — định danh chuỗi của session do bạn sinh ra và trả về. ChatGPT sẽ dùng nó trong mọi lần gọi tiếp theo.
  • buyer — thông tin người mua: tên, email, điện thoại, đôi khi địa chỉ. Trong đặc tả thực, đối tượng này được cấu trúc để PSP và hệ thống của bạn có thể dùng một cách tin cậy.
  • status — enum dạng chuỗi phản ánh trạng thái hiện tại của việc mua. Các trạng thái cơ bản:
    • not_ready_for_payment — chưa thể thanh toán (ví dụ, chưa chọn phương án giao hàng hoặc chưa tính thuế).
    • ready_for_payment — mọi thứ đã sẵn sàng, có thể yêu cầu token thanh toán và trừ tiền.
    • completed — thanh toán thành công, đơn hàng đã được tạo.
    • canceled — giao dịch bị hủy (do người dùng hoặc do lỗi).
  • currency — mã tiền tệ theo ISO 4217 ở chữ thường ("usd", "eur", v.v.).
  • line_items — danh sách các dòng trong giỏ, mỗi dòng có SKU, số lượng và chi phí đã tính.
  • fulfillment_address — địa chỉ giao hàng (nếu liên quan).
  • fulfillment_optionsfulfillment_option_id — các tùy chọn giao/fulfillment khả dụng và tùy chọn đang được chọn.
  • totals — các khoản tổng hợp: giá hàng, thuế, phí giao hàng, tổng cuối.
  • order — đối tượng mô tả đơn hàng sẽ được tạo sau khi session hoàn tất thành công.
  • messages — danh sách thông điệp cho người dùng mà ChatGPT có thể hiển thị: ví dụ, cảnh báo hoặc lỗi.
  • links — danh sách liên kết, ví dụ, đến chính sách hoàn tiền, Privacy Policy và Terms of Service.

Trong demo, không nhất thiết phải triển khai tất cả các trường, nhưng cần hiểu ý tưởng: checkout_session — là “lịch sử và trạng thái hiện tại của một nỗ lực mua hàng”, và ChatGPT kỳ vọng thấy trong đó mọi thứ cần cho UX chuẩn xác.

Để đơn giản, hãy giới thiệu một kiểu rút gọn trong mã học tập của chúng ta:

// Mô hình checkout_session rút gọn cho GiftGenius (không phải toàn bộ SPEC)
type GGCheckoutStatus = 'not_ready_for_payment' | 'ready_for_payment' | 'completed' | 'canceled';

type GGLineItem = { skuId: string; quantity: number; total: number };

type GGCheckoutSession = {
  id: string;
  status: GGCheckoutStatus;
  currency: 'usd';
  lineItems: GGLineItem[];
  grandTotal: number;
};

Mô hình này cố ý đơn giản hơn bản chính thức, nhưng rất phù hợp để thực hành: học cách nắm trạng thái và chuyển trạng thái mà không bị đắm chìm trong hàng trăm trường.

4. Vòng đời của checkout_session

Đặc tả Agentic Checkout mô tả một số thao tác trên checkout_session. Ở dạng rút gọn, vòng đời trông như sau:

  1. Tạo session: POST /checkout_sessions.
  2. Cập nhật session: POST /checkout_sessions/{id}.
  3. Hoàn tất session (complete): POST /checkout_sessions/{id}/complete.
  4. (Đôi khi) Hủy: endpoint cancel riêng hoặc chuyển sang canceled qua cập nhật.

Nhìn từ góc độ trạng thái, có thể vẽ sơ đồ như sau:

stateDiagram-v2
    [*] --> not_ready_for_payment
    not_ready_for_payment --> ready_for_payment: tính phí giao hàng/thuế
chọn tùy chọn ready_for_payment --> completed: POST /complete thành công ready_for_payment --> canceled: người dùng hủy hoặc lỗi not_ready_for_payment --> canceled: lỗi, dữ liệu không tương thích

Tạo checkout_session thường bắt đầu ở trạng thái not_ready_for_payment hoặc ngay ready_for_payment nếu mọi thứ cần cho thanh toán đã rõ (ví dụ, hàng số không cần giao và không có thuế). Cập nhật dùng để bổ sung dữ liệu (địa chỉ, mã giảm giá, tùy chọn giao) và tính lại các khoản. Hoàn tất — là lúc Delegated Payment tham gia và tiền thực sự được trừ.

Ở đây cần hiểu sự phân vai:

  • ChatGPT khởi tạo việc tạo, cập nhật và hoàn tất session dựa trên hội thoại với người dùng.
  • Backend của bạn (merchant) chịu trách nhiệm nghiệp vụ: kiểm tra SKU, tồn kho, tính giá và thuế, chuyển trạng thái, tạo đơn hàng.
  • PSP (Stripe, v.v.) xử lý thanh toán thực và cấp Shared Payment Token mà merchant dùng để trừ tiền.

Chút nữa chúng ta sẽ đặt chồng lên sơ đồ trạng thái này các yêu cầu HTTP cụ thể và vài ví dụ mã nhỏ.

5. Tạo checkout_session: ChatGPT kỳ vọng gì

Khi ChatGPT (hoặc agent) xác định rằng người dùng thực sự muốn mua gì đó, nó hình thành line items dựa trên Product Feed: danh sách SKU, số lượng, tiền tệ dự kiến và có thể là một số mong muốn thêm về giao hàng. Sau đó nó gọi endpoint của bạn POST /checkout_sessions.

Phía merchant lúc này cần:

  1. Kiểm tra dữ liệu vào: đảm bảo mọi SKU đều tồn tại, sẵn sàng bán, không vi phạm chính sách (ví dụ, không bán đồ uống có cồn cho người chưa đủ tuổi).
  2. Tính giá và thuế theo quy tắc của riêng bạn.
  3. Chuẩn bị các tùy chọn fulfillment (nếu là hàng vật lý).
  4. Trả về checkout_session hợp lệ với trạng thái và các khoản tiền.

Trình xử lý đơn giản trên Express cho GiftGenius có thể như sau:

// Pseudocode: tạo checkout_session rút gọn
app.post('/checkout_sessions', async (req, res) => {
  const items = req.body.lineItems as GGLineItem[];  // skuId + quantity
  const pricedItems = await priceItems(items);       // tính total cho mỗi SKU
  const grandTotal = sum(pricedItems.map(i => i.total));

  const session: GGCheckoutSession = {
    id: generateId(),
    status: 'ready_for_payment', // với quà tặng số có thể sẵn sàng thanh toán ngay
    currency: 'usd',
    lineItems: pricedItems,
    grandTotal,
  };

  res.status(201).json(session);
});

Ở đây chúng ta làm vài việc:

  • Không tin các giá trị đầu vào từ client (ChatGPT) và tự tính lại theo dữ liệu của mình — điều này cực kỳ quan trọng cho bảo mật trong commerce.
  • Tự sinh id session (ví dụ, tiền tố gg_chk_...).
  • Trả về trạng thái ready_for_payment nếu không có bước bổ sung (không cần giao hàng, thuế tự động, mô hình đơn giản).

Trong một backend tương thích ACP ngoài đời thực, bạn sẽ trả về thêm messages, links và đối tượng tổng hợp totals, đồng thời điền order (ít nhất ở dạng nháp) như đặc tả mô tả.

6. Cập nhật checkout_session và tính idempotent

Sau khi tạo session, ChatGPT có thể hỏi người dùng thêm chi tiết: địa chỉ giao hàng, áp dụng coupon, đổi phương án fulfillment. Khi có dữ liệu này, nền tảng sẽ gọi POST /checkout_sessions/{id} để bạn cập nhật tính toán.

Về mã thì khá giống với tạo mới, nhưng thay vì sinh session mới, bạn sẽ:

  • tìm session hiện có theo id;
  • áp dụng thay đổi (ví dụ, đổi fulfillment_option_id hoặc thêm giảm giá);
  • tính lại các khoản tiền;
  • trả về checkout_session đã cập nhật.

Quan trọng là đặc tả cho phép gọi lặp (do sự cố mạng hoặc do ChatGPT gửi lại). Vì vậy, như đã nói ở các mô‑đun trước về idempotent cho tools và webhooks, ở đây khuyến nghị dùng Idempotency-Key trong header của yêu cầu và xử lý lặp một cách cẩn thận.

Trình xử lý cập nhật giả định có thể như sau:

app.post('/checkout_sessions/:id', async (req, res) => {
  const id = req.params.id;
  const key = req.header('Idempotency-Key'); // cùng một key => cùng một hiệu ứng
  const existing = await loadSessionWithIdempotency(id, key, req.body);

  // applyUpdates bên trong có thể tính lại giá, giao hàng, v.v.
  const updated = await applyUpdates(existing, req.body);
  await saveSession(updated, key);

  res.json(updated);
});

Ở đây chúng ta không bám cứng cấu trúc SPEC cụ thể, mà trình bày ý tưởng: đầu vào — thay đổi và khóa idempotent, đầu ra — trạng thái checkout_session nhất quán. Nếu đến bạn một yêu cầu giống hệt với cùng một khóa, bạn phải trả về đúng kết quả cũ, không tạo đơn hàng thừa hay bản ghi log trùng lặp.

7. Hoàn tất checkout_session và Delegated Payment: Shared Payment Token hoạt động ra sao

Khoảnh khắc thú vị và dễ căng thẳng nhất — hoàn tất checkout_session, khi tiền thực sự được trừ. Lúc này đặc tả thứ hai tham gia: Delegated Payment.

Ý tưởng Delegated Payment

Người dùng nhập hoặc chọn phương thức thanh toán trong giao diện ChatGPT (thẻ, ví, phương thức đã lưu). Nền tảng không gửi trực tiếp dữ liệu này cho bạn — thay vào đó nó yêu cầu PSP (ví dụ, Stripe) cấp một token đặc biệt, Shared Payment Token (SPT), token này:

  • gắn duy nhất với merchant và session cụ thể;
  • giới hạn theo số tiền và thời gian sống;
  • không tiết lộ số thẻ thật cho bạn.

Kết quả là bức tranh như sau:

Tác nhân Nhìn thấy thông tin thẻ thanh toán Nhìn thấy Shared Payment Token Nhìn thấy chi tiết đơn hàng (SKU, số tiền)
Người dùng Không (không cần) Một phần (mua gì và giá bao nhiêu)
ChatGPT/OpenAI
PSP (Stripe) Trong phạm vi giao dịch
Merchant Không

Thiết kế này giúp merchant tránh lưu trữ dữ liệu thẻ và tập trung vào nghiệp vụ đơn hàng, để các vấn đề compliance cho PSP và nền tảng xử lý.

Insight

Ý nghĩa của Shared Payment Token là ẩn dữ liệu thẻ khỏi backend của bạn, nhưng chính bạn vẫn là bên thực hiện thanh toán. Bạn cũng có thể nhìn nó theo một góc khác.

Hẳn bạn từng gặp tình huống cửa hàng hoặc khách sạn trước tiên hold tiền trên thẻ của bạn, rồi sau đó mới trừ. Hãy xem Shared Payment Token như một token hold. ChatGPT đã hold tiền trên tài khoản người dùng, nhưng chưa trừ. Nó chuyển cho bạn token hold này và giờ bạn có thể chuyển nó cho Stripe để trừ tiền.

Có hai điểm quan trọng:

  • số tiền hold và số tiền trừ không nên chênh lệch nhiều, tốt nhất là trùng khớp.
  • bạn có thể bán tháng đầu của gói thuê bao qua ChatGPT với $1, rồi sau đó trừ $49.99 mỗi tháng.

Yêu cầu POST /checkout_sessions/{id}/complete

Khi người dùng nhấn nút xác nhận thanh toán trong Instant Checkout, ChatGPT:

  1. Yêu cầu SPT từ PSP (ví dụ qua Stripe ACP API).
  2. Gửi token này đến backend của bạn qua POST /checkout_sessions/{id}/complete cùng với dữ liệu người mua.

Đặc tả mô tả thân yêu cầu đại khái như sau (dưới đây là ví dụ đã được điều chỉnh và rút gọn từ tài liệu chính thức):

POST /checkout_sessions/checkout_session_123/complete

{
  "buyer": {
    "first_name": "John",
    "last_name": "Smith",
    "email": "johnsmith@mail.com"
  },
  "payment_data": {
    "token": "spt_123",
    "provider": "stripe"
  }
}

Backend của bạn cần:

  1. Tìm checkout_session với id checkout_session_123.
  2. Kiểm tra rằng trạng thái cho phép hoàn tất (thường là ready_for_payment).
  3. Tạo giao dịch tại PSP, dùng token spt_123 (cách làm tùy PSP, với Stripe — một endpoint và loại payment method cụ thể).
  4. Chờ xác nhận giao dịch thanh toán.
  5. Cập nhật checkout_session sang completed, tạo và lưu đơn hàng, điền trường order trong cấu trúc session.
  6. Trả về checkout_session hiện thời trong phản hồi.

Ở dạng TypeScript rất rút gọn, điều này có thể như sau:

app.post('/checkout_sessions/:id/complete', async (req, res) => {
  const { id } = req.params;
  const { buyer, payment_data } = req.body;
  const session = await loadSession(id);

  await chargeWithSharedToken(payment_data.token, session.grandTotal);
  const completed = await markSessionCompleted(session, buyer);

  res.json(completed);
});

Ngoài đời thực, giữa các dòng này sẽ là xử lý lỗi, thử lại, logging và tích hợp với mô hình đơn hàng của bạn.

Nếu có gì đó không ổn (ví dụ, thanh toán bị từ chối), bạn cần trả về checkout_session với trạng thái not_ready_for_payment hoặc canceled và điền messages để ChatGPT có thể giải thích rõ cho người dùng điều gì đã xảy ra.

8. Instant Checkout trong ChatGPT: tất cả ghép lại thành một luồng

Giờ hãy ghép các mảnh này thành kịch bản hoàn chỉnh “từ ý định đến thanh toán” trong ChatGPT. Bạn có thể xem bài này như “giải mã” những gì ẩn sau một nút “Mua” trong widget.

Kịch bản rút gọn:

  1. Người dùng viết: “Hãy gợi ý quà tặng số cho bạn với ngân sách đến $50 và thanh toán ngay”.
  2. Agent (hoặc chính ChatGPT App) dùng Product Feed để tìm SKU phù hợp trong phạm vi ngân sách.
  3. ChatGPT hiển thị vài thẻ quà (qua widget GiftGenius của bạn) và đề nghị chọn một cái.
  4. Sau khi chọn, ChatGPT tạo line items và gọi POST /checkout_sessions lên ACP backend của bạn, nhận về checkout_session với các khoản và trạng thái.
  5. Trong UI Instant Checkout, người dùng thấy tổng tiền, tên sản phẩm, chính sách hoàn trả và nút xác nhận.
  6. Khi xác nhận, ChatGPT nhận Shared Payment Token từ PSP và gọi POST /checkout_sessions/{id}/complete, như đã bàn ở trên.
  7. Backend của bạn thực hiện thanh toán, tạo đơn hàng, trả về checkout_session với trạng thái completed.
  8. ChatGPT hiển thị xác nhận cho người dùng, và backend của bạn (qua webhooks theo Agentic Checkout Spec) có thể gửi sự kiện ngược về OpenAI để nền tảng biết số phận đơn hàng.

Ở dạng sơ đồ sequence, trông như sau:

sequenceDiagram
    actor U as Người dùng
    participant GPT as ChatGPT
    participant GG as GiftGenius ACP backend
    participant PSP as Stripe (PSP)

    U->>GPT: Tôi muốn quà tặng đến $50 và mua ngay tại đây
    GPT->>GG: POST /checkout_sessions (line_items)
    GG-->>GPT: checkout_session (ready_for_payment)
    GPT->>U: Hiển thị Instant Checkout (sản phẩm, giá, ToS)
    U->>GPT: Nhấn “Xác nhận thanh toán”
    GPT->>PSP: Yêu cầu SPT cho số tiền và merchant
    PSP-->>GPT: Shared Payment Token (spt_xxx)
    GPT->>GG: POST /checkout_sessions/{id}/complete (token + buyer)
    GG->>PSP: Thanh toán bằng SPT
    PSP-->>GG: Thanh toán thành công
    GG-->>GPT: checkout_session (completed + order)
    GPT-->>U: Hiển thị xác nhận mua hàng

Trong kịch bản này, không xuất hiện các lời gọi “tùy ý” đến cơ sở dữ liệu của bạn hay endpoint nội bộ lạ. Mọi thứ đều nằm trong hợp đồng ACP được mô tả rõ ràng, nơi mỗi bên đều biết vai trò của mình.

9. Thực hành nhỏ: ACP backend giản lược cho GiftGenius

Để bài giảng không chỉ là lý thuyết, quan trọng là “chạy thử” trong đầu việc triển khai lớp ACP cho dự án học tập của chúng ta.

Giả sử GiftGenius đã có:

  • CSDL SKU và giá, dựa trên đó chúng ta tạo Product Feed (đã mô phỏng ở bài trước).
  • Mô hình đơn hàng đơn giản: bảng orders với các trường id, userId, skuId, amount, currency, status, createdAt.
  • Giao diện ChatGPT App và lớp MCP biết cách gợi ý quà (chúng ta đã xây ở các mô‑đun trước).

Giờ nhiệm vụ của bạn — thêm bên trên một dịch vụ nhỏ gg-acp:

  • Endpoint POST /checkout_sessions:
    • Nhận danh sách SKU và số lượng.
    • Tính lại các khoản dựa trên CSDL của bạn.
    • Tạo đơn hàng nháp (ví dụ với trạng thái pending) và checkout_session với trạng thái ready_for_payment.
    • Trả về checkout_session.
  • Endpoint POST /checkout_sessions/{id}:
    • Tìm session và đơn hàng.
    • Áp dụng thay đổi (ví dụ, hỗ trợ mã giảm giá làm giảm tổng cuối).
    • Trả về checkout_session đã cập nhật.
  • Endpoint POST /checkout_sessions/{id}/complete:
    • Nhận SPT, số tiền và dữ liệu người mua.
    • Trong bản demo có thể chỉ đánh dấu đơn là “đã thanh toán” mà không cần gọi tích hợp thực đến PSP (hoặc bạn có thể mô phỏng Stripe).
    • Cập nhật checkout_session sang trạng thái completed và gắn order_id vào.

Toàn bộ dịch vụ này có thể triển khai trong một ứng dụng nhỏ Node/Express hoặc các endpoint của Next.js App Router. Điều quan trọng — tuân thủ hợp đồng về định dạng và trạng thái, ngay cả khi bạn mô phỏng thanh toán.

Mô hình đơn hàng giả định trong TypeScript có thể như sau:

// Mô hình đơn hàng rút gọn của GiftGenius
type GGOrderStatus = 'pending' | 'paid' | 'canceled';

type GGOrder = {
  id: string;
  userId: string;
  skuId: string;
  amount: number;
  currency: 'usd';
  status: GGOrderStatus;
};

Trong production, phía trên sẽ có thêm liên kết với Auth/Identity (để biết người dùng trong chat là ai), webhooks đến OpenAI và các kịch bản hoàn tiền phức tạp hơn. Nhưng như một bước học tập trong phạm vi bài này, chỉ cần thành thạo vòng lặp: tạo session → cập nhật → hoàn tất, mà không làm mất tiền và lý trí.

10. Các lỗi thường gặp khi thiết kế ACP / Instant Checkout

Lỗi số 1: trộn vai (“ChatGPT — đây là cửa hàng của tôi”).
Đôi khi lập trình viên mặc định coi ChatGPT là “hệ thống sổ cái trung tâm” và cố lưu trạng thái nghiệp vụ của đơn hàng ở phía nền tảng: “đã có checkout_session, vậy tôi sẽ đọc lịch sử đơn hàng từ OpenAI”. Đó là ngõ cụt. checkout_session — là đối tượng của giao thức, không phải nguồn sự thật về đơn hàng. Nguồn sự thật — commerce backend của bạn: chính ở đó các đơn hàng, trạng thái, hoàn tiền và báo cáo phải sống. Trong sơ đồ này, ChatGPT chỉ là “frontend trong chat” đáng tin cậy.

Lỗi số 2: tin vào giá trị đầu vào từ ChatGPT.
Dễ nghĩ rằng “agent đã lựa chọn SKU và thậm chí tính tổng, vậy cứ nhận tổng đó và trừ tiền”. Không được làm vậy. Đầu vào từ ChatGPT (line items, giá dự kiến) phải coi như đề xuất, không phải mệnh lệnh. Backend của bạn bắt buộc tự kiểm tra SKU, giá, tồn kho, khả năng áp dụng giảm giá, v.v., so sánh với Product Feed và CSDL của chính bạn. Nếu không, bạn sẽ gặp những lỗi thú vị kiểu “người dùng mua hàng với giá $0.01 vì model quyết định làm tròn”.

Lỗi số 3: bỏ qua trạng thái và state machine.
Trong prototype sớm, thường có triển khai “thủng”: trạng thái session luôn completed, hoặc chỉ ok, còn mọi chênh lệch với trạng thái thanh toán thực bị giấu bên trong. Kết quả là ChatGPT không thể hiển thị chính xác cho người dùng: thanh toán đang xử lý, đã hoàn tất hay đã bị hủy. Đáng tin cậy hơn nhiều là triển khai trung thực state machine not_ready_for_paymentready_for_paymentcompleted/canceled và trả về trạng thái thực từ backend, thay vì bịa ra các trường ad‑hoc.

Lỗi số 4: dùng Shared Payment Token như “thẻ dùng nhiều lần”.
Theo thiết kế, SPT là token dùng một lần hoặc bị ràng buộc chặt: gắn với thao tác, số tiền và merchant cụ thể. Cố gắng cache “để dành” hoặc dùng lại cho giao dịch khác — là ý tưởng tệ. Tốt nhất PSP sẽ từ chối lần dùng thứ hai; tệ nhất — bạn làm loạn sổ sách thanh toán và đơn hàng. Mỗi checkout_session.complete phải có một token mới, và nếu thanh toán thất bại — cần yêu cầu token mới.

Lỗi số 5: thiếu tính idempotent trong /checkout_sessions và webhooks.
Trong mạng thực, yêu cầu có thể bị lặp: ChatGPT có thể gửi lại POST /checkout_sessions sau khi timeout, PSP có thể gửi lại webhook sau lỗi tạm thời. Nếu triển khai của bạn mỗi lần đều tạo đơn hàng mới và bản ghi mới, bạn sẽ nhanh chóng gặp hỗn loạn: trừ tiền đôi, đơn hàng trùng và sai khác kỳ quặc giữa các hệ thống. Dùng Idempotency-Key, kiểm tra lặp và lưu kết quả của các lần gọi trước — không phải “tối ưu tùy chọn”, mà là thành phần bắt buộc của tích hợp ACP đáng tin cậy.

Lỗi số 6: quên liên kết với Product Feed.
Đôi khi lớp ACP được thiết kế “trong chân không”: SKU và giá lấy từ các bảng nội bộ không trùng với những gì đẩy vào Product Feed. Hậu quả là ChatGPT hiển thị cho người dùng một đằng (từ feed), còn vào checkout qua ACP lại là một nẻo. Để tránh bất ngờ, quan trọng là mô hình SKU và giá của bạn phải thống nhất: feed, ACP backend và CSDL nội bộ đều nhìn vào cùng một nguồn sự thật, dù phía trên có các projection và cache khác nhau.

Bình luận
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION