How to Validate Adobe Commerce (Magento 2) Shipping Addresses with the Google Address Validation API

Check every new Adobe Commerce (Magento 2) order's shipping address against the Google Address Validation API, and hold orders whose address needs fixing before they reach the warehouse.

What This Integration Does

You can validate Magento 2 addresses without installing a checkout extension: a Spojit workflow reads new orders through the Adobe Commerce REST API, sends each shipping address to Google's Address Validation API, and acts on Google's verdict. Orders with a deliverable address carry on as normal. Orders with a missing unit number, a wrong postcode or a street Google cannot find get a private order comment explaining the problem and are put on hold, so nobody prints a label for a parcel that will come back. Because the check runs on the server after the order is placed, it works the same for the Luma checkout, a one-page checkout extension, a PWA or a headless storefront, and it never slows the checkout down.

The workflow runs on a schedule, every 15 minutes by default. Each run fetches orders created since the previous run, validates them one at a time, and leaves a record on the order itself (a comment, and a hold where needed). Re-running is safe: the workflow skips orders that already carry its comment, so an overlapping window never validates the same order twice.

Prerequisites

  • An Adobe Commerce (REST) connection in Spojit using an integration access token with access to Sales (orders, comments, hold).
  • A Google Cloud project with the Address Validation API enabled and billing turned on, plus an API key. Restrict the key to the Address Validation API in APIs & Services -> Credentials.
  • Google's coverage list for your shipping countries. The API supports many regions but not all, and the depth of checking varies by country; check Google's coverage page before relying on it for a market.
  • Optional: a Slack connection for a daily summary of held orders.

Step 1: Schedule Trigger

Add a Trigger node and set its type to Schedule. Use */15 * * * * with your store's timezone (for example Australia/Sydney). Fifteen minutes is quick enough to catch an order before the warehouse picks it and cheap enough to stay well inside Google's quotas.

Step 2: List New Orders

Add a Connector node on the Adobe Commerce REST connector in Direct Mode and pick the list-orders tool. Set:

  • status: pending (or processing, if payment capture moves orders straight on).
  • createdAfter: a time slightly earlier than the last run, in YYYY-MM-DD HH:MM:SS. Use the Date & Time connector's subtract tool on the trigger time to subtract 20 minutes, then format it. The five minutes of overlap mean no order falls between two runs.
  • pageSize: 100.

Set the Output Variable to orders. Each order includes extension_attributes.shipping_assignments[0].shipping.address, which holds the shipping address with street (an array of lines), city, region, postcode and country_id.

Step 3: Loop Over Each Order and Build the Request

Add a Loop node in ForEach mode over {{ orders.data.items }}, with the item variable order. Set On iteration error to Continue with the next item so one bad address never blocks the rest of the batch.

Inside the loop, add a Transform node in Structured mode that builds Google's request body. Name its output gav_request:

{
  "address": {
    "regionCode": "{{ order.extension_attributes.shipping_assignments.0.shipping.address.country_id }}",
    "addressLines": {{ order.extension_attributes.shipping_assignments.0.shipping.address.street }},
    "locality": "{{ order.extension_attributes.shipping_assignments.0.shipping.address.city }}",
    "administrativeArea": "{{ order.extension_attributes.shipping_assignments.0.shipping.address.region }}",
    "postalCode": "{{ order.extension_attributes.shipping_assignments.0.shipping.address.postcode }}"
  }
}

Magento stores the street as an array, which maps straight onto Google's addressLines. Magento's country_id is already a two-letter code, which is what regionCode expects.

Step 4: Call the Google Address Validation API

Add a Connector node on the HTTP Requests connector and pick http-post. Set:

  • url: https://addressvalidation.googleapis.com/v1:validateAddress
  • headers: { "Content-Type": "application/json", "X-Goog-Api-Key": "YOUR_API_KEY" }
  • body: {{ gav_request }}

Name the output validation. Google's answer is in {{ validation.data.result }}. The part to act on is verdict:

  • verdict.possibleNextAction: Google's own recommendation, one of ACCEPT, CONFIRM, CONFIRM_ADD_SUBPREMISES or FIX. This field is marked preview by Google, so treat it as a strong hint rather than a contract.
  • verdict.addressComplete: false when a component is missing, unresolved or unexpected.
  • verdict.validationGranularity: how precisely the address was matched, such as PREMISE or SUB_PREMISE for a real building, or ROUTE when only the street was found.

Google also returns address.formattedAddress, the corrected version, which is useful in the order comment.

Step 5: Decide and Act on the Order

Add a Condition node that passes when {{ validation.data.result.verdict.possibleNextAction }} equals ACCEPT. On the true branch, do nothing (or add an "Address verified" comment if your team likes the audit trail).

On the false branch, add two Connector nodes on Adobe Commerce REST, both using the raw-rest-request tool:

  1. Add a private comment. method POST, path orders/{{ order.entity_id }}/comments, body:
    {
      "statusHistory": {
        "comment": "Address check: {{ validation.data.result.verdict.possibleNextAction }}. Google suggests: {{ validation.data.result.address.formattedAddress }}",
        "is_customer_notified": 0,
        "is_visible_on_front": 0
      }
    }
  2. Put the order on hold. method POST, path orders/{{ order.entity_id }}/hold, no body.

Holding the order stops invoicing and shipping until someone releases it, which is exactly the safety net you want. Your customer service team fixes the address with the customer and clicks Unhold in the Magento admin.

Step 6: Optional Daily Summary

To give the team one list instead of scattered comments, add a second small workflow on a 0 9 * * * schedule that calls list-orders with status holded and posts the order numbers to a channel with the Slack connector's send-message tool.

Tips

  • Treat CONFIRM differently from FIX. A CONFIRM verdict usually means Google corrected something small, such as a postcode, that a person should glance at. If holding those orders is too strict for you, add a comment without the hold for CONFIRM and hold only FIX and CONFIRM_ADD_SUBPREMISES.
  • Apartments and units: CONFIRM_ADD_SUBPREMISES means the building exists but it needs a unit or apartment number. These are the parcels that most often come back, so hold them.
  • United States orders: add "enableUspsCass": true next to address in the request to get USPS CASS standardisation. Google only recommends it for US and Puerto Rico addresses.
  • Agent Mode alternative: if you would rather write the rules in plain English ("hold anything a courier would struggle to deliver"), replace the Condition with a Connector node in Agent Mode and a Response Schema with action and reason fields.

Common Pitfalls

  • Billing: every call is billed by Google to your Cloud project. Validating each order once, as this workflow does, keeps the cost predictable; validating on every address edit can multiply it.
  • Key in the workflow: the API key sits in the HTTP step's headers, so restrict it to the Address Validation API in Google Cloud and rotate it if a workflow export is ever shared.
  • Virtual orders: downloadable and virtual products have no shipping assignment. Add a Condition before Step 3 that skips orders without shipping_assignments, or the Transform renders empty fields.
  • Region names: Magento's region is the full name (for example "New South Wales"). Google accepts full names, but if you see weak matches, leave administrativeArea out and let the postcode and locality do the work.

Testing

Place two test orders in a staging store: one to a real address and one with a deliberately wrong postcode or a missing unit number. Run the workflow manually and confirm the first stays pending with no hold and the second has the comment and is on hold. Then switch the schedule on.

Learn More

Ready to build this?

Start on the free plan: 500 AI credits a month, no card needed.

Start free

Did this answer your question? Thanks for the feedback There was a problem submitting your feedback. Please try again later.