diff --git a/src/models/user.ts b/src/models/user.ts
index 8ff91d3f45..d2124bda74 100644
--- a/src/models/user.ts
+++ b/src/models/user.ts
@@ -113,6 +113,7 @@ export interface ILocalUser extends IUserBase {
 export interface IRemoteUser extends IUserBase {
 	inbox: string;
 	sharedInbox?: string;
+	featured?: string;
 	endpoints: string[];
 	uri: string;
 	url?: string;
diff --git a/src/remote/activitypub/kernel/add/index.ts b/src/remote/activitypub/kernel/add/index.ts
new file mode 100644
index 0000000000..eb2dba5b21
--- /dev/null
+++ b/src/remote/activitypub/kernel/add/index.ts
@@ -0,0 +1,22 @@
+import { IRemoteUser } from '../../../../models/user';
+import { IAdd } from '../../type';
+import { resolveNote } from '../../models/note';
+import { addPinned } from '../../../../services/i/pin';
+
+export default async (actor: IRemoteUser, activity: IAdd): Promise<void> => {
+	if ('actor' in activity && actor.uri !== activity.actor) {
+		throw new Error('invalid actor');
+	}
+
+	if (activity.target == null) {
+		throw new Error('target is null');
+	}
+
+	if (activity.target === actor.featured) {
+		const note = await resolveNote(activity.object);
+		await addPinned(actor, note._id);
+		return;
+	}
+
+	throw new Error(`unknown target: ${activity.target}`);
+};
diff --git a/src/remote/activitypub/kernel/index.ts b/src/remote/activitypub/kernel/index.ts
index 752a9bd2e2..52b0efc730 100644
--- a/src/remote/activitypub/kernel/index.ts
+++ b/src/remote/activitypub/kernel/index.ts
@@ -8,6 +8,8 @@ import like from './like';
 import announce from './announce';
 import accept from './accept';
 import reject from './reject';
+import add from './add';
+import remove from './remove';
 
 const self = async (actor: IRemoteUser, activity: Object): Promise<void> => {
 	switch (activity.type) {
@@ -31,6 +33,14 @@ const self = async (actor: IRemoteUser, activity: Object): Promise<void> => {
 		await reject(actor, activity);
 		break;
 
+	case 'Add':
+		await add(actor, activity).catch(err => console.log(err));
+		break;
+
+	case 'Remove':
+		await remove(actor, activity).catch(err => console.log(err));
+		break;
+
 	case 'Announce':
 		await announce(actor, activity);
 		break;
diff --git a/src/remote/activitypub/kernel/remove/index.ts b/src/remote/activitypub/kernel/remove/index.ts
new file mode 100644
index 0000000000..91b207c80d
--- /dev/null
+++ b/src/remote/activitypub/kernel/remove/index.ts
@@ -0,0 +1,22 @@
+import { IRemoteUser } from '../../../../models/user';
+import { IRemove } from '../../type';
+import { resolveNote } from '../../models/note';
+import { removePinned } from '../../../../services/i/pin';
+
+export default async (actor: IRemoteUser, activity: IRemove): Promise<void> => {
+	if ('actor' in activity && actor.uri !== activity.actor) {
+		throw new Error('invalid actor');
+	}
+
+	if (activity.target == null) {
+		throw new Error('target is null');
+	}
+
+	if (activity.target === actor.featured) {
+		const note = await resolveNote(activity.object);
+		await removePinned(actor, note._id);
+		return;
+	}
+
+	throw new Error(`unknown target: ${activity.target}`);
+};
diff --git a/src/remote/activitypub/models/note.ts b/src/remote/activitypub/models/note.ts
index b4afda765a..d49cf53079 100644
--- a/src/remote/activitypub/models/note.ts
+++ b/src/remote/activitypub/models/note.ts
@@ -56,7 +56,7 @@ export async function createNote(value: any, resolver?: Resolver, silent = false
 	log(`Creating the Note: ${note.id}`);
 
 	// 投稿者をフェッチ
-	const actor = await resolvePerson(note.attributedTo) as IRemoteUser;
+	const actor = await resolvePerson(note.attributedTo, null, resolver) as IRemoteUser;
 
 	// 投稿者が凍結されていたらスキップ
 	if (actor.isSuspended) {
@@ -73,7 +73,7 @@ export async function createNote(value: any, resolver?: Resolver, silent = false
 			visibility = 'followers';
 		} else {
 			visibility = 'specified';
-			visibleUsers = await Promise.all(note.to.map(uri => resolvePerson(uri)));
+			visibleUsers = await Promise.all(note.to.map(uri => resolvePerson(uri, null, resolver)));
 		}
 	}
 	//#endergion
diff --git a/src/remote/activitypub/models/person.ts b/src/remote/activitypub/models/person.ts
index dff38f5460..ee95e43ad3 100644
--- a/src/remote/activitypub/models/person.ts
+++ b/src/remote/activitypub/models/person.ts
@@ -3,15 +3,16 @@ import { toUnicode } from 'punycode';
 import * as debug from 'debug';
 
 import config from '../../../config';
-import User, { validateUsername, isValidName, IUser, IRemoteUser } from '../../../models/user';
+import User, { validateUsername, isValidName, IUser, IRemoteUser, isRemoteUser } from '../../../models/user';
 import Resolver from '../resolver';
 import { resolveImage } from './image';
-import { isCollectionOrOrderedCollection, IPerson } from '../type';
+import { isCollectionOrOrderedCollection, isCollection, IPerson } from '../type';
 import { IDriveFile } from '../../../models/drive-file';
 import Meta from '../../../models/meta';
 import htmlToMFM from '../../../mfm/html-to-mfm';
 import { updateUserStats } from '../../../services/update-chart';
 import { URL } from 'url';
+import { resolveNote } from './note';
 
 const log = debug('misskey:activitypub');
 
@@ -155,6 +156,7 @@ export async function createPerson(uri: string, resolver?: Resolver): Promise<IU
 			},
 			inbox: person.inbox,
 			sharedInbox: person.sharedInbox,
+			featured: person.featured,
 			endpoints: person.endpoints,
 			uri: person.id,
 			url: person.url,
@@ -211,6 +213,7 @@ export async function createPerson(uri: string, resolver?: Resolver): Promise<IU
 	user.bannerUrl = bannerUrl;
 	//#endregion
 
+	await updateFeatured(user._id).catch(err => console.log(err));
 	return user;
 }
 
@@ -282,6 +285,7 @@ export async function updatePerson(uri: string, resolver?: Resolver, hint?: obje
 			updatedAt: new Date(),
 			inbox: person.inbox,
 			sharedInbox: person.sharedInbox,
+			featured: person.featured,
 			avatarId: avatar ? avatar._id : null,
 			bannerId: banner ? banner._id : null,
 			avatarUrl: (avatar && avatar.metadata.thumbnailUrl) ? avatar.metadata.thumbnailUrl : (avatar && avatar.metadata.url) ? avatar.metadata.url : null,
@@ -303,6 +307,8 @@ export async function updatePerson(uri: string, resolver?: Resolver, hint?: obje
 			},
 		}
 	});
+
+	await updateFeatured(exist._id).catch(err => console.log(err));
 }
 
 /**
@@ -311,7 +317,7 @@ export async function updatePerson(uri: string, resolver?: Resolver, hint?: obje
  * Misskeyに対象のPersonが登録されていればそれを返し、そうでなければ
  * リモートサーバーからフェッチしてMisskeyに登録しそれを返します。
  */
-export async function resolvePerson(uri: string, verifier?: string): Promise<IUser> {
+export async function resolvePerson(uri: string, verifier?: string, resolver?: Resolver): Promise<IUser> {
 	if (typeof uri !== 'string') throw 'uri is not string';
 
 	//#region このサーバーに既に登録されていたらそれを返す
@@ -323,5 +329,37 @@ export async function resolvePerson(uri: string, verifier?: string): Promise<IUs
 	//#endregion
 
 	// リモートサーバーからフェッチしてきて登録
-	return await createPerson(uri);
+	if (resolver == null) resolver = new Resolver();
+	return await createPerson(uri, resolver);
+}
+
+export async function updateFeatured(userId: mongo.ObjectID) {
+	const user = await User.findOne({ _id: userId });
+	if (!isRemoteUser(user)) return;
+	if (!user.featured) return;
+
+	log(`Updating the featured: ${user.uri}`);
+
+	const resolver = new Resolver();
+
+	// Resolve to (Ordered)Collection Object
+	const collection = await resolver.resolveCollection(user.featured);
+	if (!isCollectionOrOrderedCollection(collection)) throw new Error(`Object is not Collection or OrderedCollection`);
+
+	// Resolve to Object(may be Note) arrays
+	const unresolvedItems = isCollection(collection) ? collection.items : collection.orderedItems;
+	const items = await resolver.resolve(unresolvedItems);
+	if (!Array.isArray(items)) throw new Error(`Collection items is not an array`);
+
+	// Resolve and regist Notes
+	const featuredNotes = await Promise.all(items
+		.filter(item => item.type === 'Note')
+		.slice(0, 5)
+		.map(item => resolveNote(item, resolver)));
+
+	await User.update({ _id: user._id }, {
+		$set: {
+			pinnedNoteIds: featuredNotes.map(note => note._id)
+		}
+	});
 }
diff --git a/src/remote/activitypub/resolver.ts b/src/remote/activitypub/resolver.ts
index e1c12e7e62..215e5e8704 100644
--- a/src/remote/activitypub/resolver.ts
+++ b/src/remote/activitypub/resolver.ts
@@ -19,11 +19,11 @@ export default class Resolver {
 
 		switch (collection.type) {
 		case 'Collection':
-			collection.objects = collection.object.items;
+			collection.objects = collection.items;
 			break;
 
 		case 'OrderedCollection':
-			collection.objects = collection.object.orderedItems;
+			collection.objects = collection.orderedItems;
 			break;
 
 		default:
diff --git a/src/remote/activitypub/type.ts b/src/remote/activitypub/type.ts
index 7bbea5fd18..5c06ee4ffe 100644
--- a/src/remote/activitypub/type.ts
+++ b/src/remote/activitypub/type.ts
@@ -91,6 +91,14 @@ export interface IReject extends IActivity {
 	type: 'Reject';
 }
 
+export interface IAdd extends IActivity {
+	type: 'Add';
+}
+
+export interface IRemove extends IActivity {
+	type: 'Remove';
+}
+
 export interface ILike extends IActivity {
 	type: 'Like';
 	_misskey_reaction: string;
@@ -109,5 +117,7 @@ export type Object =
 	IFollow |
 	IAccept |
 	IReject |
+	IAdd |
+	IRemove |
 	ILike |
 	IAnnounce;
diff --git a/src/server/api/endpoints/i/pin.ts b/src/server/api/endpoints/i/pin.ts
index f9ae032b11..bf729ca091 100644
--- a/src/server/api/endpoints/i/pin.ts
+++ b/src/server/api/endpoints/i/pin.ts
@@ -1,8 +1,7 @@
 import $ from 'cafy'; import ID from '../../../../misc/cafy-id';
-import User, { ILocalUser } from '../../../../models/user';
-import Note from '../../../../models/note';
+import { ILocalUser } from '../../../../models/user';
 import { pack } from '../../../../models/user';
-import { deliverPinnedChange } from '../../../../services/i/pin';
+import { addPinned } from '../../../../services/i/pin';
 import getParams from '../../get-params';
 
 export const meta = {
@@ -27,41 +26,18 @@ export default async (params: any, user: ILocalUser) => new Promise(async (res,
 	const [ps, psErr] = getParams(meta, params);
 	if (psErr) return rej(psErr);
 
-	// Fetch pinee
-	const note = await Note.findOne({
-		_id: ps.noteId,
-		userId: user._id
-	});
-
-	if (note === null) {
-		return rej('note not found');
+	// Processing
+	try {
+		await addPinned(user, ps.noteId);
+	} catch (e) {
+		return rej(e.message);
 	}
 
-	const pinnedNoteIds = user.pinnedNoteIds || [];
-
-	if (pinnedNoteIds.length > 5) {
-		return rej('cannot pin more notes');
-	}
-
-	if (pinnedNoteIds.some(id => id.equals(note._id))) {
-		return rej('already exists');
-	}
-
-	pinnedNoteIds.unshift(note._id);
-
-	await User.update(user._id, {
-		$set: {
-			pinnedNoteIds: pinnedNoteIds
-		}
-	});
-
+	// Serialize
 	const iObj = await pack(user, user, {
 		detail: true
 	});
 
 	// Send response
 	res(iObj);
-
-	// Send Add to followers
-	deliverPinnedChange(user._id, note._id, true);
 });
diff --git a/src/server/api/endpoints/i/unpin.ts b/src/server/api/endpoints/i/unpin.ts
index 82625ae5fb..2a81993e4b 100644
--- a/src/server/api/endpoints/i/unpin.ts
+++ b/src/server/api/endpoints/i/unpin.ts
@@ -1,8 +1,7 @@
 import $ from 'cafy'; import ID from '../../../../misc/cafy-id';
-import User, { ILocalUser } from '../../../../models/user';
-import Note from '../../../../models/note';
+import { ILocalUser } from '../../../../models/user';
 import { pack } from '../../../../models/user';
-import { deliverPinnedChange } from '../../../../services/i/pin';
+import { removePinned } from '../../../../services/i/pin';
 import getParams from '../../get-params';
 
 export const meta = {
@@ -27,31 +26,18 @@ export default async (params: any, user: ILocalUser) => new Promise(async (res,
 	const [ps, psErr] = getParams(meta, params);
 	if (psErr) return rej(psErr);
 
-	// Fetch unpinee
-	const note = await Note.findOne({
-		_id: ps.noteId,
-		userId: user._id
-	});
-
-	if (note === null) {
-		return rej('note not found');
+	// Processing
+	try {
+		await removePinned(user, ps.noteId);
+	} catch (e) {
+		return rej(e.message);
 	}
 
-	const pinnedNoteIds = (user.pinnedNoteIds || []).filter(id => !id.equals(note._id));
-
-	await User.update(user._id, {
-		$set: {
-			pinnedNoteIds: pinnedNoteIds
-		}
-	});
-
+	// Serialize
 	const iObj = await pack(user, user, {
 		detail: true
 	});
 
 	// Send response
 	res(iObj);
-
-	// Send Remove to followers
-	deliverPinnedChange(user._id, note._id, false);
 });
diff --git a/src/services/i/pin.ts b/src/services/i/pin.ts
index 8b7287e68d..a39cc1e597 100644
--- a/src/services/i/pin.ts
+++ b/src/services/i/pin.ts
@@ -1,12 +1,83 @@
 import config from '../../config';
 import * as mongo from 'mongodb';
-import User, { isLocalUser, isRemoteUser, ILocalUser } from '../../models/user';
+import User, { isLocalUser, isRemoteUser, ILocalUser, IUser } from '../../models/user';
+import Note from '../../models/note';
 import Following from '../../models/following';
 import renderAdd from '../../remote/activitypub/renderer/add';
 import renderRemove from '../../remote/activitypub/renderer/remove';
 import packAp from '../../remote/activitypub/renderer';
 import { deliver } from '../../queue';
 
+/**
+ * 指定した投稿をピン留めします
+ * @param user
+ * @param noteId
+ */
+export async function addPinned(user: IUser, noteId: mongo.ObjectID) {
+	// Fetch pinee
+	const note = await Note.findOne({
+		_id: noteId,
+		userId: user._id
+	});
+
+	if (note === null) {
+		throw new Error('note not found');
+	}
+
+	const pinnedNoteIds = user.pinnedNoteIds || [];
+
+	if (pinnedNoteIds.length > 5) {
+		throw new Error('cannot pin more notes');
+	}
+
+	if (pinnedNoteIds.some(id => id.equals(note._id))) {
+		throw new Error('already exists');
+	}
+
+	pinnedNoteIds.unshift(note._id);
+
+	await User.update(user._id, {
+		$set: {
+			pinnedNoteIds: pinnedNoteIds
+		}
+	});
+
+	// Deliver to remote followers
+	if (isLocalUser(user)) {
+		deliverPinnedChange(user._id, note._id, true);
+	}
+}
+
+/**
+ * 指定した投稿のピン留めを解除します
+ * @param user
+ * @param noteId
+ */
+export async function removePinned(user: IUser, noteId: mongo.ObjectID) {
+	// Fetch unpinee
+	const note = await Note.findOne({
+		_id: noteId,
+		userId: user._id
+	});
+
+	if (note === null) {
+		throw new Error('note not found');
+	}
+
+	const pinnedNoteIds = (user.pinnedNoteIds || []).filter(id => !id.equals(note._id));
+
+	await User.update(user._id, {
+		$set: {
+			pinnedNoteIds: pinnedNoteIds
+		}
+	});
+
+	// Deliver to remote followers
+	if (isLocalUser(user)) {
+		deliverPinnedChange(user._id, noteId, false);
+	}
+}
+
 export async function deliverPinnedChange(userId: mongo.ObjectID, noteId: mongo.ObjectID, isAddition: boolean) {
 	const user = await User.findOne({
 		_id: userId