All posts

Flow agents

Confirming a payment while the customer is still on the call

Your systems learn things during a call that the caller never says out loud. Send them into the live call as events, and the agent reacts at once, without talking over anyone.

The Graine team

5 min read

Picture a collections or renewal call that goes well. The customer agrees to pay, the agent sends a payment link by text message, and the customer opens it while still on the line. Now what?

Without a way to hear from your systems, the agent can only guess. It asks "has it gone through?", the customer says "I think so", and the call ends without anyone being sure.

Yet your payment provider knows within seconds whether the payment succeeded, and your server hears about it. What was missing is a way to put that fact into the conversation the moment it becomes true. That is what live call events do.

What an event is

An event is a short message your server sends into a call that is happening right now. It has a name, such as payment_completed, and optionally some data, such as the amount and a receipt number.

Events work with flow agents, which are built as steps joined by paths. Most paths are taken because of something the caller said. An event path is taken because of something your own system saw. When the call is on a step that has a path waiting for that event's name, the call takes it, and the step it lands on speaks straight away. The caller does not have to say anything first.

Caller            Your server                      The call
------            -----------                      --------
opens the link                                     on "Wait for the payment"
pays              hears from the payment provider
                  sends payment_completed    --->  picks it up within about a second
                                                   waits for the agent to finish speaking
                                                   moves to "Confirm the payment"
hears the                                          plays the fixed line at once,
confirmation                                       then hangs up

Sending one

Send the event from your own server with an API key that can place calls. The execution_id is the id the call was placed under, the one you got back when you created it.

curl -X POST "https://api.graine.ai/v2/calls/$EXECUTION_ID/events" \
  -H "Authorization: Bearer $GRAINE_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name": "payment_completed", "data": {"amount_paid": "2,450.00", "receipt_id": "RCPT-20931"}}'

The answer is 202 Accepted, which means the event was queued for the call. It does not promise that a path was taken; that depends on the step the call is on when the event arrives. If the call is not live, because it has not connected yet or has already ended, the answer says so, and when it is still connecting it tells you how long to wait before sending again.

A few limits keep events predictable: the name is up to 64 characters, the data is a JSON object of up to 8 KB, and events for one call are handled one at a time, in the order they arrive.

What the call does with it

  1. It picks the event up within about a second, then waits until the agent is neither speaking nor working on a reply, for up to 30 seconds. An event never interrupts the agent mid-sentence.
  2. The data becomes part of the call. Each value joins the call's fields under the name you sent, so a later step can say it ({amount_paid}) and a rule can test it. The event's name is kept too.
  3. If the current step has an event path for that name, the call takes it and the next step speaks first, without waiting for the caller. If the caller happens to be talking at that moment, the call still moves, and the new step answers what they said instead.
  4. If there is no such path, nothing is said. The data is still added, ready for later steps.

The transcript stays honest throughout. An event never puts words in the caller's mouth: it shows as the agent's next turn, straight after its previous one.

A worked example: waiting for a payment

Here is the shape of a payment call, as an example. Four steps matter.

  • Wait for the payment is an AI reply. The agent explains that a link has been sent, stays on the line, and answers questions about the amount while the customer pays. Nothing the customer says moves the call on, except a rule that offers another way after a few turns.
  • Confirm the payment is a fixed line that hangs up after it plays.
  • Payment failed is an AI reply that explains what happened and offers to try again.
  • Pay later agrees a date and ends the call politely.

The waiting step carries two event paths, one for each outcome:

The waiting step and the confirmation
{
  "await_payment": {
    "kind": "converse",
    "title": "Wait for the payment",
    "instructions": "Tell {first_name} you have sent a payment link by text message. Stay on the line while they pay, and answer questions about the amount due.",
    "next": [
      { "to": "confirmed", "label": "Paid", "when": { "type": "event", "event": "payment_completed" } },
      { "to": "failed", "label": "Payment failed", "when": { "type": "event", "event": "payment_failed" } },
      { "to": "pay_later", "label": "Taking a while",
        "when": { "type": "rule", "match": "all", "rules": [{ "field": "_step_turns", "op": "at_least", "value": 6 }] } }
    ]
  },
  "confirmed": {
    "kind": "say",
    "title": "Confirm the payment",
    "say": { "en": "Thank you, your payment has come through and a receipt is on its way. Have a good day!" },
    "force_tool": "end_call",
    "next": []
  }
}

When your server sends payment_completed, the call moves to Confirm the payment. If it sends payment_failed with a reason in its data, say {"failure_reason": "the card was declined"}, the call moves to Payment failed, whose instructions can use {failure_reason} to explain it in plain words. That step can wait for payment_completed too, so a second attempt that succeeds is confirmed the same way.

Why the confirmation is a fixed line

A fixed line is a step whose words never change. No model writes it, and its audio is prepared when you save the flow, in every language the agent speaks. On the call, it starts playing the moment the step is reached.

That matters here for two reasons. Speed: the customer hears the confirmation as soon as the payment lands, with no pause while a reply is written. Certainty: the words are exactly what your compliance team approved, every time.

One detail to plan for: a line that contains a variable, such as the amount, is spoken live instead, because its words change from call to call. It sounds the same and starts a moment later. If an instant start matters most, keep the variable for the step after.

Other moments that suit events

The same pattern fits whenever the caller is waiting on something outside the call:

  • a slot booked on a web page while the agent stays on the line;
  • an identity check or a document upload finishing in your app;
  • a colleague picking up a case, so the agent can say who will call back;
  • an order or delivery status changing during a support call.

In each case, your system already knows. Events let the conversation know too.

Getting started

Event paths are added in the flow's raw settings or through the flow API, and they show on the canvas like any other path. To try one, place a call through the API, keep the execution_id, and send an event from a terminal while you are on the line.

If you are designing a call that depends on something happening elsewhere, a payment, a booking or a verification, write to us at hello@graine.ai and we will help you shape the flow, or create an account and build it yourself.

Put it to work on your calls.

Tell us what your calls and your app need to do, and we'll show you how it runs on Graine. Or start building with your own account today.

Events in the flow agent docs