Index: includes/api/ApiProtect.php
===================================================================
--- includes/api/ApiProtect.php	(revision 112344)
+++ includes/api/ApiProtect.php	(working copy)
@@ -37,9 +37,18 @@
 		global $wgRestrictionLevels;
 		$params = $this->extractRequestParams();
 
-		$titleObj = Title::newFromText( $params['title'] );
-		if ( !$titleObj ) {
-			$this->dieUsageMsg( array( 'invalidtitle', $params['title'] ) );
+		$this->requireOnlyOneParameter( $params, 'title', 'pageid' );
+
+		if ( isset( $params['title'] ) ) {
+			$titleObj = Title::newFromText( $params['title'] );
+			if ( !$titleObj ) {
+				$this->dieUsageMsg( array( 'invalidtitle', $params['title'] ) );
+			}
+		} elseif ( isset( $params['pageid'] ) ) {
+			$titleObj = Title::newFromID( $params['pageid'] );
+			if ( !$titleObj ) {
+				$this->dieUsageMsg( array( 'nosuchpageid', $params['pageid'] ) );
+			}
 		}
 
 		$errors = $titleObj->getUserPermissionsErrors( 'protect', $this->getUser() );
@@ -138,8 +147,9 @@
 		return array(
 			'title' => array(
 				ApiBase::PARAM_TYPE => 'string',
-				ApiBase::PARAM_REQUIRED => true
 			),
+			'pageid' => array(
+				ApiBase::PARAM_TYPE => 'integer',
 			'token' => null,
 			'protections' => array(
 				ApiBase::PARAM_ISMULTI => true,
@@ -171,6 +181,7 @@
 	public function getParamDescription() {
 		return array(
 			'title' => 'Title of the page you want to (un)protect',
+			'pageid' => 'ID of the page you want to (un)protect',
 			'token' => 'A protect token previously retrieved through prop=info',
 			'protections' => 'Pipe-separated list of protection levels, formatted action=group (e.g. edit=sysop)',
 			'expiry' => array( 'Expiry timestamps. If only one timestamp is set, it\'ll be used for all protections.',
@@ -188,16 +199,20 @@
 	}
 
 	public function getPossibleErrors() {
-		return array_merge( parent::getPossibleErrors(), array(
-			array( 'invalidtitle', 'title' ),
-			array( 'toofewexpiries', 'noofexpiries', 'noofprotections' ),
-			array( 'create-titleexists' ),
-			array( 'missingtitle-createonly' ),
-			array( 'protect-invalidaction', 'action' ),
-			array( 'protect-invalidlevel', 'level' ),
-			array( 'invalidexpiry', 'expiry' ),
-			array( 'pastexpiry', 'expiry' ),
-		) );
+		return array_merge( parent::getPossibleErrors(),
+			$this->getRequireOnlyOneParameterErrorMessages(),
+			array(
+				array( 'invalidtitle', 'title' ),
+				array( 'nosuchpageid', 'pageid' ),
+				array( 'toofewexpiries', 'noofexpiries', 'noofprotections' ),
+				array( 'create-titleexists' ),
+				array( 'missingtitle-createonly' ),
+				array( 'protect-invalidaction', 'action' ),
+				array( 'protect-invalidlevel', 'level' ),
+				array( 'invalidexpiry', 'expiry' ),
+				array( 'pastexpiry', 'expiry' ),
+			)
+		);
 	}
 
 	public function needsToken() {
