diff --git src/wp-includes/js/wp-api.js src/wp-includes/js/wp-api.js
index d796ddc475..35fcb5c5d1 100644
--- src/wp-includes/js/wp-api.js
+++ src/wp-includes/js/wp-api.js
@@ -287,9 +287,20 @@
 	 * @param {Object} 	       loadingObjects An object containing the models and collections we are building.
 	 */
 	wp.api.utils.addMixinsAndHelpers = function( model, modelClassName, loadingObjects ) {
-
 		var hasDate = false,
 
+			/**
+			 * Specify the models that save autosaves.
+			 */
+			canSaveAutosaves = wpApiSettings.canSaveAutosaves ||
+				[ 'Post', 'Page' ],
+
+			/**
+			 * Specify the models that retrieve autosaves.
+			 */
+			canRetrieveAutosaves = wpApiSettings.canRetrieveAutosaves ||
+				[ 'PostRevision', 'PageRevision' ],
+
 			/**
 			 * Array of parseable dates.
 			 *
@@ -741,8 +752,36 @@
 				getFeaturedMedia: function() {
 					return buildModelGetter( this, this.get( 'featured_media' ), 'Media', 'wp:featuredmedia', 'source_url' );
 				}
+			},
+
+			/**
+			 * Add a helper to enable saving autosaves.
+			 */
+			autosaveMixin = {
+				autosave: function() {
+					return this.save( { is_autosave: true } );
+				}
+			},
+
+			/**
+			 * Add a helper to enable retrieving autosaves.
+			 */
+			getAutosaveMixin = {
+				getAutosave: function() {
+					return this.fetch( { data: { is_autosave: true } } );
+				}
 			};
 
+		// Add Autosaving for specific models
+		if ( _.indexOf( canSaveAutosaves, modelClassName ) >= 0 ) {
+			model = model.extend( autosaveMixin );
+		}
+
+		// Add Autosaving for specific models
+		if ( _.indexOf( canRetrieveAutosaves, modelClassName ) >= 0 ) {
+			model = model.extend( getAutosaveMixin );
+		}
+
 		// Exit if we don't have valid model defaults.
 		if ( _.isUndefined( model.prototype.args ) ) {
 			return model;
diff --git src/wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php src/wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php
index 0661152de6..05f27713b5 100644
--- src/wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php
+++ src/wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php
@@ -657,19 +657,92 @@ class WP_REST_Posts_Controller extends WP_REST_Controller {
 	 * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
 	 */
 	public function update_item( $request ) {
-		$valid_check = $this->get_post( $request['id'] );
-		if ( is_wp_error( $valid_check ) ) {
-			return $valid_check;
+		$existing_post = $this->get_post( $request['id'] );
+		if ( is_wp_error( $existing_post ) ) {
+			return $existing_post;
 		}
 
-		$post = $this->prepare_item_for_database( $request );
+		$new_post = $this->prepare_item_for_database( $request );
 
-		if ( is_wp_error( $post ) ) {
-			return $post;
+		if ( is_wp_error( $new_post ) ) {
+			return $new_post;
 		}
 
-		// convert the post object to an array, otherwise wp_update_post will expect non-escaped input.
-		$post_id = wp_update_post( wp_slash( (array) $post ), true );
+		// Keep the ID for later.
+		$post_id = $new_post->ID;
+
+		// The following functions expect array.
+		$post_data = get_object_vars( $new_post );
+
+		// Autosave
+		if ( ! empty( $request['is_autosave'] ) ) {
+			if ( ! defined( 'DOING_AUTOSAVE' ) ) {
+				define( 'DOING_AUTOSAVE', true );
+			}
+
+			$post_author = get_current_user_id();
+			$autosave_id = 0;
+
+			// Also needs to check post lock.
+			if ( $post_author == $existing_post->post_author && ( 'auto-draft' === $existing_post->post_status || 'draft' === $existing_post->post_status ) ) {
+				// Drafts and auto-drafts are just overwritten by autosave for the same user.
+				// Expects escaped input when array.
+				$post_id = wp_update_post( wp_slash( $post_data ), true );
+			} else {
+				// Store one autosave per author. If there is already an autosave, update it.
+				if ( $old_autosave = wp_get_post_autosave( $post_data['ID'], $post_author ) ) {
+					$new_autosave                = _wp_post_revision_data( $post_data, true );
+					$new_autosave['ID']          = $old_autosave->ID;
+					$new_autosave['post_author'] = $post_author;
+
+					// If the new autosave has the same content as the post, delete the autosave.
+					$autosave_is_different = false;
+
+					foreach ( array_intersect( array_keys( $new_autosave ), array_keys( _wp_post_revision_fields( $existing_post ) ) ) as $field ) {
+						if ( normalize_whitespace( $new_autosave[ $field ] ) != normalize_whitespace( $existing_post->$field ) ) {
+							$autosave_is_different = true;
+							break;
+						}
+					}
+
+					if ( ! $autosave_is_different ) {
+						wp_delete_post_revision( $old_autosave->ID );
+					} else {
+						/**
+						 * Fires before an autosave is stored via the REST API.
+						 *
+						 * @since 5.0.0
+						 *
+						 * @param array           $new_autosave Post array - the autosave that is about to be saved.
+						 * @param WP_REST_Request $request      Request object.     
+						 */
+						do_action( 'rest_creating_autosave', $new_autosave, $request );
+
+						$autosave_id = wp_update_post( $new_autosave );
+					}
+				} else {
+					// Need to merge the autosave data with some of the existing post data.
+					foreach ( array_keys( _wp_post_revision_fields( $existing_post ) ) as $field ) {
+						if ( empty( $post_data[ $field ] ) ) {
+							$post_data[ $field ] = $existing_post->$field;
+						}
+					}
+
+					/** This action is documented in wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php */
+					do_action( 'rest_creating_autosave', $post_data, $request );
+
+					$autosave_id = _wp_put_post_revision( $post_data, true );
+				}
+
+				if ( is_wp_error( $autosave_id ) ) {
+					// Pass on the error.
+					$post_id = $autosave_id;
+				}
+			}
+		} else {
+			// Expects escaped input when array.
+			$post_id = wp_update_post( wp_slash( $post_data ), true );
+		}
 
 		if ( is_wp_error( $post_id ) ) {
 			if ( 'db_update_error' === $post_id->get_error_code() ) {
diff --git src/wp-includes/rest-api/endpoints/class-wp-rest-revisions-controller.php src/wp-includes/rest-api/endpoints/class-wp-rest-revisions-controller.php
index 471c4c4b4f..8caaa43bfb 100644
--- src/wp-includes/rest-api/endpoints/class-wp-rest-revisions-controller.php
+++ src/wp-includes/rest-api/endpoints/class-wp-rest-revisions-controller.php
@@ -187,6 +187,41 @@ class WP_REST_Revisions_Controller extends WP_REST_Controller {
 		return $revision;
 	}
 
+	/**
+	 * Get autosave revision if it exists.
+	 *
+	 * @since 5.0.0
+	 *
+	 * @param  WP_REST_Request $request Full data about the request.
+	 * @return WP_Post|WP_Error Revision post object if post autosave exists, WP_Error otherwise.
+	 */
+	protected function get_autosave( $request ) {
+		$parent = $this->get_parent( $request['parent'] );
+		if ( is_wp_error( $parent ) ) {
+			return $parent;
+		}
+
+		$user_id = 0;
+
+		if ( ! empty( $request['author'] ) ) {
+			$post_author = (int) $request['author'];
+			$user_obj = get_userdata( $post_author );
+
+			if ( ! $user_obj ) {
+				return new WP_Error( 'rest_invalid_author', __( 'Invalid author ID.' ), array( 'status' => 400 ) );
+			} else {
+				$user_id = $post_author;
+			}
+		}
+
+		$revision = wp_get_post_autosave( $parent->ID, $user_id );
+		if ( empty( $revision ) || empty( $revision->ID ) || 'revision' !== $revision->post_type ) {
+			return new WP_Error( 'rest_post_no_autosave', __( 'Autosave does not exist.' ), array( 'status' => 404 ) );
+		}
+
+		return $revision;
+	}
+
 	/**
 	 * Gets a collection of revisions.
 	 *
@@ -201,7 +236,15 @@ class WP_REST_Revisions_Controller extends WP_REST_Controller {
 			return $parent;
 		}
 
-		$revisions = wp_get_post_revisions( $request['parent'] );
+		$revisions = wp_get_post_revisions( $parent->ID );
+
+		if ( ! empty( $request['is_autosave'] ) ) {
+			foreach ( $revisions as $revision_id => $revision ) {
+				if ( ! wp_is_post_autosave( $revision ) ) {
+					unset( $revisions[ $revision_id ] );
+				}
+			}
+		}
 
 		$response = array();
 		foreach ( $revisions as $revision ) {
@@ -237,7 +280,12 @@ class WP_REST_Revisions_Controller extends WP_REST_Controller {
 			return $parent;
 		}
 
-		$revision = $this->get_revision( $request['id'] );
+		if ( ! empty( $request['is_autosave'] ) ) {
+			$revision = $this->get_autosave( $request );
+		} else {
+			$revision = $this->get_revision( $request['id'] );
+		}
+
 		if ( is_wp_error( $revision ) ) {
 			return $revision;
 		}
diff --git tests/phpunit/tests/rest-api/rest-posts-controller.php tests/phpunit/tests/rest-api/rest-posts-controller.php
index bc820a8796..30f4378e5a 100644
--- tests/phpunit/tests/rest-api/rest-posts-controller.php
+++ tests/phpunit/tests/rest-api/rest-posts-controller.php
@@ -2363,6 +2363,119 @@ class WP_Test_REST_Posts_Controller extends WP_Test_REST_Post_Type_Controller_Te
 		$this->assertEquals( $params['excerpt'], $post->post_excerpt );
 	}
 
+	public function test_rest_autosave_published_post() {
+		wp_set_current_user( self::$editor_id );
+
+		$request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/posts/%d', self::$post_id ) );
+		$request->add_header( 'content-type', 'application/json' );
+
+		$autosave_data = $this->set_post_data(
+			array(
+				'id' => self::$post_id,
+				'is_autosave' => true,
+				'content' => 'Updated post content',
+			)
+		);
+
+		$request->set_body( wp_json_encode( $autosave_data ) );
+		$response = $this->server->dispatch( $request );
+
+		$this->check_update_post_response( $response );
+		$new_data = $response->get_data();
+
+		// The published post shouldn't change.
+		$current_post = get_post( self::$post_id );
+		$this->assertEquals( $current_post->ID, $new_data['id'] );
+		$this->assertEquals( $current_post->post_title, $new_data['title']['raw'] );
+		$this->assertEquals( $current_post->post_content, $new_data['content']['raw'] );
+		$this->assertEquals( $current_post->post_excerpt, $new_data['excerpt']['raw'] );
+
+		$autosave_post = wp_get_post_autosave( self::$post_id );
+		$this->assertEquals( $autosave_data['title'], $autosave_post->post_title );
+		$this->assertEquals( $autosave_data['content'], $autosave_post->post_content );
+		$this->assertEquals( $autosave_data['excerpt'], $autosave_post->post_excerpt );
+	}
+
+	public function test_rest_autosave_draft_post_same_author() {
+		wp_set_current_user( self::$editor_id );
+
+		$post_data = array(
+			'post_content' => 'Test post content',
+			'post_title'   => 'Test post title',
+			'post_excerpt' => 'Test post excerpt',
+		);
+		$post_id = wp_insert_post( $post_data );
+
+		$autosave_data = array(
+			'id' => $post_id,
+			'is_autosave' => true,
+			'content' => 'Updated post content',
+		);
+
+		$request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/posts/%d', $post_id ) );
+		$request->add_header( 'content-type', 'application/json' );
+		$request->set_body( wp_json_encode( $autosave_data ) );
+		$response = $this->server->dispatch( $request );
+
+		$this->check_update_post_response( $response );
+		$new_data = $response->get_data();
+
+		// The draft post should be updated.
+		$this->assertEquals( $post_id, $new_data['id'] );
+		$this->assertEquals( $autosave_data['content'], $new_data['content']['raw'] );
+
+		$post = get_post( $post_id );
+		$this->assertEquals( $post_data['post_title'], $post->post_title );
+		$this->assertEquals( $autosave_data['content'], $post->post_content );
+		$this->assertEquals( $post_data['post_excerpt'], $post->post_excerpt );
+
+		wp_delete_post( $post_id );
+	}
+
+	public function test_rest_autosave_draft_post_different_author() {
+		wp_set_current_user( self::$editor_id );
+
+		$post_data = array(
+			'post_content' => 'Test post content',
+			'post_title'   => 'Test post title',
+			'post_excerpt' => 'Test post excerpt',
+			'post_author'  => ++self::$editor_id,
+		);
+		$post_id = wp_insert_post( $post_data );
+
+		$autosave_data = array(
+			'id' => $post_id,
+			'is_autosave' => true,
+			'content' => 'Updated post content',
+		);
+
+		$request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/posts/%d', $post_id ) );
+		$request->add_header( 'content-type', 'application/json' );
+		$request->set_body( wp_json_encode( $autosave_data ) );
+		$response = $this->server->dispatch( $request );
+
+		$this->check_update_post_response( $response );
+		$new_data = $response->get_data();
+
+
+		// The draft post shouldn't change.
+		$current_post = get_post( $post_id );
+		$this->assertEquals( $current_post->ID, $new_data['id'] );
+		$this->assertEquals( $current_post->post_title, $new_data['title']['raw'] );
+		$this->assertEquals( $current_post->post_content, $new_data['content']['raw'] );
+		$this->assertEquals( $current_post->post_excerpt, $new_data['excerpt']['raw'] );
+
+		$autosave_post = wp_get_post_autosave( $post_id );
+		// No changes
+		$this->assertEquals( $current_post->post_title, $autosave_post->post_title );
+		$this->assertEquals( $current_post->post_excerpt, $autosave_post->post_excerpt );
+
+		// Has changes
+		$this->assertEquals( $autosave_data['content'], $autosave_post->post_content );
+
+		wp_delete_post( $post_id );
+	}
+
 	public function test_rest_update_post_raw() {
 		wp_set_current_user( self::$editor_id );
 
diff --git tests/phpunit/tests/rest-api/rest-revisions-controller.php tests/phpunit/tests/rest-api/rest-revisions-controller.php
index c30ab17c85..11576889d4 100644
--- tests/phpunit/tests/rest-api/rest-revisions-controller.php
+++ tests/phpunit/tests/rest-api/rest-revisions-controller.php
@@ -44,6 +44,16 @@ class WP_Test_REST_Revisions_Controller extends WP_Test_REST_Controller_Testcase
 				'ID'           => self::$post_id,
 			)
 		);
+
+		// Autosave, different user
+		wp_set_current_user( self::$contributor_id );
+		_wp_put_post_revision(
+			array(
+				'post_content' => 'This content is better autosaved.',
+				'ID'           => self::$post_id,
+			),
+			true
+		);
 		wp_set_current_user( 0 );
 	}
 
@@ -64,6 +74,8 @@ class WP_Test_REST_Revisions_Controller extends WP_Test_REST_Controller_Testcase
 		$this->revision_id1 = $this->revision_1->ID;
 		$this->revision_2   = array_pop( $revisions );
 		$this->revision_id2 = $this->revision_2->ID;
+		$this->revision_3   = array_pop( $revisions );
+		$this->revision_id3 = $this->revision_3->ID;
 	}
 
 	public function test_register_routes() {
@@ -95,14 +107,17 @@ class WP_Test_REST_Revisions_Controller extends WP_Test_REST_Controller_Testcase
 		$response = rest_get_server()->dispatch( $request );
 		$data     = $response->get_data();
 		$this->assertEquals( 200, $response->get_status() );
-		$this->assertCount( 2, $data );
+		$this->assertCount( 3, $data );
 
 		// Reverse chron
-		$this->assertEquals( $this->revision_id2, $data[0]['id'] );
-		$this->check_get_revision_response( $data[0], $this->revision_2 );
+		$this->assertEquals( $this->revision_id3, $data[0]['id'] );
+		$this->check_get_revision_response( $data[0], $this->revision_3 );
+
+		$this->assertEquals( $this->revision_id2, $data[1]['id'] );
+		$this->check_get_revision_response( $data[1], $this->revision_2 );
 
-		$this->assertEquals( $this->revision_id1, $data[1]['id'] );
-		$this->check_get_revision_response( $data[1], $this->revision_1 );
+		$this->assertEquals( $this->revision_id1, $data[2]['id'] );
+		$this->check_get_revision_response( $data[2], $this->revision_1 );
 	}
 
 	public function test_get_items_no_permission() {
@@ -155,6 +170,20 @@ class WP_Test_REST_Revisions_Controller extends WP_Test_REST_Controller_Testcase
 		$this->assertSame( self::$editor_id, $data['author'] );
 	}
 
+	public function test_get_autosave_item() {
+		wp_set_current_user( self::$editor_id );
+		$request  = new WP_REST_Request( 'GET', '/wp/v2/posts/' . self::$post_id . '/revisions/' . $this->revision_id3 );
+		$request->set_param( 'is_autosave', true );
+		$response = rest_get_server()->dispatch( $request );
+
+		$this->assertEquals( 200, $response->get_status() );
+		$data     = $response->get_data();
+
+		$this->assertNotEquals( self::$editor_id, $data['author'] );
+		$this->assertEquals( $this->revision_id3, $data['id'] );
+		$this->check_get_revision_response( $response, $this->revision_3 );
+	}
+
 	public function test_get_item_embed_context() {
 		wp_set_current_user( self::$editor_id );
 		$request = new WP_REST_Request( 'GET', '/wp/v2/posts/' . self::$post_id . '/revisions/' . $this->revision_id1 );
@@ -330,8 +359,10 @@ class WP_Test_REST_Revisions_Controller extends WP_Test_REST_Controller_Testcase
 		$this->assertEquals( mysql_to_rfc3339( $revision->post_date ), $response['date'] );
 		$this->assertEquals( mysql_to_rfc3339( $revision->post_date_gmt ), $response['date_gmt'] );
 
-		$rendered_excerpt = apply_filters( 'the_excerpt', apply_filters( 'get_the_excerpt', $revision->post_excerpt, $revision ) );
-		$this->assertEquals( $rendered_excerpt, $response['excerpt']['rendered'] );
+		if ( ! empty( $revision->post_excerpt ) ) {
+			$rendered_excerpt = apply_filters( 'the_excerpt', apply_filters( 'get_the_excerpt', $revision->post_excerpt, $revision ) );
+			$this->assertEquals( $rendered_excerpt, $response['excerpt']['rendered'] );
+		}
 
 		$rendered_guid = apply_filters( 'get_the_guid', $revision->guid, $revision->ID );
 		$this->assertEquals( $rendered_guid, $response['guid']['rendered'] );
