# States and Timers in Conversations

States and Timers help automatically manage the lifecycle of your application's conversations. They keep your users focused on ongoing *active* conversations, while closing out older *inactive* conversations to make sure you're not exceeding the [Conversations per user limit](/docs/conversations/conversations-limits#maximum-channelsconversations-per-identity) of 1,000.

A conversation's state indicates whether a conversation is active, inactive, or closed. You can use timers to automatically transition conversations across these states. Both `state` and `timers` are properties of the [Conversation Resource](/docs/conversations/api/conversation-resource#conversation-properties).

This guide provides an overview of states and timers and how to configure them.

## Conversation States

A Conversation can be one of four states:

* `active`: The conversation is currently in use. This is the default state for a newly created conversation.
* `inactive`: The conversation is not in use, but you can reactivate it if needed.
* `closed`: The conversation is no longer in use and you can't reactivate it.
* `initializing`: Twilio is setting up the conversation and you can't edit it yet. This state is only used shortly when a conversation is created through the [ConversationsWithParticipants](/docs/conversations/api/conversation-with-participants-resource) resource.

Update a Conversation's state

```js
// Download the helper library from https://www.twilio.com/docs/node/install
const twilio = require("twilio"); // Or, for ESM: import twilio from "twilio";

// Find your Account SID and Auth Token at twilio.com/console
// and set the environment variables. See http://twil.io/secure
const accountSid = process.env.TWILIO_ACCOUNT_SID;
const authToken = process.env.TWILIO_AUTH_TOKEN;
const client = twilio(accountSid, authToken);

async function updateConversation() {
  const conversation = await client.conversations.v1
    .conversations("CHXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX")
    .update({ state: "inactive" });

  console.log(conversation.accountSid);
}

updateConversation();
```

```python
# Download the helper library from https://www.twilio.com/docs/python/install
import os
from twilio.rest import Client

# Find your Account SID and Auth Token at twilio.com/console
# and set the environment variables. See http://twil.io/secure
account_sid = os.environ["TWILIO_ACCOUNT_SID"]
auth_token = os.environ["TWILIO_AUTH_TOKEN"]
client = Client(account_sid, auth_token)

conversation = client.conversations.v1.conversations(
    "CHXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
).update(state="inactive")

print(conversation.account_sid)
```

```csharp
// Install the C# / .NET helper library from twilio.com/docs/csharp/install

using System;
using Twilio;
using Twilio.Rest.Conversations.V1;
using System.Threading.Tasks;

class Program {
    public static async Task Main(string[] args) {
        // Find your Account SID and Auth Token at twilio.com/console
        // and set the environment variables. See http://twil.io/secure
        string accountSid = Environment.GetEnvironmentVariable("TWILIO_ACCOUNT_SID");
        string authToken = Environment.GetEnvironmentVariable("TWILIO_AUTH_TOKEN");

        TwilioClient.Init(accountSid, authToken);

        var conversation = await ConversationResource.UpdateAsync(
            state: ConversationResource.StateEnum.Inactive,
            pathSid: "CHXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");

        Console.WriteLine(conversation.AccountSid);
    }
}
```

```java
// Install the Java helper library from twilio.com/docs/java/install

import com.twilio.Twilio;
import com.twilio.rest.conversations.v1.Conversation;

public class Example {
    // Find your Account SID and Auth Token at twilio.com/console
    // and set the environment variables. See http://twil.io/secure
    public static final String ACCOUNT_SID = System.getenv("TWILIO_ACCOUNT_SID");
    public static final String AUTH_TOKEN = System.getenv("TWILIO_AUTH_TOKEN");

    public static void main(String[] args) {
        Twilio.init(ACCOUNT_SID, AUTH_TOKEN);
        Conversation conversation =
            Conversation.updater("CHXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX").setState(Conversation.State.INACTIVE).update();

        System.out.println(conversation.getAccountSid());
    }
}
```

```go
// Download the helper library from https://www.twilio.com/docs/go/install
package main

import (
	"fmt"
	"github.com/twilio/twilio-go"
	conversations "github.com/twilio/twilio-go/rest/conversations/v1"
	"os"
)

func main() {
	// Find your Account SID and Auth Token at twilio.com/console
	// and set the environment variables. See http://twil.io/secure
	// Make sure TWILIO_ACCOUNT_SID and TWILIO_AUTH_TOKEN exists in your environment
	client := twilio.NewRestClient()

	params := &conversations.UpdateConversationParams{}
	params.SetState("inactive")

	resp, err := client.ConversationsV1.UpdateConversation("CHXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
		params)
	if err != nil {
		fmt.Println(err.Error())
		os.Exit(1)
	} else {
		if resp.AccountSid != nil {
			fmt.Println(*resp.AccountSid)
		} else {
			fmt.Println(resp.AccountSid)
		}
	}
}
```

```php
<?php

// Update the path below to your autoload.php,
// see https://getcomposer.org/doc/01-basic-usage.md
require_once "/path/to/vendor/autoload.php";

use Twilio\Rest\Client;

// Find your Account SID and Auth Token at twilio.com/console
// and set the environment variables. See http://twil.io/secure
$sid = getenv("TWILIO_ACCOUNT_SID");
$token = getenv("TWILIO_AUTH_TOKEN");
$twilio = new Client($sid, $token);

$conversation = $twilio->conversations->v1
    ->conversations("CHXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX")
    ->update(["state" => "inactive"]);

print $conversation->accountSid;
```

```ruby
# Download the helper library from https://www.twilio.com/docs/ruby/install
require 'twilio-ruby'

# Find your Account SID and Auth Token at twilio.com/console
# and set the environment variables. See http://twil.io/secure
account_sid = ENV['TWILIO_ACCOUNT_SID']
auth_token = ENV['TWILIO_AUTH_TOKEN']
@client = Twilio::REST::Client.new(account_sid, auth_token)

conversation = @client
               .conversations
               .v1
               .conversations('CHXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX')
               .update(state: 'inactive')

puts conversation.account_sid
```

```bash
# Install the twilio-cli from https://twil.io/cli

twilio api:conversations:v1:conversations:update \
   --sid CHXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX \
   --state inactive
```

```bash
curl -X POST "https://conversations.twilio.com/v1/Conversations/CHXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" \
--data-urlencode "State=inactive" \
-u $TWILIO_ACCOUNT_SID:$TWILIO_AUTH_TOKEN
```

```json
{
  "sid": "CHXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
  "account_sid": "ACaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
  "chat_service_sid": "ISaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
  "messaging_service_sid": "MGaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab",
  "friendly_name": "friendly_name",
  "unique_name": "unique_name",
  "attributes": "{ \"topic\": \"feedback\" }",
  "date_created": "2015-12-16T22:18:37Z",
  "date_updated": "2015-12-16T22:18:38Z",
  "state": "inactive",
  "timers": {
    "date_inactive": "2015-12-16T22:19:38Z",
    "date_closed": "2015-12-16T22:28:38Z"
  },
  "bindings": {},
  "url": "https://conversations.twilio.com/v1/Conversations/CHaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
  "links": {
    "participants": "https://conversations.twilio.com/v1/Conversations/CHaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/Participants",
    "messages": "https://conversations.twilio.com/v1/Conversations/CHaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/Messages",
    "webhooks": "https://conversations.twilio.com/v1/Conversations/CHaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/Webhooks",
    "export": "https://conversations.twilio.com/v1/Conversations/CHaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/Export"
  }
}
```

### State Transition Table

A conversation can be transitioned between these states by updating the conversation directly, by a configured timer, and automatically by the system. The following table summarizes the possible transitions:

| From State     | To State   | Behavior                                                                                                                                               |
| -------------- | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `active`       | `inactive` | Transitioned by timer or API.                                                                                                                          |
| `active`       | `closed`   | Transitioned by timer or API.                                                                                                                          |
| `inactive`     | `active`   | Automatically transitioned when a new message is added to the conversation, or by API.                                                                 |
| `inactive`     | `closed`   | Transitioned by timer or API.                                                                                                                          |
| `closed`       | N/A        | Closed state is final.                                                                                                                                 |
| `initializing` | `active`   | Automatically transitioned when the [ConversationsWithParticipants](/docs/conversations/api/conversation-with-participants-resource) process finishes. |
| `initializing` | `closed`   | Automatically transitioned the if conversation with participants process fails.                                                                        |

### Active and Inactive Conversations

A conversation can be set from active to inactive and vice versa at any time.

As described in the [State Transition Table](#state-transition-table):

* A conversation can only be transitioned to inactive by using a configured timer or by making an API call.
* A conversation is automatically transitioned from inactive to active when a new message is added to the conversation.

> \[!NOTE]
>
> Active and inactive conversations both count towards the [Conversations per User limit](/docs/conversations/conversations-limits#maximum-channelsconversations-per-identity).

### Closed Conversations

Once a conversation closes, it becomes read-only and you can't add new participants or messages to it.
Closing a conversation is permanent, and you can't transition it back to the `active` or `inactive` state.

Closed conversations don't count towards the [Conversations per user limit](/docs/conversations/conversations-limits#maximum-channelsconversations-per-identity).

## Conversations Timers

Timers allow you to set a timeframe of inactivity after which a conversation automatically transitions between states. Timers are optional, but we highly recommend enabling them to manage conversations efficiently and avoid distruptions from the [Conversations per user limit](/docs/conversations/conversations-limits#maximum-channelsconversations-per-identity).

You can set up timers in two ways:

1. **Global Defaults**: Set up default timers for all conversations created in your account. You can set up global defaults from the Conversations Defaults page in the
   Twilio Console.
2. **For Each Conversation**: Set up a timer for a specific Conversation using the REST API.

There are two configurable timers to transition between conversation states:

* **Inactive Timer**: Transitions a conversation from active to inactive. It counts down from when the last message added was in the conversation.
* **Closed Timer**: Transitions a conversation to closed.
  * If it's the only timer, it counts down from when the last message was added in the conversation.
  * If there is also an inactive timer, it counts down from when the conversation becomes inactive.

Timers are set in [ISO 8601 duration](https://en.wikipedia.org/wiki/ISO_8601#Durations) format (`PT10M` for 10 minutes).

> \[!NOTE]
>
> **Note**: When configuring timers, durations must be specified in days or smaller units (hours, minutes, seconds).
> Using months `P6M` or years `P1Y` will result in an invalid format error. For instance, to set a timer for 6 months,
> use `P180D` (assuming an average month has 30 days), and for 1 year, use `P365D`

Configure timers for a Conversation

```js
// Download the helper library from https://www.twilio.com/docs/node/install
const twilio = require("twilio"); // Or, for ESM: import twilio from "twilio";

// Find your Account SID and Auth Token at twilio.com/console
// and set the environment variables. See http://twil.io/secure
const accountSid = process.env.TWILIO_ACCOUNT_SID;
const authToken = process.env.TWILIO_AUTH_TOKEN;
const client = twilio(accountSid, authToken);

async function updateConversation() {
  const conversation = await client.conversations.v1
    .conversations("CHXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX")
    .update({
      "timers.closed": "PT60000S",
      "timers.inactive": "PT5M",
    });

  console.log(conversation.accountSid);
}

updateConversation();
```

```python
# Download the helper library from https://www.twilio.com/docs/python/install
import os
from twilio.rest import Client

# Find your Account SID and Auth Token at twilio.com/console
# and set the environment variables. See http://twil.io/secure
account_sid = os.environ["TWILIO_ACCOUNT_SID"]
auth_token = os.environ["TWILIO_AUTH_TOKEN"]
client = Client(account_sid, auth_token)

conversation = client.conversations.v1.conversations(
    "CHXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
).update(timers_inactive="PT5M", timers_closed="PT60000S")

print(conversation.account_sid)
```

```csharp
// Install the C# / .NET helper library from twilio.com/docs/csharp/install

using System;
using Twilio;
using Twilio.Rest.Conversations.V1;
using System.Threading.Tasks;

class Program {
    public static async Task Main(string[] args) {
        // Find your Account SID and Auth Token at twilio.com/console
        // and set the environment variables. See http://twil.io/secure
        string accountSid = Environment.GetEnvironmentVariable("TWILIO_ACCOUNT_SID");
        string authToken = Environment.GetEnvironmentVariable("TWILIO_AUTH_TOKEN");

        TwilioClient.Init(accountSid, authToken);

        var conversation = await ConversationResource.UpdateAsync(
            timersInactive: "PT5M",
            timersClosed: "PT60000S",
            pathSid: "CHXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");

        Console.WriteLine(conversation.AccountSid);
    }
}
```

```java
// Install the Java helper library from twilio.com/docs/java/install

import com.twilio.Twilio;
import com.twilio.rest.conversations.v1.Conversation;

public class Example {
    // Find your Account SID and Auth Token at twilio.com/console
    // and set the environment variables. See http://twil.io/secure
    public static final String ACCOUNT_SID = System.getenv("TWILIO_ACCOUNT_SID");
    public static final String AUTH_TOKEN = System.getenv("TWILIO_AUTH_TOKEN");

    public static void main(String[] args) {
        Twilio.init(ACCOUNT_SID, AUTH_TOKEN);
        Conversation conversation = Conversation.updater("CHXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX")
                                        .setTimersInactive("PT5M")
                                        .setTimersClosed("PT60000S")
                                        .update();

        System.out.println(conversation.getAccountSid());
    }
}
```

```go
// Download the helper library from https://www.twilio.com/docs/go/install
package main

import (
	"fmt"
	"github.com/twilio/twilio-go"
	conversations "github.com/twilio/twilio-go/rest/conversations/v1"
	"os"
)

func main() {
	// Find your Account SID and Auth Token at twilio.com/console
	// and set the environment variables. See http://twil.io/secure
	// Make sure TWILIO_ACCOUNT_SID and TWILIO_AUTH_TOKEN exists in your environment
	client := twilio.NewRestClient()

	params := &conversations.UpdateConversationParams{}
	params.SetTimersInactive("PT5M")
	params.SetTimersClosed("PT60000S")

	resp, err := client.ConversationsV1.UpdateConversation("CHXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
		params)
	if err != nil {
		fmt.Println(err.Error())
		os.Exit(1)
	} else {
		if resp.AccountSid != nil {
			fmt.Println(*resp.AccountSid)
		} else {
			fmt.Println(resp.AccountSid)
		}
	}
}
```

```php
<?php

// Update the path below to your autoload.php,
// see https://getcomposer.org/doc/01-basic-usage.md
require_once "/path/to/vendor/autoload.php";

use Twilio\Rest\Client;

// Find your Account SID and Auth Token at twilio.com/console
// and set the environment variables. See http://twil.io/secure
$sid = getenv("TWILIO_ACCOUNT_SID");
$token = getenv("TWILIO_AUTH_TOKEN");
$twilio = new Client($sid, $token);

$conversation = $twilio->conversations->v1
    ->conversations("CHXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX")
    ->update([
        "timersInactive" => "PT5M",
        "timersClosed" => "PT60000S",
    ]);

print $conversation->accountSid;
```

```ruby
# Download the helper library from https://www.twilio.com/docs/ruby/install
require 'twilio-ruby'

# Find your Account SID and Auth Token at twilio.com/console
# and set the environment variables. See http://twil.io/secure
account_sid = ENV['TWILIO_ACCOUNT_SID']
auth_token = ENV['TWILIO_AUTH_TOKEN']
@client = Twilio::REST::Client.new(account_sid, auth_token)

conversation = @client
               .conversations
               .v1
               .conversations('CHXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX')
               .update(
                 timers_inactive: 'PT5M',
                 timers_closed: 'PT60000S'
               )

puts conversation.account_sid
```

```bash
# Install the twilio-cli from https://twil.io/cli

twilio api:conversations:v1:conversations:update \
   --sid CHXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX \
   --timers.inactive PT5M \
   --timers.closed PT60000S
```

```bash
curl -X POST "https://conversations.twilio.com/v1/Conversations/CHXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" \
--data-urlencode "Timers.Inactive=PT5M" \
--data-urlencode "Timers.Closed=PT60000S" \
-u $TWILIO_ACCOUNT_SID:$TWILIO_AUTH_TOKEN
```

Once set, the timers property of the Conversation resource displays the date and time when the timer will elapse in [ISO 8601 date and time](https://en.wikipedia.org/wiki/ISO_8601#Durations) in UTC.

```json
"timers": {
    "date_inactive": "2025-04-16T22:19:38Z",
    "date_closed": "2025-04-16TT22:28:38Z"
}
```

When the inactive timer lapses or you manually set the conversation to inactive, the `date_inactive` property stops returning in the Conversation resources. However, the inactive timer configuration is still retained, and the timer resets if you set the conversation back to `active` again. **To disable a timer entirely, set it to `PT0S`.**

Some other things to be aware of when configuring timers:

* Timers have a precision of 1 second.
* The minimum time for the inactive timer is 60 seconds. For a closed timer, the minimum time is 600 seconds (10 minutes).
* If both timers are set, the closed timer will automatically update based on the inactive timer.
* When a conversation is closed, all timers are removed.

### Timer scenarios

| Inactive Timer | Closed Timer    | Behavior                                                                                                                                                     |
| -------------- | --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| none           | none            | Conversations is `active` until you change it manually.                                                                                                      |
| Set to 1 hour  | Set to 24 hours | The conversation transitions to `inactive` after 1 hour of inactivity. Then, after an additional 24 hours of inactivity, it transitions to `closed`.         |
| 1 hour         | none            | The conversation transitions to `inactive` after 1 hour of inactivity. It stays in that state until a new message is added or you manually change the state. |
| none           | Set to 24 hours | The conversation transitions to `closed` after 24 hours of inactivity.                                                                                       |
