Skip to content

Transactions

Transactional operations provide ACID-compliant atomic reads and writes across multiple items.


POST /api/v1/databases/{databaseId}/items/transact/get

Section titled “POST /api/v1/databases/{databaseId}/items/transact/get”

Atomically reads multiple items at a consistent point in time. Maximum 100 items.

Request:

{
"items": [
{ "pk": "user#123", "sk": "profile" },
{ "pk": "user#123", "sk": "settings", "projectionExpression": ["theme", "locale"] }
],
"clientRequestToken": "unique-request-id"
}
FieldTypeDescription
pkstringPartition key
skstringSort key (optional)
projectionExpressionarraySpecific attributes to return (optional)
clientRequestTokenstringIdempotency token (optional)

Response (200 OK):

{
"items": [
{
"pk": "user#123",
"sk": "profile",
"item": { "name": "John" },
"itemExists": true
},
{
"pk": "user#123",
"sk": "settings",
"item": null,
"itemExists": false
}
]
}

POST /api/v1/databases/{databaseId}/items/transact/write

Section titled “POST /api/v1/databases/{databaseId}/items/transact/write”

Atomically writes, updates, or deletes multiple items. All operations succeed or all fail. Maximum 25 items.

Request:

{
"items": [
{
"action": "Put",
"pk": "user#123",
"sk": "profile",
"data": { "name": "John" }
},
{
"action": "Update",
"pk": "user#123",
"sk": "stats",
"data": { "loginCount": 5 }
},
{
"action": "Delete",
"pk": "user#123",
"sk": "temp"
},
{
"action": "ConditionCheck",
"pk": "user#123",
"sk": "settings",
"conditionExpression": "attribute_exists(pk)"
}
],
"clientRequestToken": "unique-request-id"
}
ActionDescription
PutInsert or replace an item
UpdateUpdate existing item attributes
DeleteRemove an item
ConditionCheckVerify condition without modification

Response (200 OK):

{
"successCount": 4,
"errors": null
}

If any operation fails, the entire transaction is rolled back:

{
"successCount": 0,
"errors": [
{
"itemIndex": 3,
"pk": "user#123",
"sk": "settings",
"error": "Condition check failed",
"errorType": "ConditionalCheckFailed"
}
]
}

Error TypeDescription
ConditionalCheckFailedCondition expression evaluated to false
ItemCollectionSizeLimitExceededItem collection too large
TransactionCanceledTransaction was canceled
ValidationErrorInvalid request parameters
InternalServerErrorServer error

Use clientRequestToken to make transactions idempotent:

{
"items": [...],
"clientRequestToken": "order-12345-payment"
}

If you retry with the same token within 10 minutes, TerraScale returns the original result without re-executing the transaction.


// Transactional Get
var getItems = new List<TransactGetItem>
{
new() { PartitionKey = "user#123", SortKey = "profile" },
new() { PartitionKey = "user#123", SortKey = "settings" }
};
var getResult = await client.TransactGetAsync(getItems);
foreach (var item in getResult.Value.Items)
{
if (item.ItemExists)
{
Console.WriteLine($"{item.PartitionKey}/{item.SortKey}: {item.Item}");
}
}
// Transactional Write - Transfer money between accounts
var writeItems = new List<TransactWriteItem>
{
new()
{
Action = TransactAction.Update,
PartitionKey = "account#source",
SortKey = "balance",
Data = new Dictionary<string, object?> { ["amount"] = 900 },
ConditionExpression = "amount >= :minAmount"
},
new()
{
Action = TransactAction.Update,
PartitionKey = "account#dest",
SortKey = "balance",
Data = new Dictionary<string, object?> { ["amount"] = 1100 }
},
new()
{
Action = TransactAction.Put,
PartitionKey = "transfer#12345",
SortKey = "record",
Data = new Dictionary<string, object?>
{
["from"] = "account#source",
["to"] = "account#dest",
["amount"] = 100,
["timestamp"] = DateTime.UtcNow
}
}
};
var writeResult = await client.TransactWriteAsync(writeItems, "transfer-12345");
if (writeResult.IsSuccess)
{
Console.WriteLine("Transfer completed!");
}
else
{
Console.WriteLine("Transfer failed - rolled back");
}

Ensure both debit and credit happen atomically:

{
"items": [
{ "action": "Update", "pk": "account#A", "sk": "balance", "data": {"amount": 900} },
{ "action": "Update", "pk": "account#B", "sk": "balance", "data": {"amount": 1100} },
{ "action": "Put", "pk": "transfer#123", "sk": "log", "data": {...} }
]
}

Reserve stock only if available:

{
"items": [
{
"action": "ConditionCheck",
"pk": "product#ABC",
"sk": "inventory",
"conditionExpression": "quantity >= :required"
},
{
"action": "Update",
"pk": "product#ABC",
"sk": "inventory",
"data": { "quantity": 45 }
},
{
"action": "Put",
"pk": "order#12345",
"sk": "item#ABC",
"data": { "quantity": 5 }
}
]
}

LimitValue
Transact Get items100
Transact Write items25
Total request size4 MB
Item size400 KB

  1. Use transactions only when needed - They have higher latency than batch operations
  2. Keep transactions small - Fewer items = faster execution
  3. Use idempotency tokens - Prevents duplicate operations on retry
  4. Handle failures gracefully - The entire transaction rolls back on any failure