— Technical
Managing guest cart billing address via REST API in Magento 2
14 August 2024 · 4 min read
Guest checkout flows are where Magento integrations most often break down. Headless storefronts, mobile apps, and third-party order management systems all need to manage cart state programmatically, and the billing address step is a common sticking point because the endpoint behaviour is less obvious than it looks.
Here’s how the guest cart billing address endpoint works, what it returns, and the edge cases worth knowing before you hit them in production.
The endpoint
/V1/guest-carts/:cartId/billing-address
cartId here is the masked cart ID — the long random string generated when a guest cart is created (e.g. tYqIEtiDdGx2Jw9MAyzR7FP9tx6ruD4b). This is not a numeric ID. If you’re passing a numeric ID you’re using the wrong endpoint — that would be the authenticated customer cart endpoint.
Setting a billing address (POST)
POST /rest/V1/guest-carts/{maskedCartId}/billing-address
Request payload:
{
"address": {
"region": "",
"country_id": "GB",
"street": [
"West Road"
],
"postcode": "W1S 1LA",
"city": "London",
"firstname": "John",
"lastname": "Smith",
"email": "john@example.com",
"telephone": "02012345678"
}
}
A successful response returns the billing address ID as an integer — typically the quote_address table’s address_id. You don’t need this value for subsequent checkout steps, but it confirms the write succeeded.
The email field is required for guest carts. Magento uses this as the guest’s identity for order confirmation and tracking. Omitting it will cause the checkout to fail at order placement even if the address was saved successfully.
street must be an array even if you only have one line. Passing a string will fail silently on some Magento versions — the address saves but the street is empty.
Retrieving a billing address (GET)
GET /rest/V1/guest-carts/{maskedCartId}/billing-address
Returns the full address object as stored on the quote. If no billing address has been set yet, Magento returns a 404. Handle this in your frontend rather than treating an empty billing address as an error state.
The useForShipping flag
The endpoint also accepts a useForShipping boolean at the top level of the request body:
{
"address": { ... },
"useForShipping": true
}
When true, Magento copies the billing address to the shipping address on the quote. This is the correct way to implement “same as billing” in a headless context — not by making a second API call to the shipping address endpoint with the same data.
Authentication
Guest cart endpoints use the masked cart ID as the authentication mechanism — no bearer token required. The downside is that anyone who knows the masked ID can modify the cart. This is by design for guest flows, but it means you should treat masked cart IDs as session-scoped secrets and not expose them in URLs or logs.
What breaks in practice
The most common integration issue I’ve seen here is timing: a mobile app sets the billing address before Magento has assigned a payment method to the quote, then calls the order placement endpoint and gets a generic failure. Magento validates the billing address against the selected payment method at order placement — some payment providers require specific address fields that the billing address endpoint doesn’t enforce. Set payment method first, then billing address, then place the order.
The second common issue is encoding. Country codes must be ISO 3166-1 alpha-2 (GB, US, IN) — full country names will fail. Region handling varies by country: for countries with required regions (US states, Indian states), omitting region_id or providing a non-matching region string will fail at order placement even if the address saves cleanly.
Savan Padaliya
Senior Engineering Consultant