Index: extensions/SpamBlacklist/SpamBlacklist.php
===================================================================
--- extensions/SpamBlacklist/SpamBlacklist.php	(revision 42580)
+++ extensions/SpamBlacklist/SpamBlacklist.php	(working copy)
@@ -42,6 +42,7 @@
 
 $wgHooks['EditFilter'][] = 'wfSpamBlacklistValidate';
 $wgHooks['ArticleSaveComplete'][] = 'wfSpamBlacklistArticleSave';
+$wgHooks['APIEditBeforeSave'][] = 'wfSpamBlacklistFilterAPIEditBeforeSave';
 
 /**
  * Internationalization messages
@@ -74,21 +75,45 @@
  */
 function wfSpamBlacklistFilter( &$title, $text, $section, &$hookErr, $editSummary ) {
 	$spamObj = wfSpamBlacklistObject();
-	return $spamObj->filter( $title, $text, $section, $editSummary );
+	$ret = $spamObj->filter( $title, $text, $section, $editSummary );
+	if ( $ret!==false ) EditPage::spamPage( $ret );
+	return ( $ret!==false );
 }
 
 /**
  * Hook function for EditFilterMerged, replaces wfSpamBlacklistFilter
  */
 function wfSpamBlacklistFilterMerged( &$editPage, $text, &$hookErr, $editSummary ) {
+	global $wgTitle;
+	if( is_null( $wgTitle ) ) {
+		# API mode
+		# wfSpamBlacklistFilterAPIEditBeforeSave already checked the blacklist
+		return true;
+	}
+
 	$spamObj = wfSpamBlacklistObject();
 	$title = $editPage->mArticle->getTitle();
 	$ret = $spamObj->filter( $title, $text, '', $editSummary, $editPage );
+	if ( $ret!==false ) $editPage->spamPage( $ret );
 	// Return convention for hooks is the inverse of $wgFilterCallback
-	return !$ret;
+	return ( $ret===false );
 }
 
 /**
+ * Hook function for APIEditBeforeSave
+ */
+function wfSpamBlacklistFilterAPIEditBeforeSave( &$editPage, $text, &$resultArr ) {
+	$spamObj = wfSpamBlacklistObject();
+	$title = $editPage->mArticle->getTitle();
+	$ret = $spamObj->filter( $title, $text, '', '', $editPage );
+	if ( $ret!==false ) {
+		$resultArr['spamblacklist'] = $ret;
+	}
+	// Return convention for hooks is the inverse of $wgFilterCallback
+	return ( $ret===false );
+}
+
+/**
  * Hook function for EditFilter
  * Confirm that a local blacklist page being saved is valid,
  * and toss back a warning to the user if it isn't.
Index: extensions/SpamBlacklist/SpamBlacklist_body.php
===================================================================
--- extensions/SpamBlacklist/SpamBlacklist_body.php	(revision 42580)
+++ extensions/SpamBlacklist/SpamBlacklist_body.php	(working copy)
@@ -186,8 +186,7 @@
 	 * @param string $section Section number or name
 	 * @param EditSummary $editSummary Edit summary if one exists, some people use urls there too
 	 * @param EditPage $editPage EditPage if EditFilterMerged was called, null otherwise
-	 * @return True if the edit should not be allowed, false otherwise
-	 * If the return value is true, an error will have been sent to $wgOut
+	 * @return Matched text if the edit should not be allowed, false otherwise
 	 */
 	function filter( &$title, $text, $section, $editsummary = '', EditPage &$editPage = null ) {
 		global $wgArticle, $wgVersion, $wgOut, $wgParser, $wgUser;
@@ -263,12 +262,7 @@
 					wfDebugLog( 'SpamBlacklist', "Match!\n" );
 					$ip = wfGetIP();
 					wfDebugLog( 'SpamBlacklistHit', "$ip caught submitting spam: {$matches[0]}\n" );
-					if ( $editPage ) {
-						$editPage->spamPage( $matches[0] );
-					} else {
-						EditPage::spamPage( $matches[0] );
-					}
-					$retVal = true;
+					$retVal = $matches[0];
 					break;
 				}
 			}
