Skip to contentSkip to navigationSkip to topbar
On this page

API mutation and conflict resolution


Twilio allows multiple processes to update the same resource at the same time. In general, if two updates happen at the same time, the last one to complete will overwrite the previous one.

To help prevent accidental overwrites during concurrent updates, some Twilio API resources support optimistic concurrency control using the If-Match(link takes you to an external page) and ETag(link takes you to an external page) HTTP headers. Optimistic concurrency control allows multiple processes to attempt updates but requires each update to check if the resource has changed since it was last read. If the resource has changed, the update is rejected.

You can use the ETag and If-Match headers for the following resources:

  • Task
  • Sync List Item

General conflict resolution

general-conflict-resolution page anchor

Without the ETag and If-Match headers, the last update to a resource will overwrite any previous updates.

Example: Create a Task

example-create-a-task page anchor

Create a Task with the attributes {"foo": "bar"}.

Create a TaskLink to code sample: Create a Task
1
// Download the helper library from https://www.twilio.com/docs/node/install
2
const twilio = require("twilio"); // Or, for ESM: import twilio from "twilio";
3
4
// Find your Account SID and Auth Token at twilio.com/console
5
// and set the environment variables. See http://twil.io/secure
6
const accountSid = process.env.TWILIO_ACCOUNT_SID;
7
const authToken = process.env.TWILIO_AUTH_TOKEN;
8
const client = twilio(accountSid, authToken);
9
10
async function createTask() {
11
const task = await client.taskrouter.v1
12
.workspaces("WSXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX")
13
.tasks.create({ attributes: JSON.stringify({ foo: "bar" }) });
14
15
console.log(task.accountSid);
16
}
17
18
createTask();

Response

Note about this response
1
{
2
"account_sid": "ACaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
3
"age": 25200,
4
"assignment_status": "pending",
5
"attributes": "{\"foo\": \"bar\"}",
6
"date_created": "2014-05-14T18:50:02Z",
7
"date_updated": "2014-05-15T07:26:06Z",
8
"task_queue_entered_date": null,
9
"virtual_start_time": "2014-05-14T18:50:02Z",
10
"priority": 1,
11
"reason": "Test Reason",
12
"sid": "WTaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
13
"task_queue_sid": "WQaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
14
"task_channel_sid": "TCaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
15
"task_channel_unique_name": "unique",
16
"timeout": 60,
17
"url": "https://taskrouter.twilio.com/v1/Workspaces/WSaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/Tasks/WTaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
18
"workspace_sid": "WSXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
19
"workflow_sid": "WWaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
20
"workflow_friendly_name": "Example Workflow",
21
"task_queue_friendly_name": "Example Task Queue",
22
"ignore_capacity": false,
23
"routing_target": "WKaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
24
"addons": "{}",
25
"required_attention": 0,
26
"links": {
27
"task_queue": "https://taskrouter.twilio.com/v1/Workspaces/WSaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/TaskQueues/WQaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
28
"workflow": "https://taskrouter.twilio.com/v1/Workspaces/WSaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/Workflows/WWaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
29
"workspace": "https://taskrouter.twilio.com/v1/Workspaces/WSaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
30
"reservations": "https://taskrouter.twilio.com/v1/Workspaces/WSaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/Tasks/WTaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/Reservations"
31
}
32
}

Example: Update a Task without ETag and If-Match

example-update-a-task-without-etag-and-if-match page anchor

Next, make two POST requests in quick succession to update the Task's attributes. This simulates concurrent updates from different sources.

  • POST A: Update "foo": "bar" to "foo": "bar-SFO".
  • POST B: Update "foo": "bar" to "foo": "bar-DEN".
