For developers

Build your own ICQ client

The same API our web clients run on is open to everyone. Plain HTTP and JSON, no keys, no app registration — just a UIN. Use it for a bot, a client for your favourite platform, or a widget on your site.

Base URL https://jimm.online/webapi

Quick start

Three requests to your first message

Working with the API comes down to signing in, going online and an endless event loop.

  1. 1

    Sign in

    POST your UIN and password as a form to /auth/clientLogin. You get back the token token.a.

  2. 2

    Go online

    Call /aim/startSession with that token. You get aimsid — the key to every other method — plus your buddy list.

  3. 3

    Listen

    Poll /aim/fetchEvents in a loop. The request waits up to a minute and returns the moment something happens: a message, a status change, “typing…”.

No UIN yet? Sign up on Jimm.online in a minute. For a bot, create a separate account.

🤖 An echo bot in 20 lines

A working example: the bot goes online and answers every message with its own text. Put in your UIN and password and run it.

import re, time, requests

API = "https://jimm.online/webapi"
UIN, PASSWORD = "123456789", "secret"

def call(path, **params):
    r = requests.get(API + path, params={"f": "json", **params}, timeout=75)
    resp = r.json()["response"]
    if resp["statusCode"] != 200:
        raise RuntimeError(f'{resp["statusCode"]} {resp["statusText"]}')
    return resp["data"]

login = requests.post(API + "/auth/clientLogin", data={
    "s": UIN, "pwd": PASSWORD, "devId": "echo-bot", "f": "json"}).json()
token = login["response"]["data"]["token"]["a"]

aimsid = call("/aim/startSession", a=token, events="im", clientName="EchoBot")["aimsid"]
seq = 0
while True:
    batch = call("/aim/fetchEvents", aimsid=aimsid, seqNum=seq, timeout=60000)
    for ev in batch["events"]:
        if ev["type"] == "im":
            text = re.sub(r"<[^>]+>", "", ev["eventData"]["message"])
            call("/im/sendIM", aimsid=aimsid, t=ev["eventData"]["source"]["aimId"],
                 message="Echo: " + text, offlineIM="true")
    seq = batch["lastSeqNum"]
    time.sleep(batch["timeToNextFetch"] / 1000)

How it works

What to know before the first line of code

The response envelope

Every response is wrapped in {"response": {"statusCode", "statusText", "data"}}. Judge success by statusCode, not the HTTP status: an undelivered message (602) or a rate limit (430) comes back on HTTP 200. The payload is in data.

Token and aimsid

token.a from clientLogin proves who you are. It lasts 24 hours by default, or a year with tokenType=longterm, so you don’t have to keep the password. aimsid from startSession is one particular “online” session: it lives while you poll for events and dies after 150 seconds of silence. One UIN can hold several sessions at once.

Long-polling

There are no websockets: fetchEvents simply holds the request open until there is an event (up to 60 s). After it returns, wait timeToNextFetch ms and ask again with seqNum = lastSeqNum, and you never miss an event. Set your HTTP client’s timeout above 60 s, or it will hang up before the answer arrives.

GET, POST and parameters

Almost every method is a GET with query parameters. The same parameters work as a POSTed form too, except /auth/clientLogin (POST form only) and the icon upload (raw bytes). Choose the response format with f: json (default), xml or amf3. Add c=functionName for JSONP.

From a browser

The API answers with CORS headers, so fetch from a web page works. Use GET methods: they are “simple” requests and need no CORS preflight. Send passwords straight to the API server, never through a third party.

Rate limits

The limits are the same as for regular ICQ clients, and they apply per account, not per connection. Go over and you get statusCode 430 with a Retry-After header (seconds to wait) and a rateLimit event. Don’t retry sooner, or the limit drags on.

House rules

  • Send a meaningful devId and clientName — it helps us help you when something breaks.
  • Bots don’t message people who never wrote to them. Spam accounts get blocked.
  • Don’t store other people’s passwords. Keep the token and ask for the password again when it expires.
  • Call endSession when your client closes, so contacts see you leave right away.

Live console

Try it right here

Sign in with your UIN and every method below gets a “Run” button. Requests go from your browser straight to the API server, like any client’s. The site never sees or stores your password.

The console acts as you: messages you send and buddy list changes are real.

Reference · 33

All methods

Open a method to see its parameters, response and code samples.

Sign-in

Trade a UIN and password for a token. The password travels once; the token does the rest.

POST /auth/clientLogin Sign in with a UIN and password No auth

Checks a UIN and password and returns the token token.a, which startSession takes. The body is a plain application/x-www-form-urlencoded form: the server does not read JSON and answers 400. You can keep the token instead of the password; by default it lives 24 hours.

Parameters

NameDescription
s string · in body required The UIN (or username).
pwd string · in body required The password (or password).
devId string · in body Your client’s name. Shows up in the server log; defaults to WebAIM.
tokenType string · in body Token lifetime: shortterm (24 h, the default), longterm (365 days) or a number of seconds.
f string · in body Response format. A POST sends it in the body. jsonxmlamf3

