AD SPACE AVAILABLE · BRAND PARTNERS WELCOME

Integrating Dezgo's REST API into Web Applications: A Pay-as-You-Go Architecture Guide

365Finds Editorial
Indexed 11,430 Wiki articles

Put 365 Wiki to work with your AI

Copy the prompt below, paste it into the AI you already use, then ask your question.

Download full Skill

Try it with the prompt first. If you use 365 Wiki often, install the full 365Wiki Skill so you do not have to paste it again. No regular AI? Gemini or Microsoft Copilot on the web will work.

365Wiki Skill

Building image generation and manipulation features into modern web applications often forces solo developers and lean engineering teams into an uncomfortable architectural trade-off. On one end of the spectrum, hosting open-source diffusion models on self-managed cloud GPUs (such as AWS EC2 G5 instances, RunPod, or dedicated modal instances) introduces heavy operational overhead, cold-start latency, driver management, and an idle cost baseline easily exceeding $150 to $400 every month. On the other end, mainstream AI platforms and consumer SaaS products (like Midjourney, Leonardo, or Adobe Firefly) impose mandatory monthly subscriptions, rigid usage tiers, expiring credits, and strict rate limits that do not fit variable, sporadic user traffic.

Dezgo fills this gap by offering a transparent, serverless REST API backed by a true pay-as-you-go financial model. Developers deposit prepaid credits (starting at $10) that never expire, with generation costs billed down to fractions of a cent—such as approximately $0.0019 for a standard 512x512 Stable Diffusion output, scaling predictably with pixel dimensions and sampling steps.

This technical guide walks full-stack engineers through architecting and implementing a production-grade Dezgo integration. We examine the X-Dezgo-Key authentication pattern, direct synchronous requests versus asynchronous web worker queues, implementation of /text2image and /inpainting_sdxl endpoints, real-time balance tracking via response headers, and resilient error recovery.


Architectural Comparison: Self-Hosted GPUs vs. Fixed SaaS vs. Dezgo

Before writing code, consider how Dezgo fits into the web application infrastructure landscape:

DimensionSelf-Hosted GPU Cluster (EC2 / RunPod)Mainstream SaaS (Midjourney / Commercial APIs)Dezgo REST API
Fixed Cost FloorHigh ($150–$500+/mo baseline idle cost)Medium-High ($10–$60+/user/month subscription)Zero ($10 one-time prepaid top-up; pay per render)
Unit EconomicsVariable; wasteful during traffic valleysFixed plan bundles; unused credits expire monthly~$0.0019 per 512px SD image; linear step/pixel scaling
Operational BurdenHigh (CUDA drivers; vLLM/Diffusers; autoscaling)Low (Hosted platform; limited customization)Low (Standard HTTP REST interface; zero GPU ops)
Model FlexibilityMaximum (Any HuggingFace checkpoint or LoRA)Low (Proprietary black-box models only)High (SD 1.5, SD 2.1, SDXL, SDXL Lightning, custom LoRAs)
Response ContractCustom API design requiredOften asynchronous webhooks or Discord botsDirect synchronous binary image stream (image/png)

Dezgo operates on standard HTTP POST requests that stream generated binary image files directly in the response body while transmitting precise financial metadata in response headers.


Authentication and Security Architecture

Every request to the Dezgo API requires authentication via the X-Dezgo-Key HTTP header. API keys are generated within your account console at dezgo.com/account.

The Cardinal Rule: Never Call Dezgo Directly from the Frontend

Because Dezgo keys draw directly against your prepaid cash balance without end-user sandboxing, exposing X-Dezgo-Key in browser network requests or client-side JavaScript creates severe financial risk. Malicious users can extract your key, exhaust your balance in minutes, or trigger abusive content under your account.

A secure web application architecture must always route image generation requests through a trusted backend server or serverless API proxy:

[Browser Client]
       │
       │ 1. POST /api/generate (User Session / JWT / App Quota)
       ▼
[Your Application Backend]
       │
       │ 2. Validate input, deduct internal user tokens
       │ 3. Inject "X-Dezgo-Key" secret header
       │ 4. POST https://api.dezgo.com/text2image
       ▼
[Dezgo REST Engine]
       │
       │ 5. Returns binary PNG stream + usage headers
       ▼
[Your Application Backend]
       │
       │ 6. Parse headers (x-dezgo-job-amount-usd, x-dezgo-balance-total-usd)
       │ 7. Pipe binary buffer to Object Storage (S3 / R2) or direct to client
       ▼
[Browser Client]

Step 1: Text-to-Image Integration (/text2image)

The Dezgo text-to-image endpoint accepts parameters via either multipart/form-data or application/json (with base64 payloads) and returns the rendered image directly as a binary stream (image/png or image/jpeg).

Key Request Parameters

Production Node.js / TypeScript Backend Implementation