1
// Download the helper library from https://www.twilio.com/docs/node/install
2
const twilio = require("twilio"); // Or, for ESM: import twilio from "twilio";
3
4
// Find your Account SID and Auth Token at twilio.com/console
5
// and set the environment variables. See http://twil.io/secure
6
const accountSid = process.env.TWILIO_ACCOUNT_SID;
7
const authToken = process.env.TWILIO_AUTH_TOKEN;
8
const client = twilio(accountSid, authToken);
9
10
async function updateTask() {
11
const task = await client.taskrouter.v1
12
.workspaces("WSXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX")
13
.tasks("WTaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")
14
.update({ attributes: JSON.stringify({ foo: "bar-SFO" }) });
15
16
console.log(task.accountSid);
17
}
18
19
updateTask();

Response

Note about this response
1
{
2
"account_sid": "ACaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
3
"age": 25200,
4
"assignment_status": "pending",
5
"attributes": "{\"foo\": \"bar-SFO\"}",
6
"date_created": "2014-05-14T18:50:02Z",
7
"date_updated": "2014-05-15T07:26:06Z",
8
"task_queue_entered_date": "2014-05-14T18:50:02Z",
9
"virtual_start_time": "2023-08-02T12:34:56Z",
10
"priority": 0,
11
"reason": "Test Reason",
12
"sid": "WTaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
13
"task_queue_sid": "WQaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
14
"task_channel_sid": "TCaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
15
"task_channel_unique_name": "task-channel",
16
"timeout": 60,
17
"url": "https://taskrouter.twilio.com/v1/Workspaces/WSaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/Tasks/WTaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
18
"workflow_sid": "WWaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
19
"workspace_sid": "WSXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
20
"workflow_friendly_name": "Test Workflow",
21
"task_queue_friendly_name": "Test Queue",
22
"addons": "{}",
23
"ignore_capacity": false,
24
"routing_target": "WKaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
25
"required_attention": 0,
26
"links": {
27
"task_queue": "https://taskrouter.twilio.com/v1/Workspaces/WSaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/TaskQueues/WQaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
28
"workflow": "https://taskrouter.twilio.com/v1/Workspaces/WSaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/Workflows/WWaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
29
"workspace": "https://taskrouter.twilio.com/v1/Workspaces/WSaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
30
"reservations": "https://taskrouter.twilio.com/v1/Workspaces/WSaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/Tasks/WTaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/Reservations"
31
}
32
}
1
// Download the helper library from https://www.twilio.com/docs/node/install
2
const twilio = require("twilio"); // Or, for ESM: import twilio from "twilio";
3
4
// Find your Account SID and Auth Token at twilio.com/console
5
// and set the environment variables. See http://twil.io/secure
6
const accountSid = process.env.TWILIO_ACCOUNT_SID;
7
const authToken = process.env.TWILIO_AUTH_TOKEN;
8
const client = twilio(accountSid, authToken);
9
10
async function updateTask() {
11
const task = await client.taskrouter.v1
12
.workspaces("WSXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX")
13
.tasks("WTaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")
14
.update({ attributes: JSON.stringify({ foo: "bar-DEN" }) });
15
16
console.log(task.accountSid);
17
}
18
19
updateTask();

Response

Note about this response
1
{
2
"account_sid": "ACaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
3
"age": 25200,
4
"assignment_status": "pending",
5
"attributes": "{\"foo\": \"bar-DEN\"}",
6
"date_created": "2014-05-14T18:50:02Z",
7
"date_updated": "2014-05-15T07:26:06Z",
8
"task_queue_entered_date": "2014-05-14T18:50:02Z",
9
"virtual_start_time": "2023-08-02T12:34:56Z",
10
"priority": 0,
11
"reason": "Test Reason",
12
"sid": "WTaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
13
"task_queue_sid": "WQaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
14
"task_channel_sid": "TCaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
15
"task_channel_unique_name": "task-channel",
16
"timeout": 60,
17
"url": "https://taskrouter.twilio.com/v1/Workspaces/WSaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/Tasks/WTaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
18
"workflow_sid": "WWaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
19
"workspace_sid": "WSXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
20
"workflow_friendly_name": "Test Workflow",
21
"task_queue_friendly_name": "Test Queue",
22
"addons": "{}",
23
"ignore_capacity": false,
24
"routing_target": "WKaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
25
"required_attention": 0,
26
"links": {
27
"task_queue": "https://taskrouter.twilio.com/v1/Workspaces/WSaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/TaskQueues/WQaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
28
"workflow": "https://taskrouter.twilio.com/v1/Workspaces/WSaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/Workflows/WWaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
29
"workspace": "https://taskrouter.twilio.com/v1/Workspaces/WSaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
30
"reservations": "https://taskrouter.twilio.com/v1/Workspaces/WSaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/Tasks/WTaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/Reservations"
31
}
32
}