Errors

  • 330 Wrong UIN or password (statusDetailCode: 3011, HTTP 401).
  • 460 UIN or password missing (HTTP 400).
  • 462 Bad tokenType (HTTP 400).

Example request

curl -X POST "https://jimm.online/webapi/auth/clientLogin" \
  --data-urlencode "s=123456789" \
  --data-urlencode "pwd=$PASSWORD" \
  --data-urlencode "devId=my-client" \
  --data-urlencode "f=json"

Response What response.data holds

{
    "token": {
        "a": "AAAAAGdQ…base64url…",
        "expiresIn": "86400"
    },
    "loginId": "123456789",
    "screenName": "123456789",
    "sessionSecret": "q1w2e3…",
    "hostTime": 1761130000,
    "tokenExpiresIn": 86400
}
#clientLogin · Link to this method
GET /auth/getInfo Check a token Token

Tells whether a saved token is still good and whose it is. Handy at client start-up: anything but 200 means ask for the password again.

Parameters

NameDescription
a string required The token from clientLogin.
reqAuthFreshness integer Maximum age of the sign-in, in seconds (default 86400). Older means 330.
f string Response format: json (default), xml or amf3. Add c=name for JSONP. jsonxmlamf3

Errors

  • 401 Token refused: expired, damaged or not from clientLogin.
  • 330 The sign-in is older than reqAuthFreshness allows.

Example request

curl -G "https://jimm.online/webapi/auth/getInfo" \
  --data-urlencode "a=$TOKEN" \
  --data-urlencode "f=json"

Response What response.data holds

{
    "userData": {
        "loginId": "123456789",
        "displayName": "123456789"
    }
}
#getInfo · Link to this method

Session & events

Going online, long-polling the event stream, and signing off.

GET /aim/startSession Go online Token

Opens a session and puts you online, so your contacts see you arrive. Returns aimsid, which every other method takes. events lists what you want to hear about. The starting state (buddy list, your own info) comes right in the response and again as the first events of the stream. Offline messages arrive as offlineIM events and are deleted from the server as they go, so keep them yourself. Stop polling and the session closes after 150 seconds.

Parameters

NameDescription
a string required The token from clientLogin.
events string Comma-separated events to subscribe to. Defaults to buddylist,presence,im,sentIM.
clientName string Your client’s name.
clientVersion string Your client’s version.
timeout integer Default long-poll timeout, in seconds (60).
f string Response format: json (default), xml or amf3. Add c=name for JSONP. jsonxmlamf3

Errors

  • 401 Token missing or expired.
  • 503 The server could not open a session.

Example request

curl -G "https://jimm.online/webapi/aim/startSession" \
  --data-urlencode "a=$TOKEN" \
  --data-urlencode "f=json"

Response What response.data holds

{
    "aimsid": "0123456789abcdef.123456789",
    "ts": 1761130000,
    "fetchTimeout": 60000,
    "timeToNextFetch": 500,
    "fetchBaseURL": "https://jimm.online/webapi/aim/fetchEvents?aimsid=0123456789abcdef.123456789&seqNum=0",
    "myInfo": {
        "aimId": "123456789",
        "displayId": "123456789",
        "friendly": "123456789",
        "state": "online",
        "userType": "icq",
        "bot": false,
        "service": "icq",
        "capabilities": [],
        "buddyIcon": "https://jimm.online/webapi/expressions/get?t=123456789&type=buddyIcon"
    },
    "events": {
        "buddylist": {
            "groups": [
                {
                    "name": "Друзья",
                    "id": 1,
                    "buddies": [
                        {
                            "aimId": "987654321",
                            "displayId": "987654321",
                            "friendly": "Вася",
                            "state": "online",
                            "statusMsg": "на связи",
                            "onlineTime": 1761120000,
                            "userType": "icq",
                            "service": "icq",
                            "buddyIcon": "https://jimm.online/webapi/expressions/get?t=987654321&type=buddyIcon",
                            "bot": false
                        }
                    ]
                }
            ]
        }
    },
    "wellKnownUrls": {
        "webApiBase": "https://jimm.online/webapi/",
        "fetchBaseURL": "https://jimm.online/webapi/aim/fetchEvents"
    }
}
#startSession · Link to this method
GET /aim/fetchEvents Fetch events (long-poll) aimsid

The client’s main loop. The request waits until there are events newer than seqNum or timeout runs out, then returns them as a batch (possibly empty). Make the next request with seqNum = lastSeqNum after timeToNextFetch ms. Every call keeps the session alive. The server keeps up to the last 1000 events.

Parameters

NameDescription
aimsid string required Session id from startSession.
seqNum integer The last event number you saw; 0 for everything.
timeout integer How long to wait, in milliseconds, 60000 at most.
f string Response format: json (default), xml or amf3. Add c=name for JSONP. jsonxmlamf3

Errors

  • 401 The session is closed or expired. Start over with startSession.

Example request

curl -G "https://jimm.online/webapi/aim/fetchEvents" \
  --data-urlencode "aimsid=$AIMSID" \
  --data-urlencode "f=json"

