DislifyDislify

Command Palette

Search for a command to run...

API reference

Authenticate. Submit. Receive the result.

A compact reference for integrating Dislify media jobs, quotas, and webhook delivery into a server-side application.

00

Reference

Use @dislify/sdk for media workflows

The official JavaScript/TypeScript SDK v0.2.0 wraps API-key exchange, signed uploads, retries, job and batch polling, typed results, and protected downloads. Use it for image optimization or image, video, and audio batches; the REST endpoints below remain available for lower-level control.

sdk-quick-start
npm install @dislify/sdk

import { readFile } from "node:fs/promises"
import { DislifyClient } from "@dislify/sdk"

const dislify = new DislifyClient({
  apiKey: process.env.DISLIFY_API_KEY,
})

const image = new Blob([await readFile("./hero.png")], {
  type: "image/png",
})

console.log("Starting image optimization...")

const { shareUrl } = await dislify.optimizeImage(image, {
  fileName: "hero.png",
  compression: "balanced",
  onProgress(job) {
    console.log(`${job.status}: ${job.progress ?? 0}%`)
  },
})

console.log("Completed:", shareUrl)
Running this from the CLI? Load your .env with node --env-file=.env app.mjs, or install dotenv and add import "dotenv/config".
01

Reference

Exchange an API key

API keys are long-lived account secrets. Exchange one from your server for a developer token before calling protected job routes.

auth-token
const tokenRes = await fetch("https://api.dislify.com/v1/developers/token", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    apiKey: process.env.DISLIFY_API_KEY,
  }),
})

const { token } = await tokenRes.json()

console.log(token)
02

Reference

Create a compression job

Request a short-lived upload URL, PUT the media directly to private R2 storage, then create the asynchronous compression job with the returned upload ID.

create-job
import { readFile } from "node:fs/promises"

const fileBytes = await readFile("./video.mp4")
const uploadRes = await fetch("https://api.dislify.com/v1/uploads", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    Authorization: `Bearer ${token}`,
  },
  body: JSON.stringify({
    fileName: "video.mp4",
    fileSize: fileBytes.byteLength,
    contentType: "video/mp4",
  }),
})

const upload = await uploadRes.json()

await fetch(upload.uploadUrl, {
  method: "PUT",
  headers: { "Content-Type": upload.contentType },
  body: new Uint8Array(fileBytes),
})

const res = await fetch("https://api.dislify.com/v1/jobs", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    Authorization: `Bearer ${token}`,
  },
  body: JSON.stringify({
    uploadId: upload.uploadId,
    compression: "balanced",
  }),
})

const job = await res.json()

console.log(job.id)
console.log(job.status)
03

Reference

Choose a preset or target size

Use one of eight named presets, or select custom compression and provide an approximate target in bytes or as a percentage of the original file.

gentle~15% smaller

Light optimization for files that are already close to the size you want. Prioritizes visual and audio fidelity.

web~25% smaller

A quality-first preset for websites, portfolios, product pages, and everyday sharing.

balanced~35% smaller

A practical balance between output quality and file-size reduction for general use.

discord

Targets a Discord-friendly output while still keeping the result smaller than the original file.

strong~45% smaller

More aggressive compression for uploads where a noticeably smaller file matters more than perfect fidelity.

maximum~60% smaller

Prioritizes a substantially smaller result while keeping the media usable for normal playback and sharing.

tiny~70% smaller

Pushes hard for a compact result when transfer size is the main concern.

ultra~78% smaller

The most aggressive preset. Best when getting the file as small as practical matters more than fidelity.

Custom target

Set compression: "custom" and send either targetSizeBytes or targetSizePercent. The percentage is the desired output size relative to the source — for example, 55 targets an output around 55% of the original size. Targets must be between 5% and 95% of the source size.

{
  "uploadId": "upload_id",
  "compression": "custom",
  "targetSizePercent": 55
}
04

Reference

Read job status

