---
title: "Profile, follow, and affiliate events"
canonical_url: "https://tweetstream.io/docs/profile-follow-affiliate"
last_updated: 2026-09-24
---

# Profile, follow, and affiliate events

Account events carry observed profile, follow, and affiliate relationship changes.

Canonical URL: https://tweetstream.io/docs/profile-follow-affiliate

## Account event types

Route by `op`. Ignore unknown account operations without closing the socket.

### Account event contracts

```typescript
type VerifiedType = 'blue' | 'business' | 'government' | 'verified' | 'none';
type TweetVerifiedLabel = {
  badge: string | null;
  description: string;
  url: string | null;
};

type TweetAuthor = {
  banner?: string;
  bio?: string;
  followersCount?: number;
  followingCount?: number;
  id?: string;
  joinedAt?: number;
  location?: string;
  metrics?: {
    likes?: number;
    tweets?: number;
  };
  // Includes a leading @ when present, for example "@elonmusk".
  handle?: string;
  name?: string;
  platform?: 'twitter' | 'truth_social' | 'binance_square';
  profileImage?: string;
  // The account's own website, when it has one.
  url?: string;
  verifiedLabel?: TweetVerifiedLabel;
  verifiedType?: VerifiedType;
};

type AccountEventActor = TweetAuthor & {
  websiteUrl?: string;
};

type ProfileUpdateEvent = {
  kind: 'PROFILE';
  eventId: string;
  observedAt: number;
  receivedAt?: number;
  actor: AccountEventActor;
  changes: {
    avatar?: string;
    banner?: string;
    bio?: string;
    handle?: string;
    location?: string;
    name?: string;
    verifiedLabel?: TweetVerifiedLabel | null;
    websiteUrl?: string | null;
  };
  previous?: {
    avatar?: string;
    banner?: string;
    bio?: string;
    handle?: string;
    location?: string;
    name?: string;
    verifiedLabel?: TweetVerifiedLabel | null;
    websiteUrl?: string | null;
  };
};

type FollowEvent = {
  kind: 'FOLLOW';
  eventId: string;
  observedAt: number;
  receivedAt?: number;
  actor: AccountEventActor;
  target: AccountEventActor & {
    handle: string;
  };
};

type UnfollowEvent = {
  kind: 'UNFOLLOW';
  eventId: string;
  observedAt: number;
  receivedAt?: number;
  actor: AccountEventActor;
  target: AccountEventActor & {
    handle: string;
  };
};

type AffiliateAccountIdentity = AccountEventActor & {
  id: string;
};

type AffiliateUpdateEvent = {
  action: 'added' | 'removed';
  eventId: string;
  observedAt: number;
  receivedAt?: number;
  organization: AffiliateAccountIdentity;
  member: AffiliateAccountIdentity;
};
```

## account/profile_update

Apply only fields present in `changes`; absence means unchanged.

### Profile update event

```json
{
  "v": 1,
  "t": "account",
  "op": "profile_update",
  "id": "profile-1",
  "ts": 1772000001060,
  "d": {
    "actor": {
      "id": "10228272",
      "handle": "@TeamYouTube",
      "name": "TeamYouTube",
      "profileImage": "https://pbs.twimg.com/media/avatar.jpg",
      "websiteUrl": "https://youtube.com"
    },
    "changes": {
      "handle": "@TeamYouTube",
      "name": "Team YouTube",
      "websiteUrl": "https://youtube.com/new"
    },
    "eventId": "profile-1",
    "kind": "PROFILE",
    "observedAt": 1772000001050,
    "previous": {
      "handle": "@OldTeam"
    },
    "receivedAt": 1772000001050
  }
}
```

## account/follow

Store the observed relationship using stable actor and target identifiers.

### Follow event

```json
{
  "v": 1,
  "t": "account",
  "op": "follow",
  "id": "follow-1",
  "ts": 1772000001060,
  "d": {
    "actor": {
      "id": "10228272",
      "handle": "@TeamYouTube"
    },
    "eventId": "follow-1",
    "kind": "FOLLOW",
    "observedAt": 1772000001050,
    "target": {
      "id": "4398626122",
      "handle": "@OpenAI"
    },
    "receivedAt": 1772000001050
  }
}
```

## account/unfollow

Remove the observed relationship using the same identifiers.

### Unfollow event

```json
{
  "v": 1,
  "t": "account",
  "op": "unfollow",
  "id": "unfollow-1",
  "ts": 1772000001060,
  "d": {
    "actor": {
      "id": "10228272",
      "handle": "@TeamYouTube"
    },
    "eventId": "unfollow-1",
    "kind": "UNFOLLOW",
    "observedAt": 1772000001050,
    "target": {
      "id": "4398626122",
      "handle": "@OpenAI"
    },
    "receivedAt": 1772000001050
  }
}
```

## account/affiliate_update

Apply the `added` or `removed` action idempotently to `(organization.id, member.id)`. Use `eventId` only to suppress an exact replay.

Keyword filters do not apply. Replay stored changes with `GET /api/history?type=AFFILIATE`. History is not a current-list snapshot and does not backfill changes from before the feature was enabled.

### Affiliate update event

```json
{
  "v": 1,
  "t": "account",
  "op": "affiliate_update",
  "id": "affiliate-update-1",
  "ts": 1772000001060,
  "d": {
    "action": "added",
    "organization": {
      "id": "10228272",
      "handle": "@TeamYouTube",
      "name": "TeamYouTube",
      "profileImage": "https://pbs.twimg.com/media/avatar.jpg",
      "websiteUrl": "https://youtube.com"
    },
    "member": {
      "id": "4398626122",
      "handle": "@OpenAI",
      "name": "OpenAI",
      "profileImage": "https://pbs.twimg.com/media/member-avatar.jpg"
    },
    "eventId": "affiliate-update-1",
    "observedAt": 1772000001050,
    "receivedAt": 1772000001050
  }
}
```