Response What response.data holds

{
    "events": [
        {
            "type": "im",
            "seqNum": 7,
            "timestamp": 1761130042,
            "eventData": {
                "source": {
                    "aimId": "987654321",
                    "displayId": "987654321",
                    "friendly": "Вася",
                    "userType": "icq",
                    "state": "online"
                },
                "message": "Привет! Как дела?",
                "msgId": "9c2e41d07a3b55f1",
                "timestamp": 1761130042,
                "imf": "plain",
                "autoresponse": false
            }
        }
    ],
    "lastSeqNum": 7,
    "timeToNextFetch": 500,
    "fetchBaseURL": "https://jimm.online/webapi/aim/fetchEvents?aimsid=0123456789abcdef.123456789&seqNum=7"
}
#fetchEvents · Link to this method
GET /aim/endSession Sign off aimsid

Closes the session; your contacts see you leave. In a browser, navigator.sendBeacon from pagehide works well.

Parameters

NameDescription
aimsid string required Session id from startSession.
f string Response format: json (default), xml or amf3. Add c=name for JSONP. jsonxmlamf3

Example request

curl -G "https://jimm.online/webapi/aim/endSession" \
  --data-urlencode "aimsid=$AIMSID" \
  --data-urlencode "f=json"

Response What response.data holds

{}
#endSession · Link to this method
GET /aim/startOSCARSession Address and cookie for native OSCAR Token

For a full OSCAR-over-TCP client: sign in over HTTP, then connect straight to BOS with the returned host, port and cookie, skipping the in-protocol password step.

Parameters

NameDescription
a string required The token from clientLogin.
useTLS boolean Ask for the TLS port. Falls back to plain if the server has none.
f string Response format: json (default), xml or amf3. Add c=name for JSONP. jsonxmlamf3

Errors

  • 401 Token missing or expired.

Example request

curl -G "https://jimm.online/webapi/aim/startOSCARSession" \
  --data-urlencode "a=$TOKEN" \
  --data-urlencode "f=json"

Response What response.data holds

{
    "host": "icq.jimm.online",
    "port": 5190,
    "cookie": "AAAAAGdQ…base64…"
}
#startOSCARSession · Link to this method

Messaging

Sending messages, the typing indicator and this session’s history.

GET /im/sendIM Send a message aimsid

Accepts GET or a POSTed form. From a browser prefer GET: it is a “simple” request and needs no CORS preflight. Pass offlineIM=true so a message to someone who is offline is stored and delivered when they sign in. It changes nothing for an online recipient, so it is safe to always send. Your own sessions get a copy as a sentIM event.

Parameters

NameDescription
aimsid string required Session id from startSession.
t string required Recipient’s UIN.
message string required The text. Up to ~4000 bytes.
offlineIM boolean Store it if the recipient is offline.
autoResponse string 1 marks an auto-reply (an away message).
f string Response format: json (default), xml or amf3. Add c=name for JSONP. jsonxmlamf3

Errors

  • 602 Not delivered: the recipient is offline and no offlineIM, their offline box is full, or you blocked them. HTTP is still 200 — read statusCode.
  • 430 Too fast. Wait Retry-After seconds.
  • 400 Missing t or message.

Example request

curl -G "https://jimm.online/webapi/im/sendIM" \
  --data-urlencode "aimsid=$AIMSID" \
  --data-urlencode "t=987654321" \
  --data-urlencode "message=Привет! 👋" \
  --data-urlencode "offlineIM=true" \
  --data-urlencode "f=json"

Response What response.data holds

{
    "msgId": "5f1c0e2a-9b3d-4c11-8000-0a1b2c3d4e5f",
    "state": "delivered",
    "timestamp": 1761130050
}
#sendIM · Link to this method
GET /im/setTyping Typing indicator aimsid

Tells the other side you are typing. Sent only if their client asked for typing notices; otherwise the server quietly answers HTTP 200 with an empty body, which is not an error. Don’t send more than once every couple of seconds.

Parameters

NameDescription
aimsid string required Session id from startSession.
t string required The other side’s UIN.
typingStatus string typing, typed (paused) or none (cleared). typingtypednone
f string Response format: json (default), xml or amf3. Add c=name for JSONP. jsonxmlamf3

Example request

curl -G "https://jimm.online/webapi/im/setTyping" \
  --data-urlencode "aimsid=$AIMSID" \
  --data-urlencode "t=987654321" \
  --data-urlencode "f=json"

Response What response.data holds

{}
#setTyping · Link to this method
GET /imlog/fetchStoredIMs This session’s history aimsid

Messages with one person that went through this session. The server keeps no history across sessions: sign in again and the list starts empty. Keep permanent history on the client.

Parameters

NameDescription
aimsid string required Session id from startSession.
to string required The other side’s UIN.
nToGet integer How many to return.
sortOrder string asc or desc. ascdesc
startTime integer Not before (unix time).
endTime integer Not after (unix time).
f string Response format: json (default), xml or amf3. Add c=name for JSONP. jsonxmlamf3

Errors

  • 400 Missing to.

