Ding Practice Export API

Updated September 15, 2026

This API lets a community tracker — below, the tracker — read a member's Ding practice log directly. The log is served as an Insight Timer compatible CSV, over three HTTP calls, and only for members who have switched it on.

Getting a key

Write to support.ding@gmail.com with the Discord server ID and who maintains the tracker. We issue a key bound to that server. The tracker sends it as a bearer token — never in a URL; we never log it.

The three calls

Base URL https://syntony.is/ding. {guild_id} is the tracker's Discord server, {user_id} is the member's Discord user ID. All three take Authorization: Bearer KEY.

POST   /exports/{guild_id}/{user_id}            → 204   member enabled it with the tracker
GET    /exports/{guild_id}/{user_id}/practice   → 200   the CSV
DELETE /exports/{guild_id}/{user_id}            → 204   member turned it off

With the key in $KEY:

# 1. ENABLE — the member turned the export on with you.
#    Until this call everything below answers 404, and the phone uploads nothing.
#    -> 204, empty body. Safe to repeat: enabling twice is not an error.
curl -i -X POST -H "Authorization: Bearer $KEY" \
  https://syntony.is/ding/exports/{guild_id}/{user_id}

# 2a. FETCH (Sync now, then on your own schedule) — the whole log, every time.
#     -> 200: the CSV into DingLogs.csv, the headers with the ETag into headers.txt.
#     -> 404 while the phone has not uploaded yet — normal for minutes or days after 1.
curl -sD headers.txt -o DingLogs.csv -H "Authorization: Bearer $KEY" \
  https://syntony.is/ding/exports/{guild_id}/{user_id}/practice

# 2b. FETCH WHEN YOU ALREADY HAVE IT — the same request plus one header. Optional and
#     cheap: the file changes only after the member sits, so most polls have nothing new.
#     -> 304 and an empty body when nothing moved; 200 with the full file when it did.
ETAG=$(awk 'tolower($1)=="etag:"{print $2}' headers.txt | tr -d '\r')
curl -i -H "Authorization: Bearer $KEY" -H "If-None-Match: $ETAG" \
  https://syntony.is/ding/exports/{guild_id}/{user_id}/practice

# 3. DISABLE — the member turned it off with you.
#    -> 204. If no other tracker is still enabled, we delete the file too:
#    keeping practice nobody is left to read has no reason.
curl -i -X DELETE -H "Authorization: Bearer $KEY" \
  https://syntony.is/ding/exports/{guild_id}/{user_id}

POST answers 404 as readily as GET does, and on a first integration that is the likely answer: the member also has to tick your community in Ding, on the «Together» screen. Consent is asked for in two places on purpose — with the tracker, and in the app — and this 404 is the one thing worth passing back to them: open Ding → Together → tick the community.

Our server does not see all of a member's practice — the complete log exists only on their phone. So the file has to come from the phone: it goes up the next time Ding is open with a network, which means the first one can arrive minutes or days after POST.

POST and DELETE are idempotent. Until POST is called, GET returns 404 even for a member who uses Ding daily — no consent, no data, and the phone uploads nothing either. GET has no side effects, so it is safe on a schedule and safe to repeat; passing the previous ETag back as If-None-Match returns 304 when nothing changed, which is most of the time.

Responses

CodeMeaning
200GET. The log. CSV body, strong ETag, attachment named DingLogs-YYYY-MM-DD.csv.
204POST, DELETE. Accepted. Empty body, and a repeat answers the same — enabling twice is not an error, and we do not say whether it was already on.
304GET. Unchanged since the ETag the tracker sent.
404All three. Nothing here for this tracker — deliberately one answer for every reason: unknown member, export not enabled, community unchecked in the app, nothing uploaded yet, malformed ID. We do not tell an API key who our users are.
429All three. Over 120 requests per minute on the tracker's key. Retry-After says when to come back.
401All three. Key not recognized.

The file

A header line and one line per session, newest first.

Started At,Duration,Preset,Activity
06/22/2026 07:13:26,1:0:0,Morning,Meditation
06/21/2026 08:30:00,0:12:5,Together,Meditation

The header and the four columns are frozen. Anything new appears inside Preset.

How a member stops it

Either by turning the export off with the tracker, or by unchecking that community in Ding's "Together" screen. Either one stops both the delivery and any further upload from the phone. What we share, and how to stop it, is also in our privacy policy.

Questions

support.ding@gmail.com. Questions and objections are equally welcome. The API is new and its shape is still open — if a different one suits the tracker better, we would rather build that.