Skip to main content

Overview

External profiles allow users to link their anime list accounts from external services (AniList, MyAnimeList, Kitsu) to AnimeThemes. This enables synchronization of watch lists, favorites, and ratings.

Authentication

Most external profile endpoints require authentication using Laravel Sanctum bearer tokens.
Authorization: Bearer {token}

Supported Sites

AniList

Site ID: 1 - Popular anime and manga tracking service

MyAnimeList

Site ID: 0 - The world’s most active anime and manga community

Kitsu

Site ID: 2 - Modern anime discovery platform

Get User’s External Profiles

GET /api/me/externalprofile
endpoint
Retrieve all external profiles for the authenticated user

Request

curl https://api.animethemes.moe/api/me/externalprofile \
  -H "Authorization: Bearer {token}" \
  -H "Accept: application/json"

Query Parameters

include
string
Include related resources. Available includes:
  • externalentries - Anime entries in the external profile
  • externalentries.anime - Full anime details for each entry
  • externalentries.anime.animethemes - Themes for each anime
  • externalentries.anime.images - Images for each anime
  • user - Profile owner information
Example: include=externalentries,externalentries.anime
fields[externalprofile]
string
Specify which fields to return. Available fields:
  • profile_id - Profile ID
  • name - Profile username
  • site - External site (0=MAL, 1=AniList, 2=Kitsu)
  • visibility - Privacy setting (0=Public, 1=Private)
  • user_id - AnimeThemes user ID
  • synced_at - Last sync timestamp
  • created_at - Creation timestamp
  • updated_at - Last update timestamp
Example: fields[externalprofile]=profile_id,name,site,synced_at

Response

{
  "externalprofiles": [
    {
      "profile_id": 1,
      "name": "johndoe",
      "site": 1,
      "visibility": 0,
      "user_id": 1,
      "external_user_id": 123456,
      "synced_at": "2024-03-03T12:00:00.000000Z",
      "created_at": "2024-01-20T08:00:00.000000Z",
      "updated_at": "2024-03-03T12:00:00.000000Z"
    },
    {
      "profile_id": 2,
      "name": "johndoe",
      "site": 0,
      "visibility": 0,
      "user_id": 1,
      "external_user_id": 789012,
      "synced_at": "2024-03-02T18:30:00.000000Z",
      "created_at": "2024-02-10T14:15:00.000000Z",
      "updated_at": "2024-03-02T18:30:00.000000Z"
    }
  ]
}

List All Public External Profiles

GET /api/externalprofile
endpoint
Retrieve all public external profiles (requires localhost or feature flag)

Request

curl https://api.animethemes.moe/api/externalprofile \
  -H "Accept: application/json"
This endpoint returns public profiles and profiles belonging to the authenticated user.

Query Parameters

filter[site]
integer
Filter by external site:
  • 0 - MyAnimeList
  • 1 - AniList
  • 2 - Kitsu
filter[name]
string
Filter by profile username
filter[visibility]
integer
Filter by visibility:
  • 0 - Public
  • 1 - Private
page[size]
integer
Number of results per page (default: 15, max: 100)
page[number]
integer
Page number for pagination

Response

{
  "externalprofiles": [
    {
      "profile_id": 5,
      "name": "animeuser",
      "site": 1,
      "visibility": 0,
      "user_id": 10,
      "external_user_id": 555666,
      "synced_at": "2024-03-03T10:00:00.000000Z",
      "created_at": "2024-01-15T09:00:00.000000Z",
      "updated_at": "2024-03-03T10:00:00.000000Z"
    }
  ],
  "links": {
    "first": "https://api.animethemes.moe/api/externalprofile?page[number]=1",
    "last": "https://api.animethemes.moe/api/externalprofile?page[number]=5",
    "prev": null,
    "next": "https://api.animethemes.moe/api/externalprofile?page[number]=2"
  },
  "meta": {
    "current_page": 1,
    "from": 1,
    "last_page": 5,
    "per_page": 15,
    "to": 15,
    "total": 72
  }
}

Get External Profile by ID

GET /api/externalprofile/{id}
endpoint
Retrieve a specific external profile by ID

Request

curl https://api.animethemes.moe/api/externalprofile/1 \
  -H "Accept: application/json"

Response

{
  "externalprofile": {
    "profile_id": 1,
    "name": "johndoe",
    "site": 1,
    "visibility": 0,
    "user_id": 1,
    "external_user_id": 123456,
    "synced_at": "2024-03-03T12:00:00.000000Z",
    "created_at": "2024-01-20T08:00:00.000000Z",
    "updated_at": "2024-03-03T12:00:00.000000Z"
  }
}

Create External Profile

POST /api/externalprofile
endpoint
Link a new external profile to the authenticated user
This endpoint requires the AllowExternalProfileManagement feature flag to be enabled.

Request

curl -X POST https://api.animethemes.moe/api/externalprofile \
  -H "Authorization: Bearer {token}" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "myusername",
    "site": 1,
    "visibility": 0,
    "external_user_id": 123456
  }'

Request Body

name
string
required
Username on the external site
site
integer
required
External site identifier:
  • 0 - MyAnimeList
  • 1 - AniList
  • 2 - Kitsu
visibility
integer
required
Profile visibility:
  • 0 - Public (searchable, appears in public listings)
  • 1 - Private (only visible to owner)
external_user_id
integer
User ID on the external platform (optional)

Response