Example request

curl -G "https://jimm.online/webapi/imlog/fetchStoredIMs" \
  --data-urlencode "aimsid=$AIMSID" \
  --data-urlencode "to=987654321" \
  --data-urlencode "f=json"

Response What response.data holds

{
    "msgs": [
        {
            "sender": "987654321",
            "message": "Привет!",
            "msgId": "9c2e41d07a3b55f1",
            "date": 1761130042
        }
    ]
}
#fetchStoredIMs · Link to this method

Presence & profile

Your own status, x-status and profile, and other people’s presence.

GET /presence/get Presence of people or the whole list aimsid

With bl=1, the whole buddy list with live presence. With t, the presence of given people (up to 32), whether or not they are on your list — good for a preview card before adding someone.

Parameters

NameDescription
aimsid string required Session id from startSession.
t string UINs, comma-separated (or repeat t). Up to 32.
bl string 1 returns the whole buddy list by group.
profileMsg string 1 adds the profile text.
mdir boolean Add directory data (name, city).
f string Response format: json (default), xml or amf3. Add c=name for JSONP. jsonxmlamf3

Example request

curl -G "https://jimm.online/webapi/presence/get" \
  --data-urlencode "aimsid=$AIMSID" \
  --data-urlencode "f=json"

Response What response.data holds

{
    "users": [
        {
            "aimId": "987654321",
            "displayId": "987654321",
            "friendly": "Вася",
            "state": "online",
            "statusMsg": "на связи",
            "onlineTime": 1761120000,
            "userType": "icq",
            "service": "icq",
            "buddyIcon": "https://jimm.online/webapi/expressions/get?t=987654321&type=buddyIcon"
        }
    ]
}
#getPresence · Link to this method
GET /presence/setState Change status aimsid

The main status: online, away, do not disturb, occupied, invisible. Away can carry an away message.

Parameters

NameDescription
aimsid string required Session id from startSession.
view string required The new status (or state). onlineawaydndoccupiedinvisible
awayMsg string Away message (for away).
f string Response format: json (default), xml or amf3. Add c=name for JSONP. jsonxmlamf3

Errors

  • 400 Unknown status.

Example request

curl -G "https://jimm.online/webapi/presence/setState" \
  --data-urlencode "aimsid=$AIMSID" \
  --data-urlencode "view=away" \
  --data-urlencode "f=json"

Response What response.data holds

{
    "aimId": "123456789",
    "displayId": "123456789",
    "state": "away",
    "awayMsg": "Скоро вернусь",
    "statusMsg": "",
    "userType": "icq",
    "onlineTime": 1761130000
}
#setState · Link to this method
GET /presence/setStatus Status text and x-status aimsid

Sets the line under your name and the mood icon (x-status). A parameter changes only if present: mood= with an empty value clears the x-status, no mood at all leaves it alone. Mood codes are in the reference.

Parameters

NameDescription
aimsid string required Session id from startSession.
statusMsg string Status text. Empty clears it.
mood string X-status code. Empty clears it.
f string Response format: json (default), xml or amf3. Add c=name for JSONP. jsonxmlamf3

Errors

  • 400 Unknown mood or text too long.

Example request

curl -G "https://jimm.online/webapi/presence/setStatus" \
  --data-urlencode "aimsid=$AIMSID" \
  --data-urlencode "f=json"

Response What response.data holds

{}
#setStatus · Link to this method
GET /presence/getProfile A user’s profile aimsid

Profile text (“about me”). Without sn, your own.

Parameters

NameDescription
aimsid string required Session id from startSession.
sn string Whose profile.
f string Response format: json (default), xml or amf3. Add c=name for JSONP. jsonxmlamf3

Example request

curl -G "https://jimm.online/webapi/presence/getProfile" \
  --data-urlencode "aimsid=$AIMSID" \
  --data-urlencode "f=json"

Response What response.data holds

{
    "screenName": "987654321",
    "profile": "Сижу в аське с 2003 года",
    "lastUpdated": 0
}
#getProfile · Link to this method
GET /presence/setProfile Update your profile aimsid

Replaces your profile text. Up to 4 KB.

Parameters

NameDescription
aimsid string required Session id from startSession.
profile string required The new text.
f string Response format: json (default), xml or amf3. Add c=name for JSONP. jsonxmlamf3

Errors

  • 400 Over 4 KB.

Example request

curl -G "https://jimm.online/webapi/presence/setProfile" \
  --data-urlencode "aimsid=$AIMSID" \
  --data-urlencode "profile=Сижу в аське с 2003 года" \
  --data-urlencode "f=json"

Response What response.data holds

{}
#setProfile · Link to this method

Buddy list

The buddy list lives on the server: groups, buddies, nicknames. Every change arrives as a buddylist event in all your sessions.

GET /buddylist/addBuddy Add a buddy aimsid

Adds someone to a group (Buddies by default), creating the group if needed. An empty data means success; otherwise data.resultCode says why, e.g. alreadyExists.

Parameters

