Timers serve as a way to trigger an action after a certain amount of time has elapsed, without requiring a button press or other external activity. In this section, we will discuss how to use timers.


URN Type for Timers

Because a timer is held on the Relay server and not on a device, there is no target parameter to the timer methods, thus no URN parameter is needed.

Triggering an Action with a Timer

When creating a workflow, you can use timers to start actions or other logic after a certain amount of time has passed. For example, the following shows a workflow where a 10 second timer is used. Once the 10 seconds have elapsed the timer says to the user "Timer fired" and the workflow terminates. Note the handler for the TIMER_FIRED event:

import { relay, Event, createWorkflow } from '@relaypro/sdk'

const app = relay()

const timerWorkflow = createWorkflow(workflow => {
  const interactionName = 'timer interaction'
  workflow.on(Event.START, async(event) =>{
    const { trigger: { args: { source_uri } } } = event
    await workflow.startInteraction(source_uri, interactionName);

  workflow.on(Event.INTERACTION_STARTED, async({source_uri: interaction_uri}) => {
    await workflow.say(interaction_uri, "Starting timer")
    await workflow.setVar("interaction_uri", interaction_uri);
    await workflow.setTimer(TimerType.TIMEOUT, "Timer", 10, TimeoutType.SECONDS)

  workflow.on(Event.TIMER_FIRED, async() => {
    workflow.say(await workflow.getVar("interaction_uri"), "Timer fired");
    await workflow.endInteraction(await workflow.getVar("interaction_uri"));

  workflow.on(Event.INTERACTION_ENDED, async() => {
    await workflow.terminate();

app.workflow(`timerpath`, timerWorkflow)
async def start_handler(workflow, trigger):
  target = workflow.make_target_uris(trigger)
  await workflow.start_interaction(target, 'timer')

async def lifecycle_handler(workflow, itype, interaction_uri, reason):
  if itype == relay.workflow.TYPE_STARTED:
    await workflow.say(interaction_uri, 'Starting timer')
    await workflow.set_var('interaction_uri', interaction_uri)
    await workflow.set_timer("timer", "timeout", 10, "secs")
  if itype == relay.workflow.TYPE_ENDED:
    await relay.terminate()

async def timer_handler(workflow, timerEvent):
  await workflow.say_and_wait(await workflow.get_var("interaction_uri"), "Timer fired")
  await workflow.end_interaction(await workflow.get_var("interaction_uri"))
public override async void OnStart(IDictionary<string, object> dictionary)
  var trigger = (Dictionary<string, object>) dictionary["trigger"];
  var triggerArgs = (Dictionary<string, object>) trigger["args"];
  var target = (string) triggerArgs["source_uri"];

  Relay.StartInteraction(this, target, "timer", new Dictionary<string, object>());

public override async void OnInteractionLifecycle(IDictionary<string, object> dictionary)
  var type = (string) dictionary["type"];

  if (type == InteractionLifecycleType.Started)
    var interactionUri = (string) dictionary["source_uri"];
    await Relay.Say(this, sourceUri, "Starting timer");
    await Relay.SetVar(this, "interactionUri", sourceUri);
    await Relay.SetTimer(this, "Timer", "timeout", 10, "secs");
  else if (type == InteractionLifecycleType.Ended)

public override async void OnTimerFired(IDictionary<string, object> dictionary)
  await Relay.Say(this, await Relay.GetVar("interactionUri"), "Timer fired");
  await Relay.EndInteraction(this, await Relay.GetVar("interactionUri"));
public void onStart(Relay relay, StartEvent startEvent) {
  super.onStart(relay, startEvent);
  String sourceUri = Relay.getSourceUri(startEvent);

  relay.startInteraction(sourceUri, "timer", null);

public void onInteractionLifecycle(Relay relay, InteractionLifecycleEvent lifecycleEvent) {
  super.onInteractionLifecycle(relay, lifecycleEvent);
  String interactionUri = lifecycleEvent.sourceUri;

  if (lifecycleEvent.isTypeStarted()) {
    relay.say(interactionUri, "Starting timer");
    relay.setVar("interactionUri", interactionUri);
    relay.setTimer(TimerType.TIMEOUT, "Timer", 10, TimeoutType.SECS);
  if (lifecycleEvent.isTypeEnded()) {

public void onTimerFired(Relay relay, TimerFiredEvent timerFiredEvent) {
  relay.say(relay.getVar("interactionUri", ""), "Timer Fired");
  relay.endInteraction(relay.getVar("interactionUri", ""));
api.OnStart(func(startEvent sdk.StartEvent) {
  sourceUri := api.GetSourceUri(startEvent)
  api.StartInteraction(sourceUri, "timer")

api.OnInteractionLifecycle(func(interactionLifecycleEvent sdk.InteractionLifecycleEvent) {
  interactionUri := interactionLifecycleEvent.SourceUri

  if interactionLifecycleEvent.LifecycleType == "started" {
    api.Say(interactionUri, "Starting timer", sdk.ENGLISH)
    api.SetVar("interactionUri", interactionUri)
    api.SetTimer(sdk.TIMEOUT_TIMER_TYPE, "Timer", 10, sdk.SECS_TIMEOUT_TYPE)

  if interactionLifecycleEvent.LifecycleType == "ended" {

api.OnTimerFired(func(timerFiredEvent sdk.TimerFiredEvent) {
  api.Say(api.GetVar("interactionUri", ""), "Timer Fired", sdk.ENGLISH)
  api.EndInteraction(api.GetVar("interactionUri", ""))

In the above example, we use the setTimer() function to start our timer. setTimer() takes in the type, name, timeout, and timeout type as parameters. The type is whether you would like the timer to be an interval timer or a timeout timer. The name is a unique string that you would like to name your timer. The timeout is a number and the timeout type is the time that you would like the timeout number to represent: hours, milliseconds, minutes, or seconds. In the above example, we are creating a timeout timer with the name "Timer" that will fire after 10 seconds.

Other Functions for Timers

The SDK also includes a method for cancelling a timer before it fires: clearTimer takes the name of the timer that you would like to reset and clears that timer.