Skip to content

Instantly share code, notes, and snippets.

@StephenBlackWasAlreadyTaken
Last active December 23, 2025 09:37
Show Gist options
  • Select an option

  • Save StephenBlackWasAlreadyTaken/adb0525344bedade1e25 to your computer and use it in GitHub Desktop.

Select an option

Save StephenBlackWasAlreadyTaken/adb0525344bedade1e25 to your computer and use it in GitHub Desktop.
DexcomShare Endpoints for the Uploader App
  • these are the calls used by the dexcom uploader app
  • these are in no particular order!
  • User-Agent: Dexcom%20Share/3.0.2.11 CFNetwork/672.0.2 Darwin/14.0.0

General

Read Dexcoms System time clock

GET

/ShareWebServices/Services/General/SystemUtcTime

Body:

  none

Response:

  {
    "DateTime":"\/Date(1426767421178)\/",
    "OffsetMinutes":0
  }

Session Related

Login to a Publisher Account (Get a Session ID):

POST

/ShareWebServices/Services/General/LoginPublisherAccountByName

Body:

  {
    "accountName":"yourlogin",
    "applicationId":"d8665ade-9673-4e27-9ff6-92db4ce13d13",
    "password":"yourpassword"
  }

Response:

  "e3e3e6a5-coolsessionid-bro”

Authenticate Publisher Account (Get a Session ID):

POST

/ShareWebServices/Services/General/AuthenticatePublisherAccount

Body:

  {
    "accountName":"yourlogin",
    "applicationId":"d8665ade-9673-4e27-9ff6-92db4ce13d13",
    "password":"yourpassword"
  }

Response:

  "e3e3e6a5-coolsessionid-bro”

Check if the Reciever is assigned to your account

POST

/ShareWebServices/Services/Publisher/CheckMonitoredReceiverAssignmentStatus?sessionId={YourSessionId}&serialNumber={YourSerialNumber}/

Body:

  none

Response:

  `AssignedToYou` or `NotAssigned` (plaintext)

Assign the reciever to you (If you got NotAssigned or something else)

POST

/ShareWebServices/Services/Publisher/ReplacePublisherAccountMonitoredReceiver?sessionId={YourSessionId}&serialNumber={YourSerialNumber}

Body:

  none

Response:

  No Idea, Someone please tell me, if you assign one to yourself that was
  already yours you get a 500 error

Check remote monitoring session is valid

POST

/ShareWebServices/Services/Publisher/IsRemoteMonitoringSessionActive?sessionId={YourSessionId}

Body:

  none

Response:

  `true` or `false` (plaintext)

Start remote monitoring session

POST

/ShareWebServices/Services/Publisher/StartRemoteMonitoringSession?sessionId={yoursessionid}&serialNumber={YourdexcomSerialNumber}

Body:

  none

Response:

  just a status, `200`

Stop a remote monitoring session

POST

/ShareWebServices/Services/Publisher/StopRemoteMonitoringSession?sessionId={YourSessionId}

Body:

  none

Response:

  just a status, `200`

Update Publisher information (might be fun for sending them cute messages?)

POST

/ShareWebServices/Services/Publisher/UpdatePublisherAccountRuntimeInfo

Body:

  {
    "sessionId":"YourSessionId",
    "runtimeInfo":
      {
        "DeviceManufacturer":"Apple",
        "DeviceModel":"iPhone5,2",
        "DeviceOsVersion":"7.0.2",
        "AppVersion":"3.0.2.11",
        "AppName":"DexcomShare",
        "AppNumber":"SW10569",
        "DeviceOsName":"iPhone OS"
      }
  }

Response:

  just a status, `200`

Data!

Post BG Data

POST

/ShareWebServices/Services/Publisher/PostReceiverEgvRecords?sessionId={yourSessionId}

Body:

{
  "SN":"YourSerialNumber",
  "Egvs":[
      {
        "Trend":4,
        "ST":"\/Date(1426783106000)\/",
        "DT":"\/Date(1426754317000)\/",
        "Value":97
      }
    ],
  "TA":-14365
}