{
  "externalprofile": {
    "profile_id": 3,
    "name": "myusername",
    "site": 1,
    "visibility": 0,
    "user_id": 1,
    "external_user_id": 123456,
    "synced_at": null,
    "created_at": "2024-03-03T15:30:00.000000Z",
    "updated_at": "2024-03-03T15:30:00.000000Z"
  }
}

Update External Profile

PUT /api/externalprofile/{id}
endpoint
Update an existing external profile

Request

curl -X PUT https://api.animethemes.moe/api/externalprofile/1 \
  -H "Authorization: Bearer {token}" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{
    "visibility": 1
  }'

Request Body

name
string
Update username on the external site
visibility
integer
Update profile visibility (0=Public, 1=Private)
external_user_id
integer
Update external user ID

Response

{
  "externalprofile": {
    "profile_id": 1,
    "name": "johndoe",
    "site": 1,
    "visibility": 1,
    "user_id": 1,
    "external_user_id": 123456,
    "synced_at": "2024-03-03T12:00:00.000000Z",
    "created_at": "2024-01-20T08:00:00.000000Z",
    "updated_at": "2024-03-03T15:45:00.000000Z"
  }
}

Delete External Profile

DELETE /api/externalprofile/{id}
endpoint
Permanently delete an external profile

Request

curl -X DELETE https://api.animethemes.moe/api/externalprofile/1 \
  -H "Authorization: Bearer {token}" \
  -H "Accept: application/json"

Response

{
  "message": "External profile deleted successfully"
}

External Profile Data Structure

Core Attributes

  • profile_id: Unique identifier for the external profile
  • name: Username on the external platform
  • site: External platform identifier (0=MAL, 1=AniList, 2=Kitsu)
  • visibility: Privacy setting (0=Public, 1=Private)
  • user_id: Associated AnimeThemes user ID (null for unclaimed profiles)
  • external_user_id: User ID on the external platform
  • synced_at: Timestamp of last synchronization with external service
  • created_at: Profile creation timestamp
  • updated_at: Last update timestamp

Profile Synchronization

External profiles can be synchronized with their external services to import:
  • Watch status (watching, completed, plan to watch, etc.)
  • Ratings and scores
  • Favorite anime
  • Watch history
Profiles can be synced every 3 hours. The synced_at field tracks the last sync time.

Profile URL Format

External profiles are accessible via the client at:
https://animethemes.moe/external/{site}/{profile_name}
Where {site} is:
  • mal - MyAnimeList
  • anilist - AniList
  • kitsu - Kitsu

Available Relations

External profiles support the following includes:
  • externalentries: Anime entries in the list
  • externalentries.anime: Full anime details
  • externalentries.anime.animethemes: Theme songs
  • externalentries.anime.animethemes.animethemeentries.videos: Theme videos
  • externalentries.anime.animethemes.group: Artist/group information
  • externalentries.anime.animethemes.song: Song details
  • externalentries.anime.images: Anime cover images
  • user: Profile owner’s user information

External Entries

External entries represent individual anime in an external profile’s list.

Entry Attributes

  • entry_id: Unique identifier for the entry
  • anime_id: Associated AnimeThemes anime ID
  • profile_id: Parent external profile ID
  • is_favorite: Whether marked as favorite
  • score: User’s rating (float, typically 0-10)
  • watch_status: Watch status enum (watching, completed, plan to watch, etc.)

OAuth Integration

For sites supporting OAuth (AniList, MyAnimeList), users can authenticate and authorize AnimeThemes to access their profiles.

Authorization URLs

Each site provides an authorization URL accessible via the site enum: AniList:
https://anilist.co/api/v2/oauth/authorize?client_id={id}&redirect_uri={uri}&response_type=code
MyAnimeList:
https://myanimelist.net/v1/oauth2/authorize?client_id={id}&redirect_uri={uri}&code_challenge={verifier}&state={state}&response_type=code&code_challenge_method=plain
OAuth tokens are stored securely and never exposed through the API. Access and refresh tokens are hidden attributes.

Profile Visibility

Public Profiles (visibility: 0)

  • Appear in search results
  • Listed in public profile directories
  • Indexed for search
  • Accessible to all users

Private Profiles (visibility: 1)

  • Only visible to the profile owner
  • Not searchable or indexed
  • Not listed in public directories
  • Require authentication to access

Profile Lifecycle

Claimed Profiles

Profiles with a user_id are “claimed” - linked to an AnimeThemes account. These profiles:
  • Persist indefinitely
  • Can be synced with external services
  • Support full CRUD operations

Unclaimed Profiles

Profiles without a user_id are “unclaimed” - created but not linked. These profiles:
  • Are automatically deleted after 7 days
  • Cannot be synced
  • Are typically created during the OAuth flow before completion

Error Responses

401 Unauthorized
error
Missing or invalid authentication token
{
  "message": "Unauthenticated."
}
403 Forbidden
error
User exceeded maximum external profile limit
{
  "message": "You have reached the maximum number of external profiles."
}
404 Not Found
error
External profile not found
{
  "message": "No query results for model [App\\Models\\List\\ExternalProfile]."
}
422 Unprocessable Entity
error
Validation errors
{
  "message": "The given data was invalid.",
  "errors": {
    "site": ["The site field is required."],
    "name": ["The name field is required."]
  }
}

Notes

External profile management is restricted by feature flags and middleware. Contact your administrator if you cannot create or manage profiles.
Synchronization with external services may take several minutes for large lists. The sync job runs in the background.
External profiles support Elasticsearch for fast searching. Only public profiles are indexed.

Build docs developers (and LLMs) love