Here is an Express/Next.js-compatible backend service using native fetch and FormData:

// server/services/dezgoService.ts
import { Buffer } from "node:buffer";

interface TextToImageOptions {
  prompt: string;
  negativePrompt?: string;
  model?: string;
  guidance?: number;
  steps?: number;
  width?: number;
  height?: number;
}

interface GenerationResult {
  imageBuffer: Buffer;
  contentType: string;
  jobCostUsd: number;
  remainingBalanceUsd: number;
}

export async function generateTextToImage(
  options: TextToImageOptions
): Promise<GenerationResult> {
  const apiKey = process.env.DEZGO_API_KEY;
  if (!apiKey) {
    throw new Error("DEZGO_API_KEY environment variable is not configured.");
  }

  const formData = new FormData();
  formData.append("prompt", options.prompt);
  if (options.negativePrompt) {
    formData.append("negative_prompt", options.negativePrompt);
  }
  if (options.model) {
    formData.append("model", options.model);
  }
  if (options.guidance) {
    formData.append("guidance", options.guidance.toString());
  }
  if (options.steps) {
    formData.append("steps", options.steps.toString());
  }
  if (options.width) {
    formData.append("width", options.width.toString());
  }
  if (options.height) {
    formData.append("height", options.height.toString());
  }

  const response = await fetch("https://api.dezgo.com/text2image", {
    method: "POST",
    headers: {
      "X-Dezgo-Key": apiKey,
    },
    body: formData,
  });

  if (!response.ok) {
    const errorText = await response.text();
    handleDezgoError(response.status, errorText);
  }

  // Parse billing and balance metadata from response headers
  const jobCostUsd = parseFloat(
    response.headers.get("x-dezgo-job-amount-usd") || "0"
  );
  const remainingBalanceUsd = parseFloat(
    response.headers.get("x-dezgo-balance-total-usd") || "0"
  );

  const arrayBuffer = await response.arrayBuffer();
  const imageBuffer = Buffer.from(arrayBuffer);
  const contentType = response.headers.get("content-type") || "image/png";

  return {
    imageBuffer,
    contentType,
    jobCostUsd,
    remainingBalanceUsd,
  };
}

function handleDezgoError(status: number, message: string): never {
  switch (status) {
    case 400:
      throw new Error(`Dezgo Bad Request: ${message}`);
    case 401:
      throw new Error("Dezgo Authentication failed: Check your X-Dezgo-Key.");
    case 402:
      throw new Error("Dezgo Payment Required: Prepaid account balance exhausted.");
    case 429:
      throw new Error("Dezgo Rate Limit: Too many concurrent requests.");
    default:
      throw new Error(`Dezgo API error [HTTP ${status}]: ${message}`);
  }
}

Step 2: SDXL Inpainting Integration (/inpainting_sdxl)

Inpainting allows users to alter specific masked regions of an existing image while keeping surrounding context untouched. Dezgo offers two primary endpoints: /inpainting for standard Stable Diffusion models and /inpainting_sdxl for Stable Diffusion XL high-resolution generation.

Mask Specifications