Check the job while processing or use webhooks to receive completion and failure events automatically. Completed Unlimited jobs also expose the automatic public share URL and its expiration.

job-status
const jobId = "job_123"

const res = await fetch(`https://api.dislify.com/v1/jobs/${jobId}`, {
  method: "GET",
  headers: {
    Authorization: `Bearer ${token}`,
  },
})

const job = await res.json()

console.log(job.id)
console.log(job.status)
console.log(job.downloadUrl)

// Tip:
// You do not need to keep polling this endpoint.
// Register a webhook to receive job.completed and job.failed events automatically.
05

Reference

Download a completed output

The download URL is protected. Send the same temporary Bearer token when requesting the file; the route verifies job ownership before streaming bytes from private R2 storage.

download-output
import fs from "node:fs"

const downloadRes = await fetch(job.downloadUrl, {
  headers: {
    Authorization: `Bearer ${token}`,
  },
})

if (!downloadRes.ok) {
  throw new Error(`Download failed: ${downloadRes.status}`)
}

const bytes = Buffer.from(await downloadRes.arrayBuffer())
fs.writeFileSync(job.outputName || "dislify-output.bin", bytes)
06

Reference

Register and verify webhooks

Store the signing secret when the endpoint is created, verify the raw request body, and route events by the Dislify event header.

register-webhook
const res = await fetch("https://api.dislify.com/v1/developers/webhooks", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    Authorization: `Bearer ${token}`,
  },
  body: JSON.stringify({
    url: "https://your-app.com/api/dislify/webhook",
    events: [
      "upload.received",
      "quota.updated",
      "job.completed",
      "job.failed",
    ],
  }),
})

const data = await res.json()

console.log(data.webhook.id)
console.log(data.webhook.secret)
webhook-handler
import crypto from "node:crypto"
import express from "express"

const app = express()

app.use(
  express.json({
    verify: (req, _res, buf) => {
      req.rawBody = buf.toString("utf8")
    },
  }),
)

const WEBHOOK_SECRET = process.env.DISLIFY_WEBHOOK_SECRET

app.post("/api/dislify/webhook", (req, res) => {
  const signature = req.header("X-Dislify-Signature")
  const event = req.header("X-Dislify-Event")

  const expectedSignature = crypto
    .createHmac("sha256", WEBHOOK_SECRET)
    .update(req.rawBody)
    .digest("hex")

  if (signature !== expectedSignature) {
    return res.status(401).json({
      error: "Invalid webhook signature",
    })
  }

  if (event === "job.completed") {
    console.log("Job completed:", req.body.data)
  }

  if (event === "job.failed") {
    console.log("Job failed:", req.body.data)
  }

  if (event === "upload.received") {
    console.log("Upload received:", req.body.data)
  }

  if (event === "quota.updated") {
    console.log("Quota updated:", req.body.data)
  }

  return res.json({ received: true })
})

app.listen(3001, () => {
  console.log("Webhook server running on port 3001")
})
07

Reference

Default Unlimited API policy

Dislify applies both burst protection and monthly quotas. Completed outputs follow the account retention policy rather than permanent file storage.

60

Job submissions per hour

10,000

Job submissions per month

90 days

Completed-output retention

08

Reference

Endpoint map

The primary routes used by a standard server-side integration.

POST/v1/developers/token
Exchange an API key for an access token
POST/v1/developers/token/refresh
Refresh an authenticated developer token
POST/v1/jobs
Upload media and create a compression job
GET/v1/jobs/:id
Read job state and download information
GET/v1/jobs/:id/download
Download the completed output with the same Bearer token
POST/v1/developers/webhooks
Register a signed webhook endpoint

Keep credentials server-side

Never expose API keys or webhook secrets in client bundles. Use environment variables and verify webhook signatures against the raw request body.

Ready when you are

Ready to connect the pipeline?

Create an Unlimited account, generate an API key, and submit the first media job from your server.