diff --git a/src/box/lua/schema.lua b/src/box/lua/schema.lua
index 0041286b63932a3d8fb0bd50940ace2fdb528b59..88c912f6cc18c5a5c3d8d077a475f5da779c4216 100644
--- a/src/box/lua/schema.lua
+++ b/src/box/lua/schema.lua
@@ -228,6 +228,21 @@ box.begin = function()
         box.error()
     end
 end
+
+local function atomic_tail(status, ...)
+    if not status then
+        box.rollback()
+        error((...), 2)
+     end
+     box.commit()
+     return ...
+end
+
+box.atomic = function(fun, ...)
+    box.begin()
+    return atomic_tail(pcall(fun, ...))
+end
+
 -- box.commit yields, so it's defined as Lua/C binding
 -- box.rollback yields as well
 
diff --git a/test/box/misc.result b/test/box/misc.result
index e8ff1436196776119044019c9655b43fe215e8ba..cf56fd4750b201663fc02c67673e97758b78c94e 100644
--- a/test/box/misc.result
+++ b/test/box/misc.result
@@ -55,7 +55,8 @@ t = {} for n in pairs(box) do table.insert(t, tostring(n)) end table.sort(t)
 ...
 t
 ---
-- - backup
+- - atomic
+  - backup
   - begin
   - cfg
   - commit
diff --git a/test/box/transaction.result b/test/box/transaction.result
index 9c24d1f7b28aae8a88a4fd79ae91e62c26666bd3..746f7e12c23067cc2f4149e0b23c8a7e37d3e76e 100644
--- a/test/box/transaction.result
+++ b/test/box/transaction.result
@@ -423,3 +423,83 @@ function gh_1638() box.begin(); box.rollback() end
 for i = 1, 1000 do fiber.create(function() gh_1638() end) end
 ---
 ...
+--
+--gh-818 add atomic()
+--
+space = box.schema.space.create('atomic')
+---
+...
+index = space:create_index('primary')
+---
+...
+test_run:cmd("setopt delimiter ';'")
+---
+- true
+...
+function args(...)
+    return 'args', ...
+end;
+---
+...
+box.atomic(args, 1, 2, 3, 4, 5);
+---
+- args
+- 1
+- 2
+- 3
+- 4
+- 5
+...
+function tx()
+    space:auto_increment{'first row'}
+    space:auto_increment{'second row'}
+    return space:select{}
+end;
+---
+...
+box.atomic(tx);
+---
+- - [1, 'first row']
+  - [2, 'second row']
+...
+function tx_error(space)
+    space:auto_increment{'third'}
+    space:auto_increment{'fourth'}
+    error("some error")
+end;
+---
+...
+box.atomic(tx_error, space);
+---
+- error: '[string "function tx_error(space)     space:auto_incre..."]:1: some error'
+...
+function nested(space)
+    box.begin()
+end;
+---
+...
+box.atomic(nested, space);
+---
+- error: 'Operation is not permitted when there is an active transaction '
+...
+function rollback(space)
+    space:auto_increment{'fifth'}
+    box.rollback()
+end;
+---
+...
+box.atomic(rollback, space);
+---
+...
+test_run:cmd("setopt delimiter ''");
+---
+- true
+...
+space:select{}
+---
+- - [1, 'first row']
+  - [2, 'second row']
+...
+space:drop()
+---
+...
diff --git a/test/box/transaction.test.lua b/test/box/transaction.test.lua
index 22e6e6cca901eb6e7d3eab53f2d10b1aa4e2c0d9..cda0eb151a08b9294ec3e9a8669858140e2c22d9 100644
--- a/test/box/transaction.test.lua
+++ b/test/box/transaction.test.lua
@@ -195,3 +195,45 @@ box.space.test:drop()
 --
 function gh_1638() box.begin(); box.rollback() end
 for i = 1, 1000 do fiber.create(function() gh_1638() end) end
+
+--
+--gh-818 add atomic()
+--
+space = box.schema.space.create('atomic')
+index = space:create_index('primary')
+test_run:cmd("setopt delimiter ';'")
+
+function args(...)
+    return 'args', ...
+end;
+box.atomic(args, 1, 2, 3, 4, 5);
+
+function tx()
+    space:auto_increment{'first row'}
+    space:auto_increment{'second row'}
+    return space:select{}
+end;
+box.atomic(tx);
+
+function tx_error(space)
+    space:auto_increment{'third'}
+    space:auto_increment{'fourth'}
+    error("some error")
+end;
+box.atomic(tx_error, space);
+
+function nested(space)
+    box.begin()
+end;
+box.atomic(nested, space);
+
+function rollback(space)
+    space:auto_increment{'fifth'}
+    box.rollback()
+end;
+box.atomic(rollback, space);
+
+test_run:cmd("setopt delimiter ''");
+space:select{}
+
+space:drop()