Create a checkout and place an order
View as MarkdownCreate a checkout session with selected products, update it with buyer and payment details, complete the checkout, and retrieve the resulting order.
Overview
Use this Shopping API v1 workflow to create a checkout, select payment, accept agreements, complete the checkout session to place the order, and retrieve its details.
A checkout session moves through states (incomplete → ready_for_complete → completed) as you add required data. All write operations require shopping.checkout:execute scope. Order retrieval requires shopping.order:read scope.
Go to About the Shopping API for required headers and the checkout state machine.
Prerequisites
The following prerequisites are required before you can create a checkout and place an order:
- at least one variant ID from the product catalog
- a PAT with
shopping.checkout:executeandshopping.order:readscopes - an eligible saved payment instrument on the GoDaddy account
jqanduuidgenfor the curl examples
Go to Search the catalog to get a variant ID.
Authenticate
These examples use a $GODADDY_PAT with shopping.checkout:execute and shopping.order:read scopes.
Go to About the Shopping API for the full list of required scopes.
Create a checkout session
POST /v1/shopping/checkout-sessions creates a checkout session with one or more line items. Pass variant IDs from the catalog search results.
The following procedure creates a checkout session.
-
Create a session with a selected variant:
export CREATE_IDEMPOTENCY_KEY="$(uuidgen)" CREATE_RESPONSE="$(curl --fail-with-body --silent --show-error -X POST "https://api.godaddy.com/v1/shopping/checkout-sessions" \ -H "Authorization: Bearer $GODADDY_PAT" \ -H "Request-Id: $(uuidgen)" \ -H "Idempotency-Key: $CREATE_IDEMPOTENCY_KEY" \ -H "Content-Type: application/json" \ -d "$(jq -n --arg id "$VARIANT_ID" '{context:{currency:"USD"},line_items:[{item:{id:$id},quantity:1}]}')")" export SESSION_ID="$(jq -er '.id' <<<"$CREATE_RESPONSE")" export LINE_ITEM_ID="$(jq -er '.line_items[0].id' <<<"$CREATE_RESPONSE")" export PAYMENT_INSTRUMENT_ID="$(jq -er '.payment.instruments | (map(select(.selected == true))[0] // .[0]).id' <<<"$CREATE_RESPONSE")" export PAYMENT_HANDLER_ID="$(jq -er '.payment.instruments | (map(select(.selected == true))[0] // .[0]).handler_id' <<<"$CREATE_RESPONSE")" export PAYMENT_INSTRUMENT_TYPE="$(jq -er '.payment.instruments | (map(select(.selected == true))[0] // .[0]).type' <<<"$CREATE_RESPONSE")"
The response includes an id and initial status. Save the writable line items and returned payment instruments for later requests.
Go to Example responses for trimmed response examples.
Idempotency key
Always send a unique Idempotency-Key on POST /checkout-sessions.
If the request times out, retry the unchanged request with the same key. The server returns the existing session instead of creating a duplicate.
A status of incomplete means required fields are missing. A status of ready_for_complete means all required fields are present. Check messages[] in the response for specific missing-field details.
Review the checkout
GET /v1/shopping/checkout-sessions/{id} returns current line items, totals, saved payment instruments, messages, links, and required agreements.
The following procedure refreshes the checkout before an update or completion.
-
Retrieve the checkout and selected payment instrument:
CHECKOUT_RESPONSE="$(curl --fail-with-body --silent --show-error \ "https://api.godaddy.com/v1/shopping/checkout-sessions/$SESSION_ID" \ -H "Authorization: Bearer $GODADDY_PAT" \ -H "Request-Id: $(uuidgen)")" export PAYMENT_INSTRUMENT_ID="$(jq -er '.payment.instruments | (map(select(.selected == true))[0] // .[0]).id' <<<"$CHECKOUT_RESPONSE")" export PAYMENT_HANDLER_ID="$(jq -er '.payment.instruments | (map(select(.selected == true))[0] // .[0]).handler_id' <<<"$CHECKOUT_RESPONSE")" export PAYMENT_INSTRUMENT_TYPE="$(jq -er '.payment.instruments | (map(select(.selected == true))[0] // .[0]).type' <<<"$CHECKOUT_RESPONSE")"
Persist the checkout ID, writable line item, and selected instrument for later requests. Preserve the instrument's returned id, handler_id, and type.
The standalone Go examples read these values from SESSION_ID, LINE_ITEM_ID, PAYMENT_INSTRUMENT_ID, PAYMENT_HANDLER_ID, and PAYMENT_INSTRUMENT_TYPE.
Update the checkout
PUT /v1/shopping/checkout-sessions/{id} replaces the writable checkout state. Use it to select a saved payment instrument and resend all line items.
PUT is a full replace, not a merge. Include the complete line_items[] array and every product input on each update. Omitting a writable field clears its previous value.
Payment instruments must already exist on the GoDaddy account. If none is eligible, add one at GoDaddy payment methods and retrieve the checkout again. Set BUYER_FIRST_NAME, BUYER_LAST_NAME, BUYER_EMAIL, and BUYER_PHONE to the buyer's contact values before running the examples.
The following procedure selects a payment instrument.
-
Select a payment instrument and resend all line items:
export UPDATE_IDEMPOTENCY_KEY="$(uuidgen)" UPDATE_RESPONSE="$(curl --fail-with-body --silent --show-error -X PUT "https://api.godaddy.com/v1/shopping/checkout-sessions/$SESSION_ID" \ -H "Authorization: Bearer $GODADDY_PAT" \ -H "Request-Id: $(uuidgen)" \ -H "Idempotency-Key: $UPDATE_IDEMPOTENCY_KEY" \ -H "Content-Type: application/json" \ -d "$(jq -n \ --arg line_id "$LINE_ITEM_ID" --arg variant_id "$VARIANT_ID" \ --arg first "$BUYER_FIRST_NAME" --arg last "$BUYER_LAST_NAME" \ --arg email "$BUYER_EMAIL" --arg phone "$BUYER_PHONE" \ --arg instrument_id "$PAYMENT_INSTRUMENT_ID" --arg handler "$PAYMENT_HANDLER_ID" \ --arg type "$PAYMENT_INSTRUMENT_TYPE" \ '{context:{currency:"USD"},line_items:[{id:$line_id,item:{id:$variant_id},quantity:1}],buyer:{first_name:$first,last_name:$last,email:$email,phone_number:$phone},payment:{instruments:[{id:$instrument_id,handler_id:$handler,type:$type,selected:true}]}}')")"
After the update, check status:
- If
ready_for_complete, proceed to complete the checkout. - If
incomplete, checkmessages[]for remaining required fields. - If
required_agreements[]is present, includeconsentwhen completing.
Line item removal warning
If an item can't be priced at update time, the server removes it from line_items[] and attaches a messages[] entry with code: line_item_removed. Check for missing items before proceeding.
Configure products and fulfillment
Include one line_items[] entry for each selected variant. Set quantity for each entry and preserve its returned line-item id on updates.
Some variants expose an input_schema. Build line_items[].input from that schema and resend the input on every PUT request.
| Data | Request location |
|---|---|
| Buyer contact | buyer.first_name, buyer.last_name, buyer.email, and buyer.phone_number |
| Product configuration | line_items[].input |
| Shipping or pickup | fulfillment.methods[] and its selected destination |
| Billing address | payment.instruments[].billing_address |
| Saved payment selection | The returned instrument id, handler_id, type, and selected: true |
Do not assume every saved instrument is a card. Preserve the handler and type returned by the checkout.
Go to Shopping Checkout reference for the full input, fulfillment, payment, and address schemas.
Handle required agreements
Before completing, check the checkout response for required_agreements[]. Some purchases require the buyer to accept terms first.
Before completing:
- Include each agreement with
required: trueinconsent.agreement_types. - Record the buyer's acceptance time in
agreed_at.
Missing or incomplete consent returns HTTP 400 with validation_error.
Example required_agreements[] in a checkout response:
{
"required_agreements": [
{
"key": "api_services_purchase_agreement",
"title": "API Services Purchase Agreement",
"url": "https://www.godaddy.com/legal/agreements/api-services-purchase-agreement",
"required": true
}
]
}Complete the checkout
POST /v1/shopping/checkout-sessions/{id}/complete completes a ready_for_complete session and creates its order. The request body must include payment. Include consent if the checkout has required_agreements[].
The following procedure completes the checkout.
-
Complete the session:
export COMPLETE_IDEMPOTENCY_KEY="$(uuidgen)" export AGREED_AT="$(date -u +%Y-%m-%dT%H:%M:%SZ)" REQUIRED_AGREEMENTS="$(jq -c '[.required_agreements[]? | select(.required == true) | .key]' <<<"$UPDATE_RESPONSE")" COMPLETE_BODY="$(jq -n \ --arg instrument_id "$PAYMENT_INSTRUMENT_ID" --arg handler "$PAYMENT_HANDLER_ID" \ --arg type "$PAYMENT_INSTRUMENT_TYPE" --argjson agreements "$REQUIRED_AGREEMENTS" \ --arg agreed_at "$AGREED_AT" \ '{payment:{instruments:[{id:$instrument_id,handler_id:$handler,type:$type,selected:true}]}} + (if ($agreements | length) > 0 then {consent:{agreement_types:$agreements,agreed_at:$agreed_at}} else {} end)')" COMPLETE_RESPONSE="$(curl --fail-with-body --silent --show-error -X POST "https://api.godaddy.com/v1/shopping/checkout-sessions/$SESSION_ID/complete" \ -H "Authorization: Bearer $GODADDY_PAT" \ -H "Request-Id: $(uuidgen)" \ -H "Idempotency-Key: $COMPLETE_IDEMPOTENCY_KEY" \ -H "Content-Type: application/json" \ -d "$COMPLETE_BODY")" export ORDER_ID="$(jq -er '.order.id' <<<"$COMPLETE_RESPONSE")"
The completion examples build consent from the checkout's required agreements. Never hardcode agreement keys across products.
The standalone Go completion example reads the required agreement-key array from REQUIRED_AGREEMENTS_JSON and the retry-stable key from COMPLETE_IDEMPOTENCY_KEY.
{
"payment": { "instruments": [{ "id": "$PAYMENT_INSTRUMENT_ID", "handler_id": "$PAYMENT_HANDLER_ID", "type": "$PAYMENT_INSTRUMENT_TYPE", "selected": true }] },
"consent": {
"agreement_types": ["api_services_purchase_agreement"],
"agreed_at": "$AGREED_AT"
}
}When status is completed, order.id contains the order identifier and order.permalink_url links to the receipt.
Retrieve the order
GET /v1/shopping/orders/{id} returns order totals, line statuses, fulfillment data, and a receipt link. A new order might return 404 order_not_found while the read model updates.
The following procedure retrieves an order.
-
Get order detail:
ORDER_FILE="$(mktemp)" delay=1 for attempt in 1 2 3 4 5 6; do status="$(curl --silent --show-error -o "$ORDER_FILE" -w '%{http_code}' \ "https://api.godaddy.com/v1/shopping/orders/$ORDER_ID" \ -H "Authorization: Bearer $GODADDY_PAT" \ -H "Request-Id: $(uuidgen)")" if [ "$status" = "200" ]; then break; fi code="$(jq -r '.messages[0].code // empty' "$ORDER_FILE")" if [ "$status" != "404" ] || [ "$code" != "order_not_found" ]; then jq . "$ORDER_FILE" >&2 exit 1 fi sleep "$delay" delay=$((delay < 4 ? delay * 2 : 4)) done test "$status" = "200" ORDER_RESPONSE="$(cat "$ORDER_FILE")" rm -f "$ORDER_FILE"
Example responses
The following sections provide example responses for creating and completing checkout sessions.
Checkout session
POST /checkout-sessions returns 201 with a session object. An eligible saved instrument can make it immediately ready_for_complete:
{
"id": "d9cf79e3-b39b-4e58-8f30-ddfe1619e969",
"status": "ready_for_complete",
"currency": "USD",
"line_items": [
{
"id": "1",
"item": { "id": "hosting-economyapi:1mo" },
"quantity": 1,
"totals": [
{ "type": "subtotal", "amount": 999 },
{ "type": "total", "amount": 999 }
]
}
],
"totals": [
{ "type": "subtotal", "amount": 999 },
{ "type": "total", "amount": 999 }
],
"payment": {
"instruments": [
{
"id": "payment-instrument-id",
"handler_id": "com.godaddy.payments",
"type": "card",
"selected": true
}
]
},
"required_agreements": [
{
"key": "universal_terms_and_conditions",
"title": "Universal Terms of Service Agreement",
"required": true,
"url": "https://www.godaddy.com/legal/agreements/universal-terms-of-service-agreement"
}
],
"ucp": { "version": "2026-04-08" }
}Completed checkout
POST /checkout-sessions/{id}/complete returns status: completed when payment succeeds. Use the numeric order.id to retrieve the order:
{
"id": "d9cf79e3-b39b-4e58-8f30-ddfe1619e969",
"status": "completed",
"order": {
"id": "2211390786",
"permalink_url": "https://account.godaddy.com/receipts/view/2211390786"
},
"ucp": { "version": "2026-04-08" }
}Common errors
| Response | messages[].code | Cause | Action |
|---|---|---|---|
200 with warning | line_item_removed | A line item could not be priced and was removed from the session. | Re-check line_items[] before completion. |
400 | payment_instrument_invalid | The selected payment profile is unavailable or ineligible. | Retrieve the checkout and select an eligible instrument. |
400 | validation_error | POST /complete was called with missing or incomplete consent.agreement_types. | Check the checkout's required_agreements[], collect buyer consent, and retry with consent included. |
401 | — | The PAT is missing, invalid, or expired. | Generate or export a valid PAT. |
403 | — | The PAT lacks the required Shopping scope. | Generate a PAT with shopping.checkout:execute and shopping.order:read. |
422 | item_not_found, invalid_domain, invalid_term, unsupported_currency | The request is valid JSON but cannot be processed. | Correct the item or currency before retrying with a new idempotency key. |
404 | order_not_found | A completed order is not visible in the read model yet. | Retry the unchanged GET with bounded backoff. |
429 | — | Rate limit exceeded. | Wait for the Retry-After header value, then retry. |
Checkout reads after completion
After completion, GET /checkout-sessions/{id} might return 404 checkout_not_found. Keep the completion response and use its order.id for order retrieval. Go to About the Shopping API for error handling.
Verify the purchase
Confirm that completion returned status: completed and a numeric order.id. After the order becomes visible, verify its currency, total, line-item statuses, and receipt permalink.
Fulfillment events[] and expectations[] are optional. Process them when present; do not require one expectation per line item.
Agent & Automation Notes
shopping.checkout:execute, shopping.order:readRelated
Last updated on
How is this guide?