Test checkout & events
Simulate checkout, verify the order, return to your store and trigger signed test events.
New integration? Start with First order in 10 minutes for a runnable test-key-to-verified-webhook example.
Test an order from checkout to shipment
Use a tcgp_test_ API key or a widget with data-mode="test". Artwork validation is real; checkout and fulfillment are simulated. This works even when the platform uses live Stripe credentials. No charge, printing, shipping, credit deduction or Connect transfer occurs.
- No webhook setup is required. The built-in demo receiver records simulated events and shows signature verification, a simulated failed delivery and retry, and duplicate protection. Connecting your own Test order webhook is optional.
- Create a cart with your test key and real test artwork. Save the returned cart ID, your customer/session, and the exact selected items and quantities as an immutable checkout revision. Set
external_refto that revision andreturn_urlto your thank-you page on the registered website origin. - Poll the cart until
open. Open itscheckout_url. In the widget, click Open simulated checkout; this opens a full page, while live delivery checkout remains embedded. - Use the dummy delivery details, select the simulation confirmation and click Complete simulated checkout. The fields are demonstration inputs and are not saved. A single
test_order_…order and anorder.paidtest event are saved atomically. The cart becomesconverted. - Click Return to your store. After server verification, the saved return URL receives
cart_id,order_id,mode=testandsimulated=true. Existing query parameters are preserved. These browser parameters are hints, not proof of confirmation. - Your server reads the saved cart and its
order_idwith the test key, verifies the simulated order, and removes only that revision's purchased quantities. Items added or changed afterwards stay in the cart. A repeated redirect or webhook must not remove items twice.
Server-only completion for automated tests
This uses the same validation and atomic order creation as the browser button. Only an open, unexpired test hosted/Connect cart belonging to the key is eligible. No Idempotency-Key is needed: completion is idempotent by cart. Repeats return the current order and do not emit another paid event.
curl --request POST 'https://partner.tcgplaytest.com/v1/test/carts/CART_ID/complete' \
--header "Authorization: Bearer $TCGP_TEST_API_KEY" \
--header 'Content-Type: application/json' \
--data '{"confirm_simulation":true}'Verify before clearing purchased items
This example runs on your server. Implement the ownership lookup and transaction against your own store database. Keep test and live carts separate; never clear a live purchase using a simulated event.
// Load from your database using the signed-in customer, not a browser order_id.
const revision = await loadOwnedCheckoutRevision(customer.id);
const read = async path => {
const response = await fetch(API_BASE + path, {
headers: { Authorization: "Bearer " + process.env.TCGP_TEST_API_KEY },
cache: "no-store"
});
if (!response.ok) throw new Error("Order verification unavailable");
return response.json();
};
const cart = await read("/v1/carts/" + revision.cartId);
if (revision.mode !== "test" || cart.mode !== "test" ||
cart.status !== "converted" || !cart.order_id) return;
const order = await read("/v1/orders/" + cart.order_id);
if (order.cart_id !== revision.cartId || order.external_ref !== revision.externalRef ||
order.mode !== "test" || order.simulated !== true ||
!["paid", "in_production", "shipped"].includes(order.status)) return;
// One transaction: lock this revision, skip if already cleared,
// verify order.items (item_index + quantity) against its frozen snapshot,
// remove only those purchased quantities, then mark this revision cleared.
// Preserve later additions/edits. NEVER clear the customer's entire cart.
await clearPurchasedRevisionOnce(customer.id, revision, order);For a standalone widget, configure an async onCartReady(cart) callback to save the cart ID against your customer on your server before checkout opens. It is awaited and can run again on retries, so make it idempotent. Set returnUrl to your thank-you URL and externalRef to your saved revision. A public partner code is not customer authentication. You can use the same partner's test API key to read its widget cart/order.
Simulate production and shipment
Using the returned test_order_… ID, send in_production, then shipped. Each successful transition queues the matching signed Test webhook. Shipment uses a clearly marked dummy carrier and tracking link. You can instead send cancelled from paid or in-production; shipped/cancelled orders cannot start a new lifecycle. Create a new cart for another scenario.
curl --request POST 'https://partner.tcgplaytest.com/v1/test/orders/TEST_ORDER_ID/events' \
--header "Authorization: Bearer $TCGP_TEST_API_KEY" \
--header 'Content-Type: application/json' \
--data '{"status":"in_production"}'
# Repeat with {"status":"shipped"} after production.
# Or {"status":"cancelled"} before shipment.
curl 'https://partner.tcgplaytest.com/v1/orders/TEST_ORDER_ID' \
--header "Authorization: Bearer $TCGP_TEST_API_KEY"Order responses include mode: "test", simulated: true and the original item-index/quantity snapshot. Webhook data includes the same test markers. Event types are order.paid, order.in_production, order.shipped and order.cancelled. Repeating an already-emitted transition returns current state without re-emitting it. Invalid transitions return 409. Live keys return 403, other partners' IDs return 404.
Built-in demo receiver
After checkout, use the production and shipment buttons to finish the lifecycle. Expand each demo receipt to inspect the event payload and attempt statuses. Replay a duplicate or try an invalid signature; neither applies the same event twice. Order responses include demo_webhook, with the demo state and per-event receipts. These are persistent simulated results, not external delivery acknowledgments. No demo event changes customer payments, your store database, or the external webhook queue.
Optional: your own webhook receiver
Delivery uses the existing signed webhook queue and maintenance worker, so it is asynchronous. Verify the exact raw body with your Test signing secret, reject stale timestamps, deduplicate event IDs and handle events arriving out of order. Read current order status when necessary. Saving a simulation confirms it was queued, not that your endpoint accepted it. If nothing arrives, check the Test webhook URL, worker schedule and delivery attempts; see webhook setup. The shared API-key rate limit also applies to completion, event simulation and order reads.
Connect simulation and what remains to test
With a test key, send the usual settlement: "connect" and retail_amount_cents in the cart request. No Connect onboarding is required for this simulator. It exercises your order flow and echoes the supplied card retail price; it does not calculate or collect a customer total. Stripe checkout, pricing, discounts, tax, fees, transfers, reserves, refunds and payout onboarding still require a separate Stripe test-environment checkout. The prepaid sandbox keeps its existing flow and is not accepted by these new endpoints.
Live orders always require real server-verified payment. Never treat simulated: true as real payment or send simulated orders to fulfillment.