NameDescription
aimsid string required Session id from startSession.
buddy string required The UIN.
group string The group.
preAuthorized boolean Pre-authorize this person to add you.
authorizationMsg string Authorization request text.
f string Response format: json (default), xml or amf3. Add c=name for JSONP. jsonxmlamf3

Errors

  • 400 Missing buddy.

Example request

curl -G "https://jimm.online/webapi/buddylist/addBuddy" \
  --data-urlencode "aimsid=$AIMSID" \
  --data-urlencode "buddy=987654321" \
  --data-urlencode "f=json"

Response What response.data holds

{}
#addBuddy · Link to this method
GET /buddylist/removeBuddy Remove a buddy aimsid

Removes a buddy from one group, or from all with allGroups=1.

Parameters

NameDescription
aimsid string required Session id from startSession.
buddy string required The UIN.
group string Which group.
allGroups boolean Remove from every group.
f string Response format: json (default), xml or amf3. Add c=name for JSONP. jsonxmlamf3

Example request

curl -G "https://jimm.online/webapi/buddylist/removeBuddy" \
  --data-urlencode "aimsid=$AIMSID" \
  --data-urlencode "buddy=987654321" \
  --data-urlencode "f=json"

Response What response.data holds

{}
#removeBuddy · Link to this method
GET /buddylist/moveBuddy Move a buddy aimsid

Moves a buddy to another group and/or before another buddy.

Parameters

NameDescription
aimsid string required Session id from startSession.
buddy string required The UIN.
group string required Current group.
newGroup string New group.
beforeBuddy string Place before this UIN.
f string Response format: json (default), xml or amf3. Add c=name for JSONP. jsonxmlamf3

Example request

curl -G "https://jimm.online/webapi/buddylist/moveBuddy" \
  --data-urlencode "aimsid=$AIMSID" \
  --data-urlencode "buddy=987654321" \
  --data-urlencode "group=Друзья" \
  --data-urlencode "f=json"

Response What response.data holds

{}
#moveBuddy · Link to this method
GET /buddylist/setBuddyAttribute Buddy nickname aimsid

Your private name for a buddy (only you see it). Comes back as friendly.

Parameters

NameDescription
aimsid string required Session id from startSession.
t string required The UIN.
friendly string The nickname. Empty clears it.
f string Response format: json (default), xml or amf3. Add c=name for JSONP. jsonxmlamf3

Example request

curl -G "https://jimm.online/webapi/buddylist/setBuddyAttribute" \
  --data-urlencode "aimsid=$AIMSID" \
  --data-urlencode "t=987654321" \
  --data-urlencode "f=json"

Response What response.data holds

{}
#setBuddyAttribute · Link to this method
GET /buddylist/addGroup Create a group aimsid

Creates a group. Calling it twice is harmless.

Parameters

NameDescription
aimsid string required Session id from startSession.
group string required The name.
f string Response format: json (default), xml or amf3. Add c=name for JSONP. jsonxmlamf3

Example request

curl -G "https://jimm.online/webapi/buddylist/addGroup" \
  --data-urlencode "aimsid=$AIMSID" \
  --data-urlencode "group=Работа" \
  --data-urlencode "f=json"

Response What response.data holds

{}
#addGroup · Link to this method
GET /buddylist/renameGroup Rename a group aimsid

Renames a group.

Parameters

NameDescription
aimsid string required Session id from startSession.
oldGroup string required Current name.
newGroup string required New name.
f string Response format: json (default), xml or amf3. Add c=name for JSONP. jsonxmlamf3

Example request

curl -G "https://jimm.online/webapi/buddylist/renameGroup" \
  --data-urlencode "aimsid=$AIMSID" \
  --data-urlencode "oldGroup=Работа" \
  --data-urlencode "newGroup=Коллеги" \
  --data-urlencode "f=json"

Response What response.data holds

{}
#renameGroup · Link to this method
GET /buddylist/removeGroup Remove a group aimsid

Removes a group.

Parameters

NameDescription
aimsid string required Session id from startSession.
group string required The name.
f string Response format: json (default), xml or amf3. Add c=name for JSONP. jsonxmlamf3

Example request

curl -G "https://jimm.online/webapi/buddylist/removeGroup" \
  --data-urlencode "aimsid=$AIMSID" \
  --data-urlencode "group=Коллеги" \
  --data-urlencode "f=json"

Response What response.data holds

{}
#removeGroup · Link to this method
GET /buddylist/setGroupAttribute Collapse or expand a group aimsid

Stores whether a group is collapsed, so all your clients show it the same way.

Parameters

NameDescription
aimsid string required Session id from startSession.
group string required The name.
collapsed boolean required Collapsed or not.
f string Response format: json (default), xml or amf3. Add c=name for JSONP. jsonxmlamf3

Example request

curl -G "https://jimm.online/webapi/buddylist/setGroupAttribute" \
  --data-urlencode "aimsid=$AIMSID" \
  --data-urlencode "group=Друзья" \
  --data-urlencode "collapsed=true" \
  --data-urlencode "f=json"

Response What response.data holds

{}
#setGroupAttribute · Link to this method
GET /aim/addTempBuddy Watch presence without adding aimsid

