Places
Address autocomplete and place details for delivery checkout. Pass a ` sessionToken` through both calls to bill the autocomplete and the resolution as a single session.
Autocomplete an address
sessionToken is camelCase on purpose; the production lens uses #[serde(rename = "sessionToken")]. The SDK forwards your value verbatim.
const sessionToken = crypto.randomUUID()
const r = await client.places.autocomplete('cantonments accra', sessionToken)
if (!r.ok) {
console.error(r.error.code, r.error.message)
return
}
for (const prediction of r.value.predictions) {
console.log(prediction.place_id, prediction.description)
}Resolve a place
Pass the same sessionToken you used for the autocomplete request that produced this place_id; the server bills the pair as one session.
const r = await client.places.details('place_id_xyz', sessionToken)
if (!r.ok) return
const place = r.value
console.log(place.formatted_address)
console.log(place.street_address, place.city, place.region, place.country)
console.log(place.latitude, place.longitude)React: an autocomplete input
'use client'
import { useEffect, useState, useRef } from 'react'
import { useCimplifyClient } from '@cimplify/sdk/react'
import type { AutocompletePrediction, PlaceDetailsResponse } from '@cimplify/sdk'
export function AddressInput({ onChange }: { onChange: (place: PlaceDetailsResponse) => void }) {
const client = useCimplifyClient()
const sessionToken = useRef(crypto.randomUUID()).current
const [query, setQuery] = useState('')
const [predictions, setPredictions] = useState<AutocompletePrediction[]>([])
useEffect(() => {
if (!query) return setPredictions([])
const id = setTimeout(async () => {
const r = await client.places.autocomplete(query, sessionToken)
if (r.ok) setPredictions(r.value.predictions)
}, 200)
return () => clearTimeout(id)
}, [query, client, sessionToken])
async function pick(prediction: AutocompletePrediction) {
const r = await client.places.details(prediction.place_id, sessionToken)
if (r.ok) onChange(r.value)
}
return (
<>
<input value={query} onChange={(e) => setQuery(e.target.value)} placeholder="Address" />
<ul>
{predictions.map((p) => (
<li key={p.place_id} onClick={() => pick(p)}>{p.description}</li>
))}
</ul>
</>
)
}PlaceDetailsResponse shape
| Field | Type | Notes |
|---|---|---|
place_id | string | Provider id |
formatted_address | string | Display-ready single line |
street_address | string? | Number + street |
apartment | string? | Unit / suite |
city | string? | |
region | string? | State / province |
postal_code | string? | |
country | string? | ISO-3 code |
latitude | number | |
longitude | number |
Method reference
| Method | Returns |
|---|---|
autocomplete(input, sessionToken?) | Result<AutocompleteResponse> |
details(placeId, sessionToken?) | Result<PlaceDetailsResponse> |
Related
-
Checkout Resolved address feeds
address_info -
Cart Delivery fees recompute when address changes
-
Error handling RATE_LIMITED is common; debounce input
-
Auth Saved addresses live on the customer profile
FX
Spot rates and locked quotes for cross-currency checkout. `checkout.process` will lock a quote for you automatically when `pay_currency` differs from the cart currency; call `fx.lockQuote` directly only when you need the rate ahead of time (e.g. to display "Pay in USD" before the customer commits).
Uploads
Three-step direct-to-storage upload: `init` hands you a presigned URL, ` PUT` the bytes, then `confirm` commits the upload. `upload(file)` is the one-call sugar that runs the whole sequence for you.