diff --git a/test/core/end2end/fuzzers/api_fuzzer.c b/test/core/end2end/fuzzers/api_fuzzer.c
index c74783bee446daa47612fd321a479b98121b7a06..cc98e02529db6b0475aff8c5596f00cb0be9c211 100644
--- a/test/core/end2end/fuzzers/api_fuzzer.c
+++ b/test/core/end2end/fuzzers/api_fuzzer.c
@@ -82,6 +82,14 @@ static char *read_string(input_stream *inp) {
   return str;
 }
 
+static void read_buffer(input_stream *inp, char **buffer, size_t *length) {
+  *length = next_byte(inp);
+  *buffer = gpr_malloc(*length);
+  for (size_t i = 0; i < *length; i++) {
+    (*buffer)[i] = (char)next_byte(inp);
+  }
+}
+
 static uint32_t read_uint32(input_stream *inp) {
   uint8_t b = next_byte(inp);
   uint32_t x = b & 0x7f;
@@ -106,6 +114,23 @@ static uint32_t read_uint32(input_stream *inp) {
   return x;
 }
 
+static grpc_byte_buffer *read_message(input_stream *inp) {
+  gpr_slice slice = gpr_slice_malloc(read_uint32(inp));
+  memset(GPR_SLICE_START_PTR(slice), 0, GPR_SLICE_LENGTH(slice));
+  return grpc_raw_byte_buffer_create(&slice, 1);
+}
+
+static void read_metadata(input_stream *inp, size_t *count, grpc_metadata **metadata) {
+  *count = next_byte(inp);
+  *metadata = gpr_malloc(*count * sizeof(**metadata));
+  memset(*metadata, 0, *count * sizeof(**metadata));
+  for (size_t i = 0; i < *count; i++) {
+    (*metadata)[i].key = read_string(inp);
+    read_buffer(inp, (char**)&(*metadata[i]).value, &(*metadata[i]).value_length);
+    (*metadata)[i].flags = read_uint32(inp);
+  }
+}
+
 static int read_int(input_stream *inp) { return (int)read_uint32(inp); }
 
 static grpc_channel_args *read_args(input_stream *inp) {
@@ -304,7 +329,13 @@ static void free_non_null(void *p) {
 typedef struct call_state {
   grpc_call *client;
   grpc_call *server;
+  grpc_byte_buffer *recv_message[2];
+  grpc_status_code status;
   grpc_metadata_array recv_initial_metadata;
+  grpc_metadata_array recv_trailing_metadata;
+  char *recv_status_details;
+  size_t recv_status_details_capacity;
+  int cancelled;
 } call_state;
 
 int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
@@ -323,6 +354,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
   int pending_server_shutdowns = 0;
   int pending_channel_watches = 0;
   int pending_pings = 0;
+  int pending_ops = 0;
 
 #define MAX_CALLS 16
   call_state calls[MAX_CALLS];
@@ -332,7 +364,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
   grpc_completion_queue *cq = grpc_completion_queue_create(NULL);
 
   while (!is_eof(&inp) || g_channel != NULL || g_server != NULL ||
-         pending_channel_watches > 0 || pending_pings > 0) {
+         pending_channel_watches > 0 || pending_pings > 0 || pending_ops > 0) {
     if (is_eof(&inp)) {
       if (g_channel != NULL) {
         grpc_channel_destroy(g_channel);
@@ -549,15 +581,16 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
         if (ok && !on_server && calls[0].client == NULL) {
           ok = false;
         }
-        for (size_t i = 0; i < num_ops; i++) {
-          grpc_op *op = &ops[i];
+        size_t i;
+        grpc_op *op;
+        for (i = 0; i < num_ops; i++) {
+          op = &ops[i];
           switch (next_byte(&inp)) {
             default:
               ok = false;
               break;
             case GRPC_OP_SEND_INITIAL_METADATA:
               op->op = GRPC_OP_SEND_INITIAL_METADATA;
-              op->data.send_initial_metadata.count = next_byte(&inp);
               read_metadata(&inp, &op->data.send_initial_metadata.count,
                             &op->data.send_initial_metadata.metadata);
               break;
@@ -565,12 +598,17 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
               op->op = GRPC_OP_SEND_INITIAL_METADATA;
               op->data.send_message = read_message(&inp);
               break;
+            case GRPC_OP_SEND_CLOSE_FROM_CLIENT:
+              op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
+              break;
             case GRPC_OP_SEND_STATUS_FROM_SERVER:
               op->op = GRPC_OP_SEND_STATUS_FROM_SERVER;
               read_metadata(
                   &inp,
                   &op->data.send_status_from_server.trailing_metadata_count,
                   &op->data.send_status_from_server.trailing_metadata);
+              op->data.send_status_from_server.status = next_byte(&inp);
+              op->data.send_status_from_server.status_details = read_string(&inp);
               break;
             case GRPC_OP_RECV_INITIAL_METADATA:
               op->op = GRPC_OP_RECV_INITIAL_METADATA;
@@ -598,12 +636,39 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
           op->reserved = NULL;
           op->flags = read_uint32(&inp);
           if (ok) {
+            validator *v = create_validator(decrement, &pending_ops);
+            pending_ops++;
             grpc_call_error error = grpc_call_start_batch(
                 on_server ? calls[0].server : calls[0].client, ops, num_ops,
-                tag, NULL);
+                v, NULL);
+            if (error != GRPC_CALL_OK) {
+              v->validate(v->arg, false);
+              gpr_free(v);
+            }
           } else {
             end(&inp);
           }
+          for (i = 0; i < num_ops; i++) {
+            op = &ops[i];
+            switch (op->op) {
+            case GRPC_OP_SEND_INITIAL_METADATA:
+              gpr_free(op->data.send_initial_metadata.metadata);
+              break;
+            case GRPC_OP_SEND_MESSAGE:
+              grpc_byte_buffer_destroy(op->data.send_message);
+              break;
+            case GRPC_OP_SEND_STATUS_FROM_SERVER:
+              gpr_free(op->data.send_status_from_server.trailing_metadata);
+              gpr_free((void*)op->data.send_status_from_server.status_details);
+              break;
+            case GRPC_OP_SEND_CLOSE_FROM_CLIENT:
+            case GRPC_OP_RECV_INITIAL_METADATA:
+            case GRPC_OP_RECV_MESSAGE:
+            case GRPC_OP_RECV_STATUS_ON_CLIENT:
+            case GRPC_OP_RECV_CLOSE_ON_SERVER:
+              break;
+            }
+          }
         }
         break;
       }
@@ -619,7 +684,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
       // cancel current call on server
       case 14: {
         if (num_calls > 0 && calls[0].server) {
-          grpc_call_cancel(calls[0].server, NULL)
+          grpc_call_cancel(calls[0].server, NULL);
         } else {
           end(&inp);
         }
@@ -676,13 +741,6 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
         gpr_free(tracer);
         break;
       }
-      // create an alarm
-      case 21: {
-        gpr_timespec deadline =
-            gpr_time_add(gpr_now(GPR_CLOCK_REALTIME),
-                         gpr_time_from_micros(read_uint32(&inp), GPR_TIMESPAN));
-        grpc_alarm *alarm = grpc_alarm_create(cq, );
-      }
     }
   }