Subscribes this session to presence of people not on your list, until the session ends. Up to 160 people.

Parameters

NameDescription
aimsid string required Session id from startSession.
t string required Comma-separated UINs.
f string Response format: json (default), xml or amf3. Add c=name for JSONP. jsonxmlamf3

Errors

  • 400 Empty list or over 160.

Example request

curl -G "https://jimm.online/webapi/aim/addTempBuddy" \
  --data-urlencode "aimsid=$AIMSID" \
  --data-urlencode "t=987654321" \
  --data-urlencode "f=json"

Response What response.data holds

{}
#addTempBuddy · Link to this method
GET /aim/removeTempBuddy Stop watching aimsid

Undoes addTempBuddy.

Parameters

NameDescription
aimsid string required Session id from startSession.
t string required Comma-separated UINs.
f string Response format: json (default), xml or amf3. Add c=name for JSONP. jsonxmlamf3

Example request

curl -G "https://jimm.online/webapi/aim/removeTempBuddy" \
  --data-urlencode "aimsid=$AIMSID" \
  --data-urlencode "t=987654321" \
  --data-urlencode "f=json"

Response What response.data holds

{}
#removeTempBuddy · Link to this method

Preferences & privacy

Server-side account preferences and the allow and block lists.

GET /preference/get Account preferences aimsid

Server-side preferences: 1 on, 0 off. The same values come as the preference event.

Parameters

NameDescription
aimsid string required Session id from startSession.
f string Response format: json (default), xml or amf3. Add c=name for JSONP. jsonxmlamf3

Example request

curl -G "https://jimm.online/webapi/preference/get" \
  --data-urlencode "aimsid=$AIMSID" \
  --data-urlencode "f=json"

Response What response.data holds

{
    "showGroups": 1,
    "showOffLineBuddies": 1,
    "acceptOffLineIM": 1,
    "discloseTyping": 1,
    "viewIMTimestamps": 1
}
#getPreferences · Link to this method
GET /preference/set Change preferences aimsid

Each preference is its own parameter, 1 or 0. Returns only what changed.

Parameters

NameDescription
aimsid string required Session id from startSession.
acceptOffLineIM string Accept offline messages.
discloseTyping string Show others that you are typing.
showOffLineBuddies string Show offline buddies.
f string Response format: json (default), xml or amf3. Add c=name for JSONP. jsonxmlamf3

Example request

curl -G "https://jimm.online/webapi/preference/set" \
  --data-urlencode "aimsid=$AIMSID" \
  --data-urlencode "f=json"

Response What response.data holds

{
    "discloseTyping": 1
}
#setPreferences · Link to this method
GET /preference/getPermitDeny Who can reach you aimsid

The privacy mode and the allow and block lists.

Parameters

NameDescription
aimsid string required Session id from startSession.
f string Response format: json (default), xml or amf3. Add c=name for JSONP. jsonxmlamf3

Example request

curl -G "https://jimm.online/webapi/preference/getPermitDeny" \
  --data-urlencode "aimsid=$AIMSID" \
  --data-urlencode "f=json"

Response What response.data holds

{
    "pdMode": "denySome",
    "blocks": [
        "555555"
    ]
}
#getPermitDeny · Link to this method
GET /preference/setPermitDeny Blocking and privacy mode aimsid

Changes the mode and/or adds and removes people from the lists. Lists are comma-separated UINs.

Parameters

NameDescription
aimsid string required Session id from startSession.
pdMode string permitAll everyone, denySome all but blocked, permitSome only allowed, permitOnList only buddies, denyAll nobody. permitAlldenySomepermitSomepermitOnListdenyAll
pdBlock string Block.
pdBlockRemove string Unblock.
pdAllow string Allow.
pdAllowRemove string Remove from allowed.
f string Response format: json (default), xml or amf3. Add c=name for JSONP. jsonxmlamf3

Errors

  • 400 Unknown pdMode.

Example request

curl -G "https://jimm.online/webapi/preference/setPermitDeny" \
  --data-urlencode "aimsid=$AIMSID" \
  --data-urlencode "f=json"

Response What response.data holds

{
    "pdMode": "denySome",
    "blocks": [
        "555555"
    ]
}
#setPermitDeny · Link to this method

Member directory

The member directory: search by UIN or name, and directory profiles.

GET /memberDir/search Find people aimsid

match is comma-separated key=value pairs. keyword finds an exact UIN plus keyword matches; firstName and lastName search names. You never appear in your own results.

Parameters

NameDescription
aimsid string required Session id from startSession.
match string required What to look for.
nToGet integer How many (default 100).
nToSkip integer How many to skip.
f string Response format: json (default), xml or amf3. Add c=name for JSONP. jsonxmlamf3

Example request

curl -G "https://jimm.online/webapi/memberDir/search" \
  --data-urlencode "aimsid=$AIMSID" \
  --data-urlencode "match=keyword=987654321" \
  --data-urlencode "f=json"

Response What response.data holds

