atteq API
  • Guides
  • Recipes
  • Cookbook
  • API Reference
Book an appointment without double-bookingSync a lead to the client's systemPush every call to a webhookGreet callers by nameQuote from a price list
powered by Zudoku
Recipes

Greet callers by name

Requirement

"Greet callers by name when we know them."

Pieces

  • Custom data: a collection customers with phone declared as the identity field, so its get_customers tool looks a customer up by number.
  • The lookup as a pre hook: get_customers on the agent's pre_hook_tool_ids, with its phone parameter fixed to $ref:conversation.number. The hook runs before the first word and its answer is injected as context; the number comes from the conversation, on either leg of a call.
  • Node instructions that say to use the name when the lookup answered.
  • A published agent.

The shape to avoid

The customer list in the prompt. It goes stale the day it changes, it puts every customer's name in front of the model on every call, and the personal data escapes the retention window that a collection's personal fields respect.

Also the in-conversation lookup: the tool on the node and instructions that ask the caller for their number. It works, but it makes the caller say a number the platform already knows, and the greeting cannot use the name because the lookup has not happened yet.

Steps

Ids from an earlier step are written as {{step_N.field}}; the test that runs this page substitutes them.

  1. The customers. Both fields are personal.

    create_collection

    Code
    { "name": "Customers", "slug": "customers", "fields": [ {"key": "phone", "label": "Phone", "type": "text", "required": true, "personal": true}, {"key": "name", "label": "Name", "type": "text", "required": true, "personal": true} ] }
  2. Declare the identity field. It is set once the fields exist, and it is what gives get_customers a phone parameter instead of a record_id. A phone number written to it is stored in E.164, so two spellings of one number are one customer.

    update_collection (collection_id = {{step_1.id}})

    Code
    {"identity_field_key": "phone"}
  3. A customer.

    create_record (collection_id = {{step_1.id}})

    Code
    {"values": {"phone": "+34600000001", "name": "Marta"}}
  4. Fix the lookup's phone to the number the conversation opened with. get_tool_id on the collection is the tool's id. A fixed_parameters value written $ref:conversation.<key> is resolved when the tool runs: an inbound call opens with the caller's number under number (and the dialled one under called_number), an outbound call with the contact's under the same number. The model no longer sees phone at all.

    update_tool (tool_id = {{step_1.get_tool_id}})

    Code
    {"fixed_parameters": {"phone": "$ref:conversation.number"}}
  5. An agent publishes only with an AI profile.

    create_llm_settings

    Code
    {"name": "fast", "provider": "openai", "model": "gpt-4o-mini"}
  6. The profile.

    create_profile

    Code
    {"name": "default", "text": {"llm_settings_id": "{{step_5.id}}"}}
  7. The agent.

    create_agent

    Code
    {"name": "Reception"}
  8. Its draft.

    get_draft (agent_id = {{step_7.id}})

    Code
    {}
  9. The root node. No tool on it: the lookup has already happened by the time the node is reached, and its answer is in the context. The instructions say what to do with it.

    add_node (graph_id = {{step_8.graph_id}})

    Code
    { "instructions": "The context may hold the answer of get_customers. If it holds a record, greet the caller by the name in it and use it from then on. If it holds no record, or nothing at all, greet them without a name and do not guess one." }
  10. Named as the root.

    set_root (graph_id = {{step_8.graph_id}}, node_id = {{step_9.id}})

    Code
    {}
  11. The profile on the draft, and the lookup as the pre hook.

    edit_draft (version_id = {{step_8.id}})

    Code
    {"ai_profile_id": "{{step_6.id}}", "pre_hook_tool_ids": ["{{step_1.get_tool_id}}"]}
  12. Published.

    publish_version (version_id = {{step_8.id}})

    Code
    {}

What the agent sees

No tool. Before the first word, one line of context: get_customers's answer, {"record": {...}} with the name or {"record": null}. The instructions decide what to say with it.

Variations

  • A browser test call opens with no number, so the hook is handed no phone at all and answers that there was nothing to look up by; the agent greets without a name. Test the greeting by calling the published number.
  • Outbound calls from a campaign: the same hook serves, because the contact's number opens the call under number too. The contact's record also travels with the call as context, so a campaign that already knows the name needs no lookup.
  • A returning caller's last order: a second field on the same record, or a second collection orders whose query_orders tool sits on the root node; the instructions say what to mention.
  • Writing a new caller down: attach write_customers (write_tool_id) to the node; it asks the person before it writes, because requires_confirmation is on by default for a collection's write tool.
Last modified on November 4, 2026
Push every call to a webhookQuote from a price list
On this page
  • Requirement
  • Pieces
  • The shape to avoid
  • Steps
  • What the agent sees
  • Variations
JSON
JSON
JSON
JSON
JSON
JSON
JSON
JSON
JSON
JSON
JSON
JSON