dappcdn api access

dAppCDN for Institutions

Latest versions, checksums and direct downloads of the official files, for universities, companies and IT departments, through an API key of their own.

Access is by request only: contact us and we will set up a key for your institution.

The official files, straight into your deployments

Universities, companies and IT departments keep hundreds of computers up to date. dAppCDN gives them what a person gets on our pages, without the pages: the latest version of every app, its checksums and a direct download of the official file, exactly as its developer released it, through an API key of their own.

What you get

  • The latest release of every app you need, by its name in our addresses (its slug).
  • Every older version of an app too, when you need to stay on one or go back to it.
  • For each file: its name, operating system, size, MD5, SHA-1 and SHA-256, and whether our antivirus scan passed.
  • Direct downloads, without the download page and its waiting time, from the same fast CDN as our site.
  • A key for your institution alone, limited to the apps, networks and countries you choose.
  • Usage statistics of your key, on request: requests, downloads, and why a request was refused.

How it works

Every request carries your key in the Authorization header, never in the address. Four requests cover everything:

  • GET/api/institutions/v1/projects

    Every app your key reaches, each with its latest release.

  • GET/api/institutions/v1/projects/<slug>

    One app's latest release with its files, and the list of all its versions (without their files).

  • GET/api/institutions/v1/projects/<slug>/releases/<version>

    One version of the app, the latest or an older one, with its files. The version is written as the list gives it, URL-encoded.

  • GET/api/institutions/v1/projects/<slug>/files/<file id>

    The file itself: a redirect to a short-lived download link. Every file in the answers above carries this address as download_url.

The answer for one app looks like this:

{
  "project": {
    "slug": "example-app",
    "name": "Example App",
    "url": "https://dappcdn.com/download/utilities/example-app",
    "latest_release": {
      "id": "00000000-0000-4000-8000-000000000002",
      "version": "2.0.0",
      "latest": true,
      "release_date": "2026-02-01",
      "files": [
        {
          "id": "00000000-0000-4000-8000-000000000001",
          "name": "example-app-2.0.0-setup.exe",
          "label": "Windows installer",
          "os": "windows",
          "size": 12582912,
          "hash": { "md5": "...", "sha1": "...", "sha256": "..." },
          "scanned": true,
          "available": true,
          "download_url": "https://dappcdn.com/api/institutions/v1/projects/example-app/files/00000000-0000-4000-8000-000000000001"
        }
      ]
    },
    "versions": [
      { "id": "00000000-0000-4000-8000-000000000002", "version": "2.0.0", "latest": true, "release_date": "2026-02-01", "file_count": 3 },
      { "id": "00000000-0000-4000-8000-000000000003", "version": "1.9.2", "latest": false, "release_date": "2025-11-20", "file_count": 3 }
    ]
  }
}
  • The slug is the last part of an app's address on our site: /download/utilities/example-app is example-app.
  • versions starts with the latest release ("latest": true), then the others from the newest to the oldest. release_date is null when the developer gave none.
  • os is one of windows, macos, linux, android, ios or other. A checksum we do not have is null.
  • A file that failed our antivirus scan is listed with "available": false and is never served.
  • A key can make around 300 requests a minute, of which 20 downloads, and has a number of downloads a day agreed with you. Download each file once and spread it inside your network (a software distribution share, a package repository, a cache): the API is not meant to be called by every computer.
  • Errors answer with a JSON error and the usual status: 401 for a missing, wrong or expired key, 403 for an app, a network, a country or an action the key does not allow, 404 for an unknown app, version or file, 429 when there are too many requests or the downloads of the day are used up (until 00:00 UTC), 503 while downloads are paused. Retry-After says when to try again.

Getting a key: contact us

The API is not open: every key is issued by us, on request, one institution at a time. Write to us with the name of your institution, a contact person, what you would use the API for and the apps you need. If you want, tell us the networks (IP addresses or ranges) or the countries your requests will come from, and we will limit the key to them.

Keep the key on your servers and in your deployment tools only: not in a public repository, a script shared with others or a web page. If it is ever exposed, tell us and we will replace it at once. Use of the API is covered by our Terms of Service and Privacy Policy.


Examples