{
    "results": {
        "nTotal": 1,
        "nSkipped": 0,
        "nProfiles": 1,
        "infoArray": [
            {
                "profile": {
                    "aimId": "987654321",
                    "displayId": "987654321",
                    "firstName": "Василий",
                    "lastName": "Пупкин",
                    "city": "Киев",
                    "country": "UA"
                }
            }
        ]
    }
}
#memberDirSearch · Link to this method
GET /memberDir/get Directory profile aimsid

Directory profiles (name, city, country) of up to 20 people. Without t, your own.

Parameters

NameDescription
aimsid string required Session id from startSession.
t string Comma-separated UINs.
f string Response format: json (default), xml or amf3. Add c=name for JSONP. jsonxmlamf3

Example request

curl -G "https://jimm.online/webapi/memberDir/get" \
  --data-urlencode "aimsid=$AIMSID" \
  --data-urlencode "f=json"

Response What response.data holds

{
    "infoArray": [
        {
            "profile": {
                "aimId": "987654321",
                "displayId": "987654321",
                "firstName": "Василий",
                "lastName": "Пупкин",
                "city": "Киев",
                "country": "UA"
            }
        }
    ]
}
#memberDirGet · Link to this method
GET /memberDir/update Update your directory profile aimsid

Each field is its own set=key=value. Fields you leave out stay as they are.

Parameters

NameDescription
aimsid string required Session id from startSession.
set string required A field: firstName, lastName. Repeatable.
f string Response format: json (default), xml or amf3. Add c=name for JSONP. jsonxmlamf3

Example request

curl -G "https://jimm.online/webapi/memberDir/update" \
  --data-urlencode "aimsid=$AIMSID" \
  --data-urlencode "set=firstName=Иван" \
  --data-urlencode "f=json"

Response What response.data holds

{}
#memberDirUpdate · Link to this method

Buddy icons

Fetching and uploading buddy icons.

GET /expressions/get A user’s buddy icon No auth

No auth needed. type=buddyIcon serves the image itself, ready for <img src>. Without type, JSON with the link.

Parameters

NameDescription
t string required The UIN.
type string buddyIcon returns the image. buddyIconbigBuddyIcon
f string Response format: json (default), xml or amf3. Add c=name for JSONP. jsonxmlamf3

Errors

  • 400 Missing t.

Example request

curl -G "https://jimm.online/webapi/expressions/get" \
  --data-urlencode "t=987654321" \
  --data-urlencode "f=json"

Response What response.data holds

{
    "expressions": [
        {
            "type": "bigBuddyIcon",
            "url": "https://jimm.online/webapi/expressions/get?t=987654321&type=buddyIcon&bartId=…"
        }
    ]
}
#expressionsGet · Link to this method
POST /expressions/upload Upload your buddy icon aimsid

The body is the raw image bytes (GIF, JPEG or PNG), not a form. Up to 64 KB. Your contacts get it through a presence event.

Parameters

NameDescription
aimsid string required Session id from startSession.
type string required Always buddyIcon. buddyIcon
f string Response format: json (default), xml or amf3. Add c=name for JSONP. jsonxmlamf3

Request body: the image bytes (image/png, image/jpeg, image/gif).

Errors

  • 460 Missing type.
  • 462 Empty, over 64 KB, or unknown type.

Example request

curl -X POST "https://jimm.online/webapi/expressions/upload?aimsid=$AIMSID&type=buddyIcon&f=json" \
  -H "Content-Type: image/png" \
  --data-binary @avatar.png

Response What response.data holds

{
    "id": "0001a1b2c3d4e5f6…"
}
#expressionsUpload · Link to this method

Events

What fetchEvents delivers

Each event looks like {type, seqNum, timestamp, eventData}. Subscribe with the events parameter of startSession.