Inpainting requires two image inputs:

  1. init_image: The baseline image being edited (PNG or JPEG).
  2. mask_image: A grayscale or binary mask image matching the exact dimensions of init_image. White pixels (#FFFFFF / 255) indicate the target zone to replace; black pixels (#000000 / 0) designate the protected zone to keep intact.

Python Backend Implementation (FastAPI / Requests)

# app/services/dezgo_inpainting.py
import os
import requests
from typing import Dict, Any, Tuple

DEZGO_API_KEY = os.environ.get("DEZGO_API_KEY")
INPAINTING_SDXL_URL = "https://api.dezgo.com/inpainting_sdxl"

def execute_sdxl_inpainting(
    prompt: str,
    init_image_bytes: bytes,
    mask_image_bytes: bytes,
    negative_prompt: str = "",
    guidance: float = 7.5,
    steps: int = 30,
) -> Tuple[bytes, Dict[str, Any]]:
    """
    Submits an inpainting task to Dezgo's SDXL endpoint using multipart form-data.
    """
    if not DEZGO_API_KEY:
        raise ValueError("DEZGO_API_KEY is not defined in system environment.")

    headers = {
        "X-Dezgo-Key": DEZGO_API_KEY
    }

    files = {
        "init_image": ("init.png", init_image_bytes, "image/png"),
        "mask_image": ("mask.png", mask_image_bytes, "image/png"),
    }

    data = {
        "prompt": prompt,
        "negative_prompt": negative_prompt,
        "guidance": str(guidance),
        "steps": str(steps),
    }

    response = requests.post(
        INPAINTING_SDXL_URL,
        headers=headers,
        files=files,
        data=data,
        timeout=45
    )

    if response.status_code == 402:
        raise RuntimeError("Dezgo prepaid balance is depleted. Please top up funds.")
    elif response.status_code != 200:
        raise RuntimeError(f"Dezgo Inpainting failed [{response.status_code}]: {response.text}")

    metadata = {
        "job_cost_usd": float(response.headers.get("x-dezgo-job-amount-usd", "0")),
        "remaining_balance_usd": float(response.headers.get("x-dezgo-balance-total-usd", "0")),
        "content_type": response.headers.get("Content-Type", "image/png"),
    }

    return response.content, metadata

Step 3: Handling Synchronous vs. Asynchronous Workflows in Web Apps

Because Dezgo holds the HTTP connection until rendering finishes (typically 2 to 8 seconds depending on step count and model architecture), calling Dezgo synchronously inside a serverless edge function or web request handler can trigger gateway timeouts (such as the default 10-second limit on serverless platforms or 30-second edge limits).

Recommended Pattern: Background Worker Queue with Webhook/SSE

To build a reliable web experience, decouple client request handling from Dezgo rendering using a Redis-backed queue (such as BullMQ in Node.js or Celery in Python):

[Client Web App] 
       │ 1. POST /api/jobs { prompt, mask }
       ▼
[Web Server] ──── 2. Add job to Redis Queue ────► [Redis (BullMQ)]
       │                                                 │
       │ 3. Returns { jobId: "job_9410" } (HTTP 202)    │ 4. Worker pulls job
       ▼                                                 ▼
[Client Web App]                                 [Background Worker]
       │                                                 │
       │ 5. Listen on SSE / WebSocket                    │ 5. POST https://api.dezgo.com/...
       │    OR Poll GET /api/jobs/job_9410               │ 6. Upload output to S3 / R2
       │                                                 │ 7. Record balance & cost in DB
       ◄────── 8. Push "COMPLETED" + CDN Image URL ──────┘

BullMQ Worker Snippet

// workers/renderWorker.ts
import { Worker, Job } from "bullmq";
import { generateTextToImage } from "../services/dezgoService";
import { uploadToS3 } from "../services/storageService";
import { db } from "../services/db";

export const renderWorker = new Worker("image-generation", async (job: Job) => {
  const { prompt, userId, jobId } = job.data;

  // 1. Call Dezgo
  const { imageBuffer, contentType, jobCostUsd, remainingBalanceUsd } =
    await generateTextToImage({ prompt, steps: 30 });

  // 2. Persist generated image to permanent object storage
  const storageUrl = await uploadToS3({
    key: `renders/${userId}/${jobId}.png`,
    body: imageBuffer,
    contentType,
  });

  // 3. Update database record and log compute expenditure
  await db.renderJobs.update({
    where: { id: jobId },
    data: {
      status: "COMPLETED",
      outputUrl: storageUrl,
      costUsd: jobCostUsd,
    },
  });

  // 4. Trigger alert if developer prepaid balance is running low
  if (remainingBalanceUsd < 5.0) {
    await sendSlackAlert(`⚠️ Dezgo API balance low: $${remainingBalanceUsd.toFixed(2)} remaining.`);
  }

  return { storageUrl, jobCostUsd };
});

Managing Prepaid Balance and Production Guardrails

Dezgo does not provide automated recurring billing top-ups; developers manually replenish their prepaid wallet via the account dashboard. Therefore, monitoring balance headers programmatically is vital to prevent sudden service disruptions.

Response Header Telemetry

Every successful render returns the following headers:

Proactive Balance Checking Endpoint

You can check your account's financial status without triggering a generation by calling the transaction endpoint:

curl -s -H "X-Dezgo-Key: YOUR_API_KEY" https://api.dezgo.com/account/tx/last

This returns a JSON object containing your latest transaction index and current balance.

Error Handling Strategy

  1. HTTP 402 (Payment Required): Catch this explicitly in your backend error handler. Route immediate high-priority alerts to engineering channels and return a graceful message to the user ("Image generation is temporarily queued for system maintenance") rather than generic 500 errors.
  2. HTTP 429 (Rate Limit): Dezgo protects infrastructure with concurrency limits. Wrap calls with exponential backoff and jitter (e.g., retry after 1s, 2s, 4s).
  3. HTTP 400 (Bad Request): Commonly caused by mismatched mask dimensions or invalid prompt characters. Always validate that init_image and mask_image match exact pixel dimensions before dispatching to Dezgo.

Conclusion: When Dezgo Fits Best

For solo developers, micro-SaaS builders, and digital product teams needing on-demand AI imagery, Dezgo eliminates the twin headaches of idle GPU hosting and rigid monthly SaaS subscriptions. By combining a backend API proxy, an asynchronous task queue, and programmatic balance tracking using Dezgo's response headers, you can deliver fast, reliable text-to-image and inpainting capabilities at sustainable, sub-cent unit costs.

References