Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.photon.codes/docs/llms.txt

Use this file to discover all available pages before exploring further.

im.locations sends Find My location-sharing requests and reads friend locations that are already visible to the current iMessage account. Use request(chat, address) when you want to ask someone to share location. Use list(...), get(...), and watch(...) after location is already shared with the current account.
Location updates are not part of the durable event log. im.locations.watch(...) is a dedicated live stream. Updates missed while disconnected cannot be replayed with im.events.catchUp(...).

What You Can Do

NeedUse this when
Request location sharingYou want to send a visible Find My request card to a chat participant
List shared locationsYou want every currently visible friend location
Fetch one locationYou want the latest snapshot for one friend
Watch live updatesYou are updating a map or background job as locations change

Before You Use It

RuleMeaning
Requests do not grant accessrequest(...) only sends a visible request card; the other person must accept or start sharing
Reads only show visible shareslist(...), get(...), and watch(...) only return locations already visible to the current account
Coordinates can be absentCheck both latitude and longitude before plotting a point
Missed updates are gonewatch(...) updates missed during a disconnect are not replayed by catchUp(...)

Request Location Sharing

Send a visible Find My request card in an existing direct or group chat:
const receipt = await im.locations.request(chat.guid, "alice@example.com");

console.log(receipt.requestStatus, receipt.messageGuid);
Inputs:
ArgumentMeaning
chatWhere to send the request card. Pass a direct or group chat.guid, not an email or phone number.
addressWho to ask for location. Pass that person’s full email address or E.164 phone number.
options.clientMessageIdOptional idempotency key for retrying the same logical request.
The address must belong to someone in chat. In a direct chat, that means the other participant. In a group chat, that means an existing group member. Returns LocationRequestReceipt. A successful call means the request card was sent or the server accepted the request operation. It does not mean the other person is now sharing location. The returned receipt includes:
FieldMeaning
addressThe normalized email address or E.164 phone number that was requested
requestedWhether the server sent or accepted a request operation
requestStatusServer status for the request operation
reasonOptional reason when the request was not sent or needs explanation
messageGuidMessage GUID for the request card, when a card was created
When messageGuid is present, use it like any other message GUID. For example, you can look it up with im.messages.get(...). For idempotent retries from your job system, pass clientMessageId:
await im.locations.request(chat.guid, "alice@example.com", {
  clientMessageId: `location-request-${job.id}`,
});
clientMessageId is only needed when your queue or worker may rerun the same logical request after a crash or timeout. Most direct calls can omit it. See error handling for details.
After the other person accepts or starts sharing, use get(...), list(...), or watch(...) to read their location.

List Shared Locations

const locations = await im.locations.list();

for (const location of locations) {
  if (location.latitude === undefined || location.longitude === undefined) {
    continue;
  }

  console.log(location.address, location.latitude, location.longitude);
}
list(...) takes no arguments. Returns SharedFriendLocation[]. If no friends are sharing location, the array is empty. Each item is a location snapshot, and a snapshot is not guaranteed to include coordinates. latitude and longitude are optional. They may be absent while a device is still locating, when location is unavailable, or when only address metadata is available.
Check both latitude and longitude before showing a map marker. Do not rely only on locationType, and do not assume every listed location has coordinates.

Get One Friend Location

const location = await im.locations.get("alice@example.com");

console.log(location.name ?? location.address, location.locationType);
Input:
ArgumentMeaning
addressThe friend whose location you want. Pass a full email address or E.164 phone number. Do not pass chat.guid or a display name.
Phone numbers must include the country code, start with +, and omit spaces, parentheses, and dashes. Returns SharedFriendLocation. If the address is not sharing location or is not visible to the current account, get(...) throws NotFoundError. The returned object looks like this:
{
  "address":              "alice@example.com",       // Normalized email address or E.164 phone number
  "isLocatingInProgress": false,                     // Whether the device is still locating
  "locationType":         "live",                    // Freshness of the location source
  "latitude":             37.7749,                   // Latitude; may be absent
  "longitude":            -122.4194,                 // Longitude; may be absent
  "accuracy":             12,                        // Horizontal accuracy in meters; may be absent
  "locationTimestamp":    "2026-01-01T12:00:00Z",    // Time the location was captured; may be absent
  "expiresAt":            "2026-01-01T13:00:00Z",    // Share expiration time; may be absent
  "name":                 "Alice",                   // Friend display name; may be absent
  "shortAddress":         "Mission, SF",             // Short human-readable address; may be absent
  "longAddress":          "Mission District, SF"     // Full human-readable address; may be absent
}

Location Types

location.locationType describes how fresh the snapshot is:
ValueMeaning
"live"Actively updating live location
"shallow"Recent cached location
"legacy"Older cached location from a previous session
"unknown"The server could not classify the source
locationType only describes freshness. It does not guarantee that coordinates are present.

Watch Live Updates

Scope

Watch every visible friend’s location updates:
for await (const update of im.locations.watch()) {
  console.log(update.location.address, update.sourceSequence);
}
Watch one address:
for await (const update of im.locations.watch("alice@example.com")) {
  const { latitude, longitude } = update.location;

  if (latitude === undefined || longitude === undefined) {
    continue;
  }

  console.log(latitude, longitude);
}
Inputs:
CallMeaning
watch()Watch every visible friend’s location updates
watch(address)Watch one friend by full email address or E.164 phone number
Do not pass chat.guid or a display name to watch(...).

Update Shape

Each update is SharedFriendLocationUpdated:
{
  "location": {                         // Latest SharedFriendLocation snapshot
    "address": "alice@example.com",
    "locationType": "live",
    "latitude": 37.7749,
    "longitude": -122.4194
  },
  "sourceSequence": 123                 // Live-location stream sequence; useful for duplicate detection
}
Breaking out of the for await loop closes the live stream.
sourceSequence belongs only to the location live stream. It is not the same as durable event sequence. You can use it to detect duplicate live updates after reconnecting, but you cannot use im.events.catchUp(...) to recover location updates missed while disconnected.

Next Steps

  1. Addresses — check whether an email address or phone number is reachable over iMessage
  2. Events — understand durable events and catch-up
  3. Chats — manage chats, read state, and typing state