downloadAccess
Read or replace the download policy for an app. A policy either allows public downloads or restricts downloads to specified IPv4 and IPv6 addresses or networks. Apps without a configured policy default to public access.
See Restricting downloads by IP address for private-storage setup, proxy configuration, and automatic-update considerations.
Authentication and permissions
Both methods use the shared API authentication rules.
- GET: the app owner and collaborators with current, accepted access can read the policy, including collaborators with read-only access.
- PUT: only the app owner can replace the policy. Build or release permission on another account's app does not grant this permission.
The shared account IP restrictions apply to this API. They are separate from the app's download policy, which controls who can download artifacts.
Read the policy
GET /v1/downloadAccess?appId={appId}
Authorization: Bearer <access-token>
The required appId query parameter is the ToDesktop app ID: 1–128 ASCII letters,
numbers, underscores, or hyphens.
curl "https://api.todesktop.com/v1/downloadAccess?appId=your-app-id" \
-H "Authorization: Bearer $TODESKTOP_ACCESS_TOKEN"
Returns HTTP 200 with the saved policy. For an app with no configured policy:
{
"appId": "your-app-id",
"downloadAccess": { "mode": "public" }
}
This reads the saved setting; it does not confirm that every CDN location is already enforcing that setting.
Replace the policy
PUT /v1/downloadAccess?appId={appId}
Authorization: Bearer <access-token>
Content-Type: application/json
Supply the complete policy as the JSON body. Do not wrap it in downloadAccess
or include appId in the body. Each PUT replaces the previous policy, including
the entire address list.
Restrict downloads
Private artifact storage must first be configured for the app by ToDesktop.
Otherwise, this request returns 409 with reason private-storage-required.
Replace the example addresses below with the public source addresses that your network or proxy uses to reach ToDesktop:
curl -X PUT "https://api.todesktop.com/v1/downloadAccess?appId=your-app-id" \
-H "Authorization: Bearer $TODESKTOP_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
--data '{"mode":"ipAllowlist","allowedCidrs":["203.0.113.10","2001:db8::/48"]}'
Returns HTTP 200 with the normalized policy:
{
"appId": "your-app-id",
"downloadAccess": {
"mode": "ipAllowlist",
"allowedCidrs": ["203.0.113.10/32", "2001:db8::/48"]
},
"cacheInvalidation": "requested"
}
Restore public downloads
curl -X PUT "https://api.todesktop.com/v1/downloadAccess?appId=your-app-id" \
-H "Authorization: Bearer $TODESKTOP_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
--data '{"mode":"public"}'
The response contains downloadAccess: { "mode": "public" } and
cacheInvalidation: "requested". This restores public access through ToDesktop's
download URLs. It does not change the underlying artifact storage permissions.
Policy fields and limits
Addresses can be bare IPv4/IPv6 addresses or CIDR networks. CIDR notation, such as
203.0.113.0/24, identifies a network range. Bare addresses become /32 for IPv4
or /128 for IPv6. Network host bits are cleared (203.0.113.4/24 becomes
203.0.113.0/24), surrounding whitespace is trimmed, and duplicate normalized
entries are removed. The 100-entry limit applies before deduplication.
IPv4 must use dotted-decimal notation. IPv6 zone identifiers such as %eth0 are
not accepted. Use IPv4 entries for IPv4-mapped IPv6 addresses. Unknown fields,
empty address lists, and a null policy are rejected. The JSON request body must
not exceed 16 KiB.
Propagation and retries
PUT saves the policy and then requests CDN configuration-cache invalidation.
cacheInvalidation: "requested" means the invalidation request succeeded; it
does not confirm global enforcement. Old policies can remain in the CDN's
two-hour configuration cache, including when an in-flight read restores an older
value after an update. Requests already in progress can also complete.
If the API returns 503 with reason invalidation-failed, the policy was
saved but invalidation failed. Retry the same PUT to request invalidation again.
An identical PUT still requests invalidation. A GET showing the new value does
not replace that retry or verify propagation.
Coordinate concurrent writers: retrying an older PUT after a newer policy change can overwrite the newer policy. See the guide's verification steps before relying on a new restriction.
Errors
API responses, including errors, use Cache-Control: private, no-store. Errors
have this shape:
{
"error": {
"reason": "private-storage-required",
"message": "Private artifact storage must be configured before restricting this app."
}
}