Response:

  just a status, `200`

ST system time, DT display time, TA is a time offset, multiply by 1000 and subtract it from the time (so subtracting a negative in this example, which is really adding)

Read BG Data

POST

/ShareWebServices/Services/Publisher/ReadPublisherLatestGlucoseValues?sessionId={YourSessionId}&minutes=1440&maxCount=1

Body:

  none

Response:

[
  {
    "DT":"\/Date(1426780716000-0700)\/",
    "ST":"\/Date(1426784306000)\/",
    "Trend":4,
    "Value":99,
    "WT":"\/Date(1426769941000)\/"
  }
]

Invite Follower Related

Check if someone is already a contact of yours

POST

/ShareWebServices/Services/Publisher/DoesContactExistByName?sessionId={YourSessionId}&contactName={NameOfNewFollower}

Body:

  none

Response:

  `true` or `false` (plaintext)

Create a contact if they dont already exist

POST

/ShareWebServices/Services/Publisher/CreateContact?sessionId={YourSessionId}&contactName={FollowerName}&emailAddress={FollowerEmail}

Body:

  none

Response:

  a contact id (needed for the invite!), `123312-af1341123-coolid`

Send the invite!!

POST

/ShareWebServices/Services/Publisher/CreateSubscriptionInvitation?sessionId={YourSessionId}&contactId={ContactId}

Body:

  {
    "AlertSettings":{
      "HighAlert":{
        "MinValue":200,
        "AlarmDelay":"PT1H",
        "AlertType":1,
        "IsEnabled":false,
        "RealarmDelay":"PT2H",
        "Sound":"High.wav",
        "MaxValue":401
      },
      "LowAlert":{
        "MinValue":39,
        "AlarmDelay":"PT30M",
        "AlertType":2,
        "IsEnabled":false,
        "RealarmDelay":"PT2H",
        "Sound":"Low.wav",
        "MaxValue":70
      },
      "FixedLowAlert":{
        "MinValue":39,
        "AlarmDelay":"PT0M",
        "AlertType":3,
        "IsEnabled":true,
        "RealarmDelay":"PT30M",
        "Sound":"UrgentLow.wav",
        "MaxValue":55
      },
      "NoDataAlert":{
        "MinValue":39,
        "AlarmDelay":"PT1H",
        "AlertType":4,
        "IsEnabled":false,
        "RealarmDelay":"PT0M",
        "Sound":"NoData.wav",
        "MaxValue":401
      }
    },
    "Permissions":1,
    "DisplayName":"{YourAccountDisplayName}"
  }

Note that permissions 1 means they can view your graph data

Response:

  a subscriber id for the person you invited! (Usefull for updating their
  subscription permissions and such) `793312-af1341123-coolid`

List all Followers

POST

/ShareWebServices/Services/Publisher/ListPublisherAccountSubscriptions?sessionId={YourSessionId}

Body:

  none

Response:

  [
    {
      "ContactId":"FollowersContactId",
      "ContactName":"FollowersName",
      "DateTimeCreated":{
        "DateTime":"\/Date(1437101121008)\/",
        "OffsetMinutes":0
      },
      "DateTimeModified":{
        "DateTime":"\/Date(1437101121008)\/",
        "OffsetMinutes":0
      },
      "DisplayName":"YourDisplayName",
      "InviteExpires":{
        "DateTime":"\/Date(1437705921008)\/",
        "OffsetMinutes":0
      },
      "IsEnabled":false,
      "IsMonitoringSessionActive":true,
      "Permissions":1,
      "State":2,
      "SubscriberId":"00000000-0000-0000-0000-000000000000",
      "SubscriptionId":"theirSubscriptionIdIsuppose?"
    }
  ]

note: maybe we can use this subscription id to send our own custom invites to followers

Delete Follower

POST

/ShareWebServices/Services/Publisher/DeleteContact?sessionId={YourSessionId}&contactId={followersContactId}

Body:

  none

Response:

  just a status, `200`

