This guide defines a search_listings function that the OpenAI models can call,
backed by Trawley's hybrid search endpoint.
bash
npm install openai
Define the function
ts
const tools = [
{
type: 'function',
function: {
name: 'search_listings',
description:
'Search live property listings from acmehomes.co.uk. Accepts a natural ' +
'language query; constraints like price, bedrooms, or date are understood.',
parameters: {
type: 'object',
properties: {
query: {
type: 'string',
description: 'What to find, e.g. "3 bed houses under £500k with a garden"',
},
},
required: ['query'],
},
},
},
] as const
const TRAWLEY_SCRAPER_ID = 'scr_8f2a1c9e'
async function runSearch(query: string) {
const params = new URLSearchParams({ search: query, take: '10' })
const res = await fetch(
`https://api.trawley.ai/v1/scrapers/${TRAWLEY_SCRAPER_ID}/hybrid?${params}`,
)
const { data } = await res.json()
return data
}
Run the call loop
ts
import OpenAI from 'openai'
const client = new OpenAI()
const messages: OpenAI.ChatCompletionMessageParam[] = [
{ role: 'user', content: 'Find a 3 bed house near Kendal with a garden under £500k.' },
]
while (true) {
const completion = await client.chat.completions.create({
model: 'gpt-4.1',
messages,
tools,
})
const message = completion.choices[0].message
messages.push(message)
if (!message.tool_calls?.length) {
console.log(message.content)
break
}
for (const call of message.tool_calls) {
const { query } = JSON.parse(call.function.arguments)
const results = await runSearch(query)
messages.push({
role: 'tool',
tool_call_id: call.id,
content: JSON.stringify(results),
})
}
}
After running a function, push a role: 'tool' message with the matching
tool_call_id. The model reads the result and continues until it can answer in
plain text.