im An incoming message. message may carry HTML from desktop clients (<HTML><BODY>…); strip tags if you render text.
{
    "type": "im",
    "seqNum": 12,
    "timestamp": 1761130042,
    "eventData": {
        "source": {
            "aimId": "987654321",
            "displayId": "987654321",
            "friendly": "Вася",
            "userType": "icq",
            "state": "online"
        },
        "message": "Привет! Как дела?",
        "msgId": "9c2e41d07a3b55f1",
        "timestamp": 1761130042,
        "imf": "plain",
        "autoresponse": false
    }
}
offlineIM A message sent while you were away; timestamp is when it was sent. Deleted from the server once delivered, so it never comes twice.
{
    "type": "offlineIM",
    "seqNum": 12,
    "timestamp": 1761130042,
    "eventData": {
        "aimId": "987654321",
        "friendly": "Вася",
        "message": "Ты где?",
        "msgId": "3e1f…",
        "timestamp": 1761100000,
        "imf": "plain",
        "autoresponse": false
    }
}
sentIM A copy of a message you sent, for your other sessions — sync across devices. iSent: true means this very session sent it; don’t show it twice.
{
    "type": "sentIM",
    "seqNum": 12,
    "timestamp": 1761130042,
    "eventData": {
        "sender": {
            "aimId": "123456789"
        },
        "dest": {
            "aimId": "987654321",
            "displayId": "987654321"
        },
        "message": "Привет!",
        "msgId": "5f1c0e2a-…",
        "timestamp": 1761130050,
        "iSent": true
    }
}
typing The other side is typing (typing), paused (typed) or cleared (none).
{
    "type": "typing",
    "seqNum": 12,
    "timestamp": 1761130042,
    "eventData": {
        "aimId": "987654321",
        "typingStatus": "typing"
    }
}
presence A buddy changed status, x-status or icon. Only changed fields come; an empty state means unchanged — don’t mark them offline.
{
    "type": "presence",
    "seqNum": 12,
    "timestamp": 1761130042,
    "eventData": {
        "aimId": "987654321",
        "friendly": "Вася",
        "state": "away",
        "statusMsg": "обедаю",
        "userType": "icq",
        "moodIcon": "https://jimm.online/webapi/…",
        "onlineTime": 1761120000
    }
}
buddylist The whole buddy list, at sign-in and after any change. Replace your list with it, don’t merge.
{
    "type": "buddylist",
    "seqNum": 12,
    "timestamp": 1761130042,
    "eventData": {
        "groups": [
            {
                "name": "Друзья",
                "id": 1,
                "buddies": [
                    {
                        "aimId": "987654321",
                        "displayId": "987654321",
                        "friendly": "Вася",
                        "state": "online",
                        "statusMsg": "на связи",
                        "onlineTime": 1761120000,
                        "userType": "icq",
                        "service": "icq",
                        "buddyIcon": "https://jimm.online/webapi/expressions/get?t=987654321&type=buddyIcon",
                        "bot": false
                    }
                ]
            }
        ]
    }
}
myInfo Your own status and info, at sign-in and on change.
{
    "type": "myInfo",
    "seqNum": 12,
    "timestamp": 1761130042,
    "eventData": {
        "aimId": "123456789",
        "displayId": "123456789",
        "state": "online",
        "userType": "icq",
        "statusMsg": "",
        "capabilities": []
    }
}
preference Server preferences: at sign-in and after preference/set.
{
    "type": "preference",
    "seqNum": 12,
    "timestamp": 1761130042,
    "eventData": {
        "showGroups": 1,
        "acceptOffLineIM": 1
    }
}
permitDeny Privacy mode and block lists: at sign-in and on change.
{
    "type": "permitDeny",
    "seqNum": 12,
    "timestamp": 1761130042,
    "eventData": {
        "pdMode": "permitAll"
    }
}
rateLimit You are sending too fast: warn, limit (messages refused), clear (go ahead).
{
    "type": "rateLimit",
    "seqNum": 12,
    "timestamp": 1761130042,
    "eventData": {
        "classes": [
            {
                "id": 3,
                "status": "limit"
            }
        ]
    }
}
clientError The recipient’s client could not handle your message; cookie is the msgId from sendIM.
{
    "type": "clientError",
    "seqNum": 12,
    "timestamp": 1761130042,
    "eventData": {
        "source": {
            "aimId": "987654321"
        },
        "cookie": "5f1c0e2a-…",
        "channel": "im"
    }
}
sessionEnded The server closed the session (rate limits or a restart, say). Stop polling and sign in again.
{
    "type": "sessionEnded",
    "seqNum": 12,
    "timestamp": 1761130042,
    "eventData": {}
}

statusCode values

CodeHTTPMeaning
200 200 Success.
330 401 Sign in again. With statusDetailCode: 3011, wrong password.
400 400 A parameter is missing or wrong; see statusText.
401 401 / 200 Token or aimsid no longer valid: the session is closed or expired.
430 200 Rate limited. Wait the seconds in the Retry-After header.
460 400 A required parameter is missing.
462 400 A parameter is present but unusable.
602 200 Message not delivered: recipient offline, box full, or blocked.

Presence states

  • online Online
  • away Away
  • idle Idle (hasn’t touched the client for a while). Set by the server, not by you.
  • dnd Do not disturb
  • occupied Occupied
  • invisible Invisible — how you see yourself; others see `offline`.
  • offline Offline

X-statuses (mood)

Codes for presence/setStatus?mood=….

  • Shopping
  • Bathing
  • Tired
  • Party
  • Beer
  • Thinking
  • Eating
  • TV
  • Friends
  • Coffee
  • Music
  • Business
  • Cinema
  • Having fun
  • Phone
  • PSP
  • Studying
  • Sick
  • Falling asleep
  • Surfing
  • Internet
  • Working
  • Typing
  • Angry
  • Love
  • Weekend
  • WC
  • Sleeping
  • On mobile
  • In love
  • Confused
  • Gaming
  • On the way
  • Diary
  • Searching

OpenAPI spec

The whole API in one file: import it into Postman or Insomnia, open it in Swagger Editor, or generate an SDK for your language.

The server is open-oscar-server by mk6i, an MIT-licensed open project. The API is compatible with AOL’s Web AIM API, so the old AOL docs help in places too.

Spotted a mistake or missing a method? Tell us in the Telegram community. Built a client? Show us — we’ll write about it on the blog.