Each example reads the latest release of an app, downloads one of its files and checks it against the published checksum. Replace example-app with the slug of the app you need and keep your key in DAPPCDN_KEY (or your tool's secret store).

curl and jq (bash)

#!/usr/bin/env bash
set -euo pipefail

# The latest release of one app
curl -fsS -H "Authorization: Bearer $DAPPCDN_KEY" \
  https://dappcdn.com/api/institutions/v1/projects/example-app

# Its Linux file, saved under its own name and checked against the published SHA-256
{ read -r NAME; read -r URL; read -r SHA256; } < <(
  curl -fsS -H "Authorization: Bearer $DAPPCDN_KEY" https://dappcdn.com/api/institutions/v1/projects/example-app \
    | jq -r '([.project.latest_release.files[] | select(.os == "linux")][0] // {})
             | (.name // ""), (.download_url // ""), (.hash.sha256 // "")'
)
if [ -z "$URL" ]; then echo "No Linux file in the latest release" >&2; exit 1; fi
curl -fL -H "Authorization: Bearer $DAPPCDN_KEY" -o "$NAME" "$URL"
if [ -n "$SHA256" ]; then echo "$SHA256  $NAME" | sha256sum -c -; fi

# An older version, by the version the list in .project.versions gives
curl -fsS -H "Authorization: Bearer $DAPPCDN_KEY" \
  https://dappcdn.com/api/institutions/v1/projects/example-app/releases/1.9.2

PowerShell (Intune, Configuration Manager, PDQ Deploy)

# Intune (Win32 app), Configuration Manager, PDQ Deploy or a scheduled task
# Windows PowerShell 5.1 or PowerShell 7
[Net.ServicePointManager]::SecurityProtocol = [Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls12
$headers = @{ Authorization = "Bearer $env:DAPPCDN_KEY" }
$answer  = Invoke-RestMethod -Uri 'https://dappcdn.com/api/institutions/v1/projects/example-app' -Headers $headers
$file    = $answer.project.latest_release.files | Where-Object { $_.os -eq 'windows' } | Select-Object -First 1
if (-not $file) { throw 'No Windows file in the latest release' }

Write-Output "Latest version: $($answer.project.latest_release.version)"
Invoke-WebRequest -Uri $file.download_url -Headers $headers -OutFile $file.name -UseBasicParsing

if ($file.hash.sha256 -and (Get-FileHash $file.name -Algorithm SHA256).Hash -ne $file.hash.sha256) {
    throw "Checksum mismatch for $($file.name)"
}

AutoPkg (Munki, Jamf Pro)

A recipe for AutoPkg 2.3 or newer, with only its core processors. Add your own processors after the download to import it into Munki or Jamf Pro, as with any other download recipe. AutoPkg writes the variables of a run, the key among them, to its receipts on the Mac that runs it: keep that machine's AutoPkg cache private.

# ExampleApp.download.recipe.yaml
# DAPPCDN_KEY comes from your AutoPkg preferences or the command line, never from the recipe:
#   defaults write com.github.autopkg DAPPCDN_KEY "<key>"
#   autopkg run ExampleApp.download.recipe.yaml -k DAPPCDN_KEY="<key>"
Description: Downloads the latest macOS release of Example App from dAppCDN.
Identifier: com.example.autopkg.download.ExampleApp
MinimumVersion: '2.3'
Input:
  NAME: ExampleApp
  SLUG: example-app
Process:
  - Processor: URLTextSearcher
    Arguments:
      url: https://dappcdn.com/api/institutions/v1/projects/%SLUG%
      request_headers:
        Authorization: Bearer %DAPPCDN_KEY%
      re_pattern: '"version":"(?P<version>[^"]+)"'
  - Processor: URLTextSearcher
    Arguments:
      url: https://dappcdn.com/api/institutions/v1/projects/%SLUG%
      request_headers:
        Authorization: Bearer %DAPPCDN_KEY%
      re_pattern: '"name":"[^"]+\.dmg".*?"download_url":"(?P<download_url>[^"]+)"'
  - Processor: URLDownloader
    Arguments:
      url: '%download_url%'
      request_headers:
        Authorization: Bearer %DAPPCDN_KEY%
      filename: '%NAME%-%version%.dmg'
  - Processor: EndOfCheckPhase

Ansible

# dappcdn_key: kept in Ansible Vault
- name: Read the latest release of Example App
  ansible.builtin.uri:
    url: https://dappcdn.com/api/institutions/v1/projects/example-app
    headers:
      Authorization: "Bearer {{ dappcdn_key }}"
    return_content: true
  register: dappcdn

- name: Pick its Linux file
  ansible.builtin.set_fact:
    dappcdn_file: "{{ dappcdn.json.project.latest_release.files | selectattr('os', 'equalto', 'linux') | first }}"

- name: See whether this version is already there
  ansible.builtin.stat:
    path: "/opt/packages/{{ dappcdn_file.name }}"
    checksum_algorithm: sha256
  register: dappcdn_local

# The key goes to dAppCDN only: get_url would also send it to the CDN behind the redirect
- name: Get the file's short-lived download link
  when: not (dappcdn_local.stat.exists and dappcdn_local.stat.checksum == dappcdn_file.hash.sha256)
  ansible.builtin.uri:
    url: "{{ dappcdn_file.download_url }}"
    headers:
      Authorization: "Bearer {{ dappcdn_key }}"
    follow_redirects: none
    status_code: 302
  register: dappcdn_link

- name: Download it, checked against the published SHA-256
  when: dappcdn_link is not skipped
  ansible.builtin.get_url:
    url: "{{ dappcdn_link.location }}"
    dest: "/opt/packages/{{ dappcdn_file.name }}"
    checksum: "{{ ('sha256:' + dappcdn_file.hash.sha256) if dappcdn_file.hash.sha256 else omit }}"

Using another tool? Any tool that can send an HTTP header works the same way. Write to us and we will help you set it up.