Still undocumented but logged if you need info on it (Not adding it all here out of lazziness)

  • getting the image
  • getting the subscription display name
  • getting the subscription email address
  • reading the contact list
  • sending changes to the contacts Permissions
  • removing a contact
  • follower aknowledging alarms
  • follower reading invitation info
  • follower accepting invitation
  • follower updating runtimeInfo
  • folower listing all their subscriptions
  • read subscription alerts

CURL examples for getting values from Dexcom

curl -v \
  -H "Accept: application/json" -H "Content-Type: application/json" \
  -H "User-Agent: Dexcom Share/3.0.2.11 CFNetwork/711.2.23 Darwin/14.0.0" \
  -X POST https://share1.dexcom.com/ShareWebServices/Services/General/LoginPublisherAccountByName \
  -d '{"accountName":"YOURLOGIN","applicationId":"d8665ade-9673-4e27-9ff6-92db4ce13d13","password":"YOURPASSWORD"}' 

which should recieve a response like

"8c1234deb-323c-4e9d-8362-39cfa23499ed"

which you use to get values like

curl -v \
  -H "Content-Length: 0" -H "Accept: application/json" \
  -H "User-Agent: Dexcom Share/3.0.2.11 CFNetwork/672.0.2 Darwin/14.0.0" \
  -X POST "https://share1.dexcom.com/ShareWebServices/Services/Publisher/ReadPublisherLatestGlucoseValues?sessionId=8c1234deb-323c-4e9d-8362-39cfa23499ed&minutes=1440&maxCount=1" 
@dgoldman95
Copy link

Ah I see. thanks @fsallstrom

@rdemol01
Copy link

rdemol01 commented Oct 4, 2025

I wanted to highlight the difference between these endpoints:

  1. LoginPublisherAccountByName - as documented above
    Result = does not return sessionId on my end
  2. LoginPublisherAccountById - as found in py example from osa1 on 25.4.2024
    Result = does return a sessionId

In summary, what works for me:

Login to a Publisher Account by Id (Get a Session ID):
POST/ShareWebServices/Services/General/LoginPublisherAccountById
Body:
{
"accountId":"your account id from endpoint AuthenticatePublisherAccount",
"applicationId":"d8665ade-9673-4e27-9ff6-92db4ce13d13",
"password":"yourpassword"
}

@grahamjenson
Copy link

grahamjenson commented Nov 10, 2025

Anyone got further on this @Okomoko @MooseV2 ? I just want to be able to pull down the recent sgvs from a user without having to share the password.

I get "Account not configured with proper device key".

DXUSER=<user>
DXPASS=<pass>
SUBSCRIPTION_ID="<from get subscriptions endpoint>"

DXURL=https://shareous1.dexcom.com
APP_ID="d8665ade-9673-4e27-9ff6-92db4ce13d13"



SESSION_BODY=$(cat <<EOF | tr -d '\n' 
{"accountName":"$DXUSER", "password":"$DXPASS", "applicationId":"$APP_ID"}
EOF
)

ACCOUNT_ID_BODY=$(cat <<EOF | tr -d '\n'
{ "accountName": "$DXUSER", "password": "$DXPASS", "applicationId": "$APP_ID"}
EOF
)

SESSION_ID=$(curl -v -H "Accept: application/json" \
          -H "Content-Type: application/json" \
          -H "User-Agent: Dexcom Share/3.0.2.11 CFNetwork/672.0.2 Darwin/14.0.0" \
          -X POST \
"$DXURL/ShareWebServices/Services/General/LoginPublisherAccountByName" -d "$SESSION_BODY" | tr -d '"')

ACCOUNT_ID=$(curl --location --request POST "$DXURL/ShareWebServices/Services/General/AuthenticatePublisherAccount" \
--header 'Content-Type: application/json' \
-d "$ACCOUNT_ID_BODY" | tr -d '"')


CURRENT_DATETIME=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
DATETIME_MINUS_1H=$(date -u -v -1H +"%Y-%m-%dT%H:%M:%SZ")

PART1=$(cat <<EOF | tr -d '\n' | base64 | tr -d '='
{"Timestamp":"$CURRENT_DATETIME", "AppId":"$APP_ID", "IsZip":0, "AccId":"$ACCOUNT_ID"}
EOF
)

