Skip to content
Get Started

Location Sharing API

Request, read, and watch Find My location shares via the Sendblue API

Request and read Find My location shares from your recipients. Location Sharing lets your line ask a contact to share their location over iMessage, read the location of contacts already sharing with your line, and stream live location updates as they move.

Location Sharing is available on dedicated Sendblue lines with iMessage enabled, and only works with iMessage recipients.

There are three capabilities:

CapabilityEndpointDescription
RequestPOST /api/request-locationSend a Find My location-request card to a contact. When they accept, the shared location is delivered to your receive webhook.
ReadGET /api/location · GET /api/location/{number}Read the current location of contacts already sharing with your line.
WatchGET /api/location/{number}/watchStream live location updates for a contact over Server-Sent Events (SSE).

A contact must be sharing their location with your line before Read and Watch return data. Use Request to prompt a contact who is not sharing yet — once they accept, they become a sharing contact for the duration they selected.


Send a Find My location-request card to a contact. This appears in their iMessage conversation as a native “Share My Location” request that they can accept and choose a duration for.

POST https://api.sendblue.com/api/request-location
ParameterTypeRequiredDescription
numberstringYesRecipient phone number (E.164 format)
from_numberstringYesYour Sendblue line (E.164 format)
Terminal window
curl -X POST 'https://api.sendblue.com/api/request-location' \
-H 'sb-api-key-id: YOUR_API_KEY' \
-H 'sb-api-secret-key: YOUR_API_SECRET' \
-H 'Content-Type: application/json' \
-d '{
"number": "+19175551234",
"from_number": "+14155559876"
}'
const axios = require('axios');
await axios.post(
'https://api.sendblue.com/api/request-location',
{
number: '+19175551234',
from_number: '+14155559876'
},
{
headers: {
'sb-api-key-id': 'YOUR_API_KEY',
'sb-api-secret-key': 'YOUR_API_SECRET',
'Content-Type': 'application/json'
}
}
);
{
"status": "QUEUED",
"message": "Location request accepted for dispatch",
"number": "+19175551234",
"message_handle": "6f1b2c3d4e5f6789",
"uuid": "6f1b2c3d4e5f6789"
}

The request is queued and sent to your line. The recipient sees a location-request card in iMessage. The response does not contain a location — the shared location is delivered later, via webhook, once the recipient accepts.

When the recipient accepts the request, Sendblue POSTs an inbound message to your configured receive webhook. It’s a standard inbound message webhook with two additions for location shares: message_type is "location", and a location object is included.

{
"is_outbound": false,
"message_handle": "99DCC379-DD76-4712-BA65-11EFB33B8CD6",
"from_number": "+19175551234",
"message_type": "location",
"location": {
"latitude": 37.331413,
"longitude": -122.030731,
"accuracy": 12.5,
"altitude": 8.2,
"timestamp": "2025-12-12T15:41:20.000Z",
"duration": "endOfDay"
}
}

The standard message fields (number, to_number, sendblue_number, content, media_url, and so on) are omitted above for brevity — see the inbound message webhook reference for the full payload.

FieldTypeDescription
latitudenumberLatitude in decimal degrees
longitudenumberLongitude in decimal degrees
accuracynumber | undefinedHorizontal accuracy in meters, when available
altitudenumber | undefinedAltitude in meters, when available
timestampstring | undefinedISO 8601 time the fix was captured
durationstring | undefinedThe share duration the recipient selected, as an Apple-defined key (e.g. oneHour, endOfDay, indefinitely)

Read the current location of contacts already sharing with your line. These endpoints return the latest cached fix — they do not send a request card. A contact must already be sharing (for example, after accepting a location request).

GET https://api.sendblue.com/api/location
ParameterTypeRequiredDescription
from_numberstringYesYour Sendblue line (E.164 format)
Terminal window
curl -X GET 'https://api.sendblue.com/api/location?from_number=%2B14155559876' \
-H 'sb-api-key-id: YOUR_API_KEY' \
-H 'sb-api-secret-key: YOUR_API_SECRET'
{
"status": "OK",
"from_number": "+14155559876",
"locations": [
{
"number": "+19175551234",
"state": "shared_with_fix",
"location": {
"address": "1 Apple Park Way, Cupertino, CA",
"latitude": 37.331413,
"longitude": -122.030731,
"accuracy": 12.5,
"altitude": 8.2,
"timestamp": "2025-12-12T15:41:20.000Z",
"locationType": "live",
"expiresAt": "2025-12-12T23:59:59.000Z"
}
}
]
}
GET https://api.sendblue.com/api/location/{number}

The {number} path parameter is the recipient phone number in E.164 format (URL-encode the leading + as %2B).

ParameterTypeRequiredDescription
from_numberstringYesYour Sendblue line (E.164 format)
Terminal window
curl -X GET 'https://api.sendblue.com/api/location/%2B19175551234?from_number=%2B14155559876' \
-H 'sb-api-key-id: YOUR_API_KEY' \
-H 'sb-api-secret-key: YOUR_API_SECRET'
{
"status": "OK",
"from_number": "+14155559876",
"number": "+19175551234",
"state": "shared_with_fix",
"location": {
"address": "1 Apple Park Way, Cupertino, CA",
"latitude": 37.331413,
"longitude": -122.030731,
"accuracy": 12.5,
"altitude": 8.2,
"timestamp": "2025-12-12T15:41:20.000Z",
"locationType": "live",
"expiresAt": "2025-12-12T23:59:59.000Z"
}
}

If the contact is not sharing with your line, the response has state: "not_shared" and no location object.

FieldTypeDescription
numberstring | nullThe contact’s phone number
statestringOne of not_shared, shared_no_fix_yet, or shared_with_fix (see below)
locationobjectPresent when a fix is available (omitted for not_shared)
ValueMeaning
not_sharedThe contact is not sharing their location with your line
shared_no_fix_yetThe contact is sharing, but no coordinates are available yet
shared_with_fixThe contact is sharing and coordinates are available in location
FieldTypeDescription
addressstring | nullReverse-geocoded address, when available
latitudenumberLatitude in decimal degrees (omitted for a placeholder 0,0 fix)
longitudenumberLongitude in decimal degrees (omitted for a placeholder 0,0 fix)
accuracynumberHorizontal accuracy in meters, when available
altitudenumberAltitude in meters, when available
timestampstringISO 8601 time the fix was captured
locationTypestringOne of live, shallow, legacy, or unknown
expiresAtstringISO 8601 time the share expires, when known

Stream live location updates for a single contact over Server-Sent Events (SSE). The connection stays open and emits a location event each time a new fix arrives, until you close it, the contact stops sharing, or the line disconnects.

GET https://api.sendblue.com/api/location/{number}/watch

The {number} path parameter is the recipient phone number in E.164 format (URL-encode the leading + as %2B). The contact must already be sharing with your line.

ParameterTypeRequiredDescription
from_numberstringYesYour Sendblue line (E.164 format)
Terminal window
curl -N 'https://api.sendblue.com/api/location/%2B19175551234/watch?from_number=%2B14155559876' \
-H 'sb-api-key-id: YOUR_API_KEY' \
-H 'sb-api-secret-key: YOUR_API_SECRET' \
-H 'Accept: text/event-stream'

The -N (--no-buffer) flag keeps curl from buffering the stream so events print as they arrive.

The server responds with Content-Type: text/event-stream and emits named events:

event: ready
data: {"status":"OK","from_number":"+14155559876","number":"+19175551234"}
event: location
data: {"from_number":"+14155559876","number":"+19175551234","state":"shared_with_fix","location":{"latitude":37.331413,"longitude":-122.030731,"accuracy":12.5,"altitude":8.2,"timestamp":"2025-12-12T15:41:20.000Z","locationType":"live"}}
event: complete
data: {"reason":"sharing_ended"}
EventDescription
readyThe watch is established. Sent once, before the first fix.
locationA new location fix. The data payload matches the read response (number, state, and an optional location object).
errorThe watch failed. The data payload contains a message. The stream then ends.
completeThe watch ended normally. The data payload contains a reason such as sharing_ended, authorization_revoked, or worker_disconnected.

The stream also sends SSE comment lines (: keepalive) roughly every 15 seconds to keep the connection alive. Ignore any line beginning with :.

// Uses the built-in fetch (Node 18+) to read the SSE stream.
const res = await fetch(
'https://api.sendblue.com/api/location/%2B19175551234/watch?from_number=%2B14155559876',
{
headers: {
'sb-api-key-id': 'YOUR_API_KEY',
'sb-api-secret-key': 'YOUR_API_SECRET',
Accept: 'text/event-stream'
}
}
);
const reader = res.body.getReader();
const decoder = new TextDecoder();
let buffer = '';
while (true) {
const { value, done } = await reader.read();
if (done) break;
buffer += decoder.decode(value, { stream: true });
const chunks = buffer.split('\n\n');
buffer = chunks.pop() ?? '';
for (const chunk of chunks) {
const eventLine = chunk.split('\n').find((l) => l.startsWith('event:'));
const dataLine = chunk.split('\n').find((l) => l.startsWith('data:'));
if (!eventLine || !dataLine) continue; // skip keepalive comments
const event = eventLine.slice('event:'.length).trim();
const data = JSON.parse(dataLine.slice('data:'.length).trim());
if (event === 'location') {
console.log('New fix:', data.location);
} else if (event === 'complete' || event === 'error') {
break;
}
}
}

To stop watching, close the HTTP connection.


HTTP StatusMessage / message fieldDescription
400You must specify a valid from_number...Missing or invalid number / from_number
400Your account has been blocked...The account is blocked
401UnauthorizedInvalid or missing API credentials
403Location request blocked by account policyThe request was declined by account send policy (e.g. rate/line limits)
404The from_number is not registeredThe from_number is not a line on your account
422unsupported_on_this_lineThis line doesn’t support Location Sharing — it isn’t a dedicated iMessage line, is a shared line, or doesn’t have iMessage enabled
422unsupported_recipientThe recipient is known to be SMS/RCS; Find My requires an iMessage recipient
503worker_unavailableThe line is not currently connected
503worker_version_unsupportedThis line doesn’t support Location Sharing yet; try again shortly
504Timeout waiting for location readA read did not complete in time; retry
{
"status": "ERROR",
"message": "Description of what went wrong"
}

Some 422 responses include a detail field with a human-readable explanation.


  1. Line support: Location Sharing requires a dedicated Sendblue line with iMessage enabled. It isn’t available on shared lines, and some lines may not support it — those return a 422 or 503 error.

  2. iMessage only: Find My location sharing is an iMessage feature. Requests to numbers known to be SMS/RCS are rejected with unsupported_recipient. Unknown numbers are allowed and resolved as iMessage on send.

  3. Request is asynchronous: POST /api/request-location only sends the request card. The location arrives later, via your receive webhook, once the recipient accepts — and only if they accept.

  4. Read/Watch need an active share: GET /api/location* and the watch endpoint only return data for contacts already sharing with your line. Use a location request to prompt a contact who is not sharing yet.

  5. Shares expire: Recipients choose how long to share (for example, one hour, until end of day, or indefinitely). Once a share expires, the contact reverts to not_shared and watches for them end with a complete event.

  6. Requests count toward your limits: A location request counts as a message and is subject to your account’s sending limits.