The POST B request overwrites the POST A request, and the Task's attributes are now "foo": "bar-DEN".


Conflict resolution with ETag and If-Match

conflict-resolution-with-etag-and-if-match page anchor

When you update a resource, the response returns a new ETag value that represents the current version of the resource. If you want to ensure that you're updating the most recent version, include the ETag value in the If-Match header of your update request.

  1. Make a GET request to retrieve the Task with the ETag header.
  2. Use the ETag value in the If-Match header when you make your update request.

If the ETag value and the If-Match value don't match, it means that the resource has been updated in-between and Twilio rejects your update with a 412 Precondition Failed error.

Example: Update a Task with ETag and If-Match

example-update-a-task-with-etag-and-if-match page anchor
1
// Download the helper library from https://www.twilio.com/docs/node/install
2
const twilio = require("twilio"); // Or, for ESM: import twilio from "twilio";
3
4
// Find your Account SID and Auth Token at twilio.com/console
5
// and set the environment variables. See http://twil.io/secure
6
const accountSid = process.env.TWILIO_ACCOUNT_SID;
7
const authToken = process.env.TWILIO_AUTH_TOKEN;
8
const client = twilio(accountSid, authToken);
9
10
async function updateTask() {
11
const task = await client.taskrouter.v1
12
.workspaces("WSXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX")
13
.tasks("WTaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")
14
.update({
15
attributes: JSON.stringify({ foo: "bar-DEN" }),
16
ifMatch: "0",
17
});
18
19
console.log(task.accountSid);
20
}
21
22
updateTask();

Response

Note about this response
1
{
2
"account_sid": "ACaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
3
"age": 25200,
4
"assignment_status": "pending",
5
"attributes": "{\"foo\": \"bar-DEN\"}",
6
"date_created": "2014-05-14T18:50:02Z",
7
"date_updated": "2014-05-15T07:26:06Z",
8
"task_queue_entered_date": "2014-05-14T18:50:02Z",
9
"virtual_start_time": "2023-08-02T12:34:56Z",
10
"priority": 0,
11
"reason": "Test Reason",
12
"sid": "WTaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
13
"task_queue_sid": "WQaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
14
"task_channel_sid": "TCaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
15
"task_channel_unique_name": "task-channel",
16
"timeout": 60,
17
"url": "https://taskrouter.twilio.com/v1/Workspaces/WSaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/Tasks/WTaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
18
"workflow_sid": "WWaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
19
"workspace_sid": "WSXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
20
"workflow_friendly_name": "Test Workflow",
21
"task_queue_friendly_name": "Test Queue",
22
"addons": "{}",
23
"ignore_capacity": false,
24
"routing_target": "WKaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
25
"required_attention": 0,
26
"links": {
27
"task_queue": "https://taskrouter.twilio.com/v1/Workspaces/WSaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/TaskQueues/WQaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
28
"workflow": "https://taskrouter.twilio.com/v1/Workspaces/WSaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/Workflows/WWaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
29
"workspace": "https://taskrouter.twilio.com/v1/Workspaces/WSaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
30
"reservations": "https://taskrouter.twilio.com/v1/Workspaces/WSaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/Tasks/WTaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/Reservations"
31
}
32
}

This operation fails with a 412 Precondition Failed response because the ETag (1) and the If-Match (0) values don't match.