PART2=$(cat <<EOF | tr -d '\n' | base64 |  tr -d '='
{"SubscriptionLastSyncTimestamps":[{"SubscriptionId":"$SUBSCRIPTION_ID","LastSyncTimestamps":{"Glucose":"$DATETIME_MINUS_1H"}}]}
EOF
)

PART3="N4r7x-9dyEJ03YqsTXHL5d" # hardcoded I guess?


curl -v -H "Accept: application/json" \
          -H "Content-Type: application/json" \
          -H "User-Agent: Dexcom Share/3.0.2.11 CFNetwork/672.0.2 Darwin/14.0.0" \
          -X POST \
"$DXURL/ShareWebServices/Services/Subscriber/ReadEvents" \
-d "\"$PART1.$PART2.$PART3\""

@Dexus
Copy link

Dexus commented Dec 22, 2025

Without the RSA Keys you will never get results. There are multiple services involved. First you would need to extract the RSA key, from a APK/IPA and then you can maybe try to get closer to the rest. But this would for sure not public... at least not from my side, as its not legal in germany... even I would like to doit.

@Dexus
Copy link

Dexus commented Dec 22, 2025

To accept a Invite:

POST /ShareWebServices/Services/Subscriber/AcceptSubscriptionInvitation2 HTTP/1.1
Host: shareous1.dexcom.com
Content-Type: application/json
Connection: keep-alive
Accept: application/json
User-Agent: Dexcom%20Follow/3554 CFNetwork/3826.600.41 Darwin/24.6.0
Content-Length: 287
Accept-Language: de-DE,de;q=0.9
Accept-Encoding: gzip, deflate, br

"eyJUaW1lc3RhbXAiOiIyMDI1LTEyLTIyVDE1OjI0OjMzWiIsIkFwcElkIjoiZDg5NDQzZDItMzI3Yy00YTZmLTg5ZTUtNDk2YmJiMDMxN2RiIiwiSXNaaXAiOjAsIkFjY0lkIjoiZmI2ZGNmZDQtYmJiYi1iYmJiLWJiYmItN2RkYjNmOGFlN2VjIn0.
eyJJbnZpdGF0aW9uSWQiOiJFRUVFQjFCRC1CQkJCLUJCQkItQUFBQS1GRkZGN0M3RDI5OEEifQ.
w78tMhY9w7l4asK8bizCt8OlwrHigKDDsw"

HTTP/1.1 200 OK
Date: Mon, 22 Dec 2025 15:24:33 GMT
Content-Type: application/json
Transfer-Encoding: chunked
Connection: keep-alive
CF-RAY: fffff0765b9d3314-TXL
vary: Accept-Encoding
vary: Origin
vary: Access-Control-Request-Method
vary: Access-Control-Request-Headers
x-trace-id: 055dbec3-aaaa-aaaa-ffff-fffffd691738
strict-transport-security: max-age=15780000; includeSubDomains; preload
cf-cache-status: DYNAMIC
X-Content-Type-Options: nosniff
Server: cloudflare

26
"ffffcc91-aaaa-bbbb-cccc-dddd562a8c38"
0

Problem the "JWT" like request has a hash, which I don't able to reproduce yet.

And there are many more work places... to be able to use the "Dexcom Follower" App Without using you own credentials.

@KajBjurman
Copy link

Without the RSA Keys you will never get results. There are multiple services involved. First you would need to extract the RSA key, from a APK/IPA and then you can maybe try to get closer to the rest. But this would for sure not public... at least not from my side, as its not legal in germany... even I would like to doit.

Decompiling in order to achieve interoperability is legal in most EU countries, including Germany. Isn't it?

@Dexus
Copy link

Dexus commented Dec 23, 2025

Normally I would say you are right, but once you touch the DRM/auth/server-side access it will need to checked by a lawyer. And the Encryption is one part of it. Would be nicer if Dex would publish the API for anyone - who needs it. But as medical service they will not because of business..

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment