# deAPI Docs Versions (/docs) * [v1 (latest)](/docs/v1) # Architecture & Security (/docs/v1/architecture-and-security) 'Under the Hood' details, encryption mechanisms, and privacy levels. Understanding data processing protocols is critical for ensuring security and privacy. The dryAPI architecture utilizes a decentralized network of verified Workers, maintaining a balance between high-performance inference and robust data protection. 1\. Under the Hood: Security Architecture [#1-under-the-hood-security-architecture] The following section outlines the data flow for a standard inference job (using Image-to-Image as the reference model). **Data Flow** 1. Client → dryAPI Server (HTTPS Encrypted) Requests are initiated via the API. All data transmission is encrypted in transit using HTTPS protocols. 2. Server → Worker The central server designates an appropriate Worker node and transmits the model, parameters, and task specifications. 3. Worker (Processing) The Worker node receives the payload (image, prompt, settings). Data is processed by a local, isolated Python server. 4. Result → Client The generated or modified asset returns to the client via the same encrypted return path. **Security Mechanisms** Multi-layer security measures are implemented to guarantee network integrity and data protection: * **HTTPS Everywhere:** Encryption is enforced at every stage of communication. * **Request Hashing:** Checksums are utilized to prevent Worker spoofing or the submission of fraudulent results. * **Binary Verification:** The Worker application automatically validates checksums for the Python server and models prior to execution, ensuring code integrity. * **Injection Protection:** The execution environment is strictly isolated to prevent code injection that could compromise Worker infrastructure. 2\. Privacy Model & Worker Reliability [#2-privacy-model--worker-reliability] Security in the distributed environment is maintained through a reputation system and strict technical data access controls. **Data Visibility** * dryAPI Server: Accesses prompts and metadata required for job coordination. No long-term storage of sensitive payload data occurs. * Worker: Receives the full payload (e.g., input image), but data resides exclusively in RAM. No disk writes occur, and there is no exposure via a UI. Data extraction would require advanced, real-time reverse engineering. **Additional Safeguards** * Worker Scoring: An automated reputation system identifies and excludes unreliable nodes that fail to complete tasks. * Dual Verification (Optional): For sensitive workloads, task verification by two independent Workers is available (incurring 2x cost, while remaining significantly below standard cloud pricing). 3\. Use Cases: Decentralized vs. Enterprise [#3-use-cases-decentralized-vs-enterprise] The decentralized model is classified as a "Perfect Fit" for: * ✓ Public content transcription (YouTube, X, TikTok, Twitch, Kick) * ✓ Image and video generation applications * ✓ AI workloads devoid of critical data (PII, trade secrets) For these scenarios, Community Workers provide an optimal price-to-performance ratio (estimated 5-10x cost reduction compared to centralized cloud), without unnecessary expenditure on Enterprise-grade infrastructure. **Secure Worker Tier** For Enterprise clients handling sensitive data (internal documentation, prototypes), a Premium tier is being introduced featuring: * Dedicated GPU farms (RTX 4090, H100, RTX 6000 PRO) located in secure Data Centers. * Full infrastructure isolation, audited operators, NDAs, and legal accountability. * Certified privacy standards (at a higher price point) **Additional request** - contact support for more information: [support@dryapi.dev](mailto:support@dryapi.dev) # dryAPI Documentation (v1) (/docs/v1) This version is generated from the live dryAPI documentation index. Sections [#sections] * [API / Analysis](/docs/v1/api/analysis/audio-to-text-spaces) * [API](/docs/v1/api/errors) * [API / Generation](/docs/v1/api/generation/audio-to-video) * [API / Prompt Enhancement](/docs/v1/api/prompt-enhancement/image-prompt-booster) * [API / Transformation](/docs/v1/api/transformation/background-removal) * [API / Utilities](/docs/v1/api/utilities/check-balance) * [Core](/docs/v1/architecture-and-security) * [Execution & Integrations](/docs/v1/execution-modes-and-integrations/execution-modes-and-http-queue) * [Other](/docs/v1/other/faq-frequently-asked-questions) API schema [#api-schema] * [OpenAPI schema](/docs/v1/openapi) * [API reference](/docs/v1/api-reference) *** Generated by `pnpm docs:sync:dryapi`. # Introduction (/docs/v1/introduction) > Fast and affordable inference for open-source AI models What is dryAPI? [#what-is-dryapi] dryAPI provides fast and affordable inference for open-source AI models — without infrastructure overhead. Run image, video, audio, and text workloads through a single, consistent API. dryAPI handles GPU orchestration, execution, and scaling so you can focus on building applications, not managing infrastructure. Under the hood, dryAPI runs on a global, decentralized GPU network, allowing significantly lower inference costs compared to traditional cloud providers. *** What you can build [#what-you-can-build] With dryAPI, you can power a wide range of AI applications: * **Image generation** — Create and edit images using modern diffusion models * **Text-to-speech** — Generate natural-sounding speech with preset voices, voice cloning, or voice design * **Music generation** — Create music tracks with lyrics, tempo, key, and style control * **Video AI** — Video generation and transcription from YouTube, Twitch, Kick,TikTok and X * **Document & text processing** — OCR and text extraction from documents and images * **Multimodal workflows** — Combine text, image, audio, and video in a single application * **Image enhancement** — Upscale images to higher resolution A full, up-to-date list of supported models is available here: * [Available models](/docs/v1/models) - View all supported AI models and their capabilities *** API Reference for AI Assistants [#api-reference-for-ai-assistants] If you are building an AI agent or integrating AI assistance into your development workflow, you can use the `llms.txt` file below to give your model structured access to the complete dryAPI reference. The file provides canonical API endpoints, usage documentation, and stable links to all relevant sections of the platform. Simply include or link to this file in your AI tooling or agent configuration to enable accurate and up-to-date access to the dryAPI API. * [llms.txt](https://dryapi.dev/llms.txt) - [https://dryapi.dev/llms.txt](https://dryapi.dev/llms.txt) # Limits & Quotas (/docs/v1/limits-and-quotas) This section contains a description of rate limits and file upload specifications. dryAPI is engineered for High Throughput capability upon deployment. Unlike traditional providers, API scalability is not restricted by complex access levels during the initial integration phase. *** Account Types [#account-types] All new accounts start as **Basic** and can upgrade to **Premium** by making any payment. | Type | Qualification | | ----------- | ------------------------------- | | **Basic** | New accounts (no payments made) | | **Premium** | Any payment made via Stripe | > **NOTE** > > Upon registration, you receive a **$5 bonus** added to your balance. This bonus is available for **Basic accounts** with conservative rate limits designed for testing and evaluation. > > To upgrade to **Premium** (300 RPM, unlimited daily requests), simply top up your account with any available amount. Your remaining bonus balance carries over — for example, if you use $2 of your bonus and then purchase $10, your total balance becomes $13 ($3 remaining + $10 purchased), now usable with Premium limits. > **WARNING** > > Accounts registered with temporary or disposable email addresses do not receive the $5 bonus. We value long-term users and honest usage. *** Rate Limits [#rate-limits] Rate limits are defined per endpoint as: * **RPM** — Requests Per Minute * **RPD** — Requests Per Day Limits reset daily at **midnight UTC**. *** Basic Limits [#basic-limits] Basic accounts have conservative limits designed for testing and evaluation. Generation Endpoints [#generation-endpoints] | Endpoint | Models | RPM | RPD | | ------------------------------ | ------------------------------------------------------------------------- | --- | --- | | `/api/v1/client/txt2img` | `Flux1schnell`, `ZImageTurbo_INT8, Flux_2_Klein_4B_BF16` | 3 | 100 | | `/api/v1/client/txt2video` | `Ltxv_13B_0_9_8_Distilled_FP8`, `Ltx2_19B_Dist_FP8, Ltx2_3_19B_Dist_INT8` | 1 | 15 | | `/api/v1/client/img2video` | `Ltxv_13B_0_9_8_Distilled_FP8`, `Ltx2_19B_Dist_FP8, Ltx2_3_19B_Dist_INT8` | 1 | 15 | | `/api/v1/client/aud2video` | `Ltx2_3_19B_Dist_INT8` | 1 | 15 | | `/api/v1/client/txt2audio` | `Kokoro`, `Chatterbox`, `Qwen3_TTS` | 5 | 300 | | `/api/v1/client/txt2music` | `ACE-Step-v1.5-turbo` | 1 | 15 | | `/api/v1/client/txt2embedding` | `Bge_M3_INT8` | 10 | 500 | Analysis Endpoints [#analysis-endpoints] | Endpoint | Models | RPM | RPD | | ---------------------------------- | -------------------- | --- | --- | | `/api/v1/client/img2txt` | `Nanonets_Ocr_S_F16` | 5 | 50 | | **Whisper Transcription (shared)** | `WhisperLargeV3` | 1 | 10 | > **WARNING** > > **Whisper Shared Limit:** All four Whisper transcription endpoints share a single combined limit of **1 RPM** and **10 RPD**: > > * `/api/v1/client/vid2txt` — Video URL transcription (YouTube, X, Twitch, TikTok, Kick) > * `/api/v1/client/videofile2txt` — Video file upload transcription > * `/api/v1/client/aud2txt` — X Spaces transcription > * `/api/v1/client/audiofile2txt` — Audio file upload transcription > > For example: 5× `/vid2txt` + 3× `/aud2txt` + 2× `/audiofile2txt` = 10 RPD ✓ Transformation Endpoints [#transformation-endpoints] | Endpoint | Models | RPM | RPD | | ---------------------------- | ---------------------------------------------- | --- | --- | | `/api/v1/client/img2img` | `Flux_2_Klein_4B_BF16, QwenImageEdit_Plus_NF4` | 1 | 15 | | `/api/v1/client/img-rmbg` | `Ben2` | 5 | 100 | | `/api/v1/client/img-upscale` | `RealESRGAN_x4plus` | 5 | 100 | Utility Endpoints [#utility-endpoints] | Endpoint | RPM | RPD | | ----------------------------------------------- | --- | --- | | Price Calculation (`/price-calculation/*`) | 50 | 200 | | Request Status (`/request-status/{request_id}`) | 50 | 200 | *** Premium Limits [#premium-limits] Premium accounts have high limits suitable for production workloads. All endpoints share a unified **300 RPM** with **unlimited daily requests**. | Endpoint | Models | RPM | RPD | | ------------------------------ | -------------------------------------------------------------------------- | --- | --------- | | `/api/v1/client/txt2img` | `Flux1schnell`, `ZImageTurbo_INT8, Flux_2_Klein_4B_BF16` | 300 | Unlimited | | `/api/v1/client/txt2video` | `Ltxv_13B_0_9_8_Distilled_FP8`, `Ltx2_19B_Dist_FP8 , Ltx2_3_19B_Dist_INT8` | 300 | Unlimited | | `/api/v1/client/img2video` | `Ltxv_13B_0_9_8_Distilled_FP8`, `Ltx2_19B_Dist_FP8, Ltx2_3_19B_Dist_INT8` | 300 | Unlimited | | `/api/v1/client/aud2video` | `Ltx2_3_19B_Dist_INT8` | 300 | Unlimited | | `/api/v1/client/txt2audio` | `Kokoro`,`Chatterbox`, `Qwen3_TTS` | 300 | Unlimited | | `/api/v1/client/txt2music` | `ACE-Step-v1.5-turbo` | 300 | Unlimited | | `/api/v1/client/txt2embedding` | `Bge_M3_INT8` | 300 | Unlimited | | `/api/v1/client/img2txt` | `Nanonets_Ocr_S_F16` | 300 | Unlimited | | `/api/v1/client/vid2txt` | `WhisperLargeV3` | 300 | Unlimited | | `/api/v1/client/videofile2txt` | `WhisperLargeV3` | 300 | Unlimited | | `/api/v1/client/aud2txt` | `WhisperLargeV3` | 300 | Unlimited | | `/api/v1/client/audiofile2txt` | `WhisperLargeV3` | 300 | Unlimited | | `/api/v1/client/img2img` | `Flux_2_Klein_4B_BF16, QwenImageEdit_Plus_NF4` | 300 | Unlimited | | `/api/v1/client/img-rmbg` | `Ben2` | 300 | Unlimited | | `/api/v1/client/img-upscale` | `RealESRGAN_x4plus` | 300 | Unlimited | > **INFO** > > Premium Whisper endpoints have independent limits — each endpoint has its own 300 RPM allocation. *** Endpoints Without Rate Limits [#endpoints-without-rate-limits] The following endpoints have no rate limits for all accounts: * **Utilities** — `/balance`, `/models` *** Basic vs Premium Comparison [#basic-vs-premium-comparison] | Aspect | Basic | Premium | | ------------------- | ------------------------- | ------------------------ | | RPM Limits | 1–10 RPM | 300 RPM (all endpoints) | | Daily Limits (RPD) | Limited | Unlimited | | Whisper Limit | Shared across 4 endpoints | Independent per endpoint | | Upgrade Requirement | — | Any payment via Stripe | *** dryAPI vs. Traditional Providers [#dryapi-vs-traditional-providers] Many AI infrastructure providers enforce restrictive initial limits, necessitating complex queue management systems for developers. **Getting Started** * Traditional Providers: Often require credit card verification or initial payment before any API access. * dryAPI: Immediate access with $5 bonus upon registration — no payment required to start testing. **Scaling to Production** * Traditional Providers: Typically require specific monetary spend thresholds (e.g., $50+) and time delays (weeks/months) to unlock higher rate limits. * dryAPI: Instant upgrade to Premium (300 RPM, unlimited daily requests) with any available top-up amount ($10, $25, or $50). **Limit Structure** * Traditional Providers: Often utilize separate quotas for tokens (TPM), requests (RPM), daily limits (RPD), and per-model restrictions. * dryAPI Premium: Simple unified structure — 300 RPM across all endpoints with unlimited daily requests. For High Volume Production requirements beyond Premium limits, please contact support via: [support@dryapi.dev](mailto:support@dryapi.dev) *** File Uploads [#file-uploads] The majority of endpoints (Video-to-Text, Audio-to-Text, Image-to-Image) support direct binary file uploads or URL-based inputs. The global limits for file uploads are specified below. **1. Video** (Video-to-Text, Image-to-Video) * Max size: 80 MB * Supported Formats: MP4, MPEG, QuickTime (MOV), AVI, WMV, OGG **2. Audio** (Audio-to-Text, Voice Cloning reference audio, Audio-to-Video, Music reference audio) * Max size: 80 MB * Supported Formats: AAC, MP3, OGG, WAV, WebM, FLAC * Voice Cloning reference audio: max 10 MB, 3–10 seconds duration. Supported formats: MP3, WAV, FLAC, OGG, M4A. * Audio-to-Video conditioning audio: max 20 MB. Supported formats: MP3, WAV, OGG, FLAC. * Music reference audio (style transfer): max 10 MB. Supported formats: MP3, WAV, FLAC, OGG, M4A. **3. Images** (Image-to-Image, OCR) * Max size: 10 MB * Supported Formats: JPG, JPEG, PNG, GIF, BMP, WebP *** Model Parameter Limits [#model-parameter-limits] Certain parameters — such as maximum character count, image resolution, frame count, or audio duration — are **model-specific** and may differ between models available on the same endpoint. These limits are returned dynamically via the [Models endpoint](/docs/v1/api/utilities/model-selection): ```bash theme={null} GET https://api.dryapi.dev/api/v1/client/models ``` Check the `limits` field in each model object to see the applicable constraints before submitting a request. This ensures your inputs stay within the accepted bounds for the specific model you're using. *** URL Input & Duration Limits [#url-input--duration-limits] For endpoints processing content via direct URLs (e.g., X Spaces), specific duration limits apply regardless of file size. **1. Audio-to-Text** (X/Twitter Spaces) * Max Duration: 600 minutes * Note: Processing speeds for X Spaces may vary due to external bandwidth limits. **2. Video-to-Text** (X, Kick, Twitch) * Max Duration: 600 minutes *** Rate Limit Errors [#rate-limit-errors] When you exceed your rate limit, the API returns a `429 Too Many Requests` response. **How to handle:** 1. **RPM exceeded** — Wait 60 seconds before retrying 2. **RPD exceeded** — Wait until midnight UTC for daily reset 3. **Need higher limits?** — [Upgrade to Premium](https://dryapi.dev/billing) with any payment for 300 RPM and unlimited daily requests # Models (/docs/v1/models) > How to discover, select, and use models on dryAPI **dryAPI** gives you a unified API across multiple open-source models running on a decentralized GPU cloud. We regularly expand the model lineup — new models, new capabilities, better performance — so your integration can always take advantage of the latest options. The [Model Selection](/docs/v1/api/utilities/model-selection) endpoint returns the live, authoritative list of all available models, their slugs, limits, and defaults. **Use it as the starting point for every integration.** > **TIP** > > This page explains how model selection works and how to use the endpoint. For the actual list of models and their exact slugs, always refer to the [Model Selection](/docs/v1/api/utilities/model-selection) endpoint. *** Fetching the live model list [#fetching-the-live-model-list] Before you start building, call the models endpoint to discover what's available: ```bash theme={null} curl -X GET "https://api.dryapi.dev/api/v1/client/models" \ -H "Authorization: Bearer $DRYAPI_API_KEY" \ -H "Accept: application/json" ``` The response returns a paginated `data` array of model objects. Each object contains: | Field | Description | | ----------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `name` | Human-friendly display name (for UI only — never send this to the API). | | `slug` | **`The exact string to pass as the model parameter`** in any task endpoint. | | `inference_types` | Array of task types this model supports (e.g. `["txt2img"]`, `["img2video", "txt2video"]`). | | `info.limits` | Min/max constraints for parameters like width, height, steps, frames, fps, etc. Fields vary per model type. | | `info.features` | Capability flags — e.g. `supports_guidance`, `supports_negative_prompt`, `supports_steps`, `supports_last_frame`. Not every model includes this field; some return it as an empty object. | | `info.defaults` | Recommended default values for each parameter. Not every model includes this field. | | `loras` | Array of available LoRA adapters (`display_name` + `name`). Present only on models that support LoRAs. | | `languages` | Array of supported languages, each with available voices. Present only on speech models. | > **NOTE** > > Not every model returns all fields. For example, a transcription model may return an empty `info`, while an image-generation model will include detailed `limits`, `features`, and `defaults`. Always check for the presence of fields before using them. You can filter the list by task type using the `filter[inference_types]` query parameter: ```bash theme={null} # Get only image-generation models curl -X GET "https://api.dryapi.dev/api/v1/client/models?filter[inference_types]=txt2img" \ -H "Authorization: Bearer $DRYAPI_API_KEY" \ -H "Accept: application/json" ``` See the full endpoint spec → [Model Selection](/docs/v1/api/utilities/model-selection) *** How model selection works [#how-model-selection-works] * **Every task endpoint requires a model parameter.** Pass the `slug` value returned by the models endpoint — not the display name. * **Quality ↔ Speed trade-off.** Larger models often yield higher quality but cost more and take longer. See the [Pricing](/docs/v1/pricing) page for per-task rates. * **Versioning & lifecycle.** Models may be updated, superseded, or deprecated. Re-fetch the model list periodically to stay current. *** Supported tasks [#supported-tasks] The table below shows which **task types** dryAPI supports. To see which models are currently available for a given task, query the models endpoint with the corresponding `filter[inference_types]` value. | Task | `inference_types` value | What it does | | ------------------- | ----------------------- | ----------------------------------------------------------------------------------------------------------------- | | Text-to-Image | `txt2img` | Generate images from text prompts — concept art, prototyping, creative exploration. | | Image-to-Image | `img2img` | Transform existing images — style transfer, edits, inpainting, outpainting. | | Text-to-Speech | `txt2audio` | Turn text into natural voice — narration, accessibility, product voices. Supports voice cloning and voice design. | | Text-to-Music | `txt2music` | Generate music tracks from text — background music, jingles, songs with vocals. | | Video-to-Text | `video2text` | Transcribe video by URL (YouTube, Twitch, Kick, X , TikTok) into text. | | Audio-to-Text | `audio2text` | Transcribe audio by URL into text — subtitles, notes, search, accessibility. | | Video File-to-Text | `video_file2text` | Transcribe an uploaded video file into text. | | Audio File-to-Text | `audio_file2text` | Transcribe an uploaded audio file into text. | | Image-to-Text (OCR) | `img2txt` | Extract text and meaning from images — OCR, descriptions, accessibility. | | Text-to-Video | `txt2video` | Generate short AI video clips from a text prompt. | | Image-to-Video | `img2video` | Animate a still image into a short video clip. | | Audio-to-Video | `aud2video` | Generate video conditioned on an audio file and a text prompt. | | Text-to-Embedding | `txt2embedding` | Create vector embeddings — search, RAG, semantic similarity, clustering. | | Background Removal | `img-rmbg` | Remove background from images — product photos, portraits, compositing. | | Image Upscale | `img-upscale` | Upscale images to higher resolution. | > **NOTE** > > Some models support **multiple tasks** (e.g. both `txt2img` and `img2img`). The models endpoint will list all supported `inference_types` for each model. *** Choosing the right model [#choosing-the-right-model] When the models endpoint returns several options for the same task, use these guidelines: **Image generation** — Start with the fastest model for iteration. Increase steps and resolution for final quality. If the model object includes a non-empty `loras` array, you can use LoRA adapters for style control. **Speech generation (TTS)** — Check the model's `languages` array for available languages and voices. Use `info.defaults` for recommended speed and format settings. The endpoint supports three modes: `custom_voice` (preset speakers), `voice_clone` (clone from reference audio), and `voice_design` (create voice from a text description). Not all models support all modes — check model capabilities before selecting a mode. **Music generation** — Provide a text description (`caption`) of the desired music style. Optionally include `lyrics` (use `"[Instrumental]"` for instrumental tracks), `bpm`, `keyscale`, and `timesignature` to fine-tune the output. You can also upload a `reference_audio` file for style transfer. Check `info.limits` for supported duration range and inference steps. Use fewer steps with turbo models (e.g. 8) and more steps with base models (e.g. 32+). **Transcription (Video/Audio-to-Text)** — Transcription models support both URL-based and file-upload transcription. For long content, enable timestamps (`include_ts: true`). URL-based transcription works with YouTube, Twitch, Kick, TikTok and X/Twitter. **OCR (Image-to-Text)** — Check `info.limits` for the maximum supported image dimensions. For complex layouts, consider multiple passes or post-processing. **Video generation** — Start with low frame counts to validate aesthetics, then scale up. Check `info.limits.max_frames`, `min_frames`, and `max_fps` for each model. Some models support a `last_frame` feature (see `info.features.supports_last_frame`). For audio-to-video, provide an audio file to condition the video generation alongside your text prompt — some models (e.g. LTX 2.3) support `txt2video`, `img2video`, and `aud2video` tasks. **Embeddings** — Check `info.limits.max_input_tokens` and `max_total_tokens` for batch sizing. Use for semantic search, clustering, and retrieval-augmented generation (RAG). **Background removal** — Check `info.limits.max_width` and `max_height` for the maximum supported resolution. **Image upscale** — Check `info.limits` for input size constraints. *** Parameter limits & resolution rules [#parameter-limits--resolution-rules] Each model defines its own limits in the `info.limits` object. These limits vary between models and task types. Common fields include: * **Dimensions:** `min_width`, `max_width`, `min_height`, `max_height`, and (for image models) `resolution_step` — the value that width/height must be divisible by. * **Steps:** `min_steps`, `max_steps` — how many inference steps the model supports. * **Video-specific:** `min_frames`, `max_frames`, `min_fps`, `max_fps`. * **Text-specific:** `max_input_tokens`, `max_total_tokens` (for embedding models), `min_text`, `max_text` (for speech models). If you provide image dimensions that are not aligned to the required step, the API may adjust them automatically. To avoid unexpected output sizes, always round your `width` and `height` to a multiple of the model's `resolution_step` before sending the request. Some models do not support guidance. Check `info.features.supports_guidance` — if it's `false`, do not send a guidance value, or set it to `0`. > **TIP** > > Always read `info.limits` and `info.defaults` from the models endpoint for the specific model you're using. Do not assume that limits from one model apply to another. *** API usage examples [#api-usage-examples] **1. Discover models for your task** ```bash theme={null} # Fetch all text-to-image models curl -X GET "https://api.dryapi.dev/api/v1/client/models?filter[inference_types]=txt2img" \ -H "Authorization: Bearer $DRYAPI_API_KEY" \ -H "Accept: application/json" # Read the response: pick a slug, note its limits and defaults. ``` **2. Use the slug in a generation request** ```bash theme={null} curl -X POST "https://api.dryapi.dev/api/v1/client/txt2img" \ -H "Authorization: Bearer $DRYAPI_API_KEY" \ -H "Content-Type: application/json" \ -H "Accept: application/json" \ -d '{ "prompt": "isometric cozy cabin at dusk, soft rim light", "model": "", "width": 768, "height": 768, "steps": 4, "seed": 12345 }' ``` > **WARNING** > > Replace `` with an actual `slug` value from the models endpoint. The `seed` field is required for image generation. Check `info.limits` for valid ranges of `width`, `height`, `steps`, and other parameters before sending. **3. Transcribe a video by URL** ```bash theme={null} curl -X POST "https://api.dryapi.dev/api/v1/client/vid2txt" \ -H "Authorization: Bearer $DRYAPI_API_KEY" \ -H "Content-Type: application/json" \ -H "Accept: application/json" \ -d '{ "video_url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ", "include_ts": true, "model": "" }' ``` Jobs return a `request_id`. Poll results with `GET /api/v1/client/request-status/{request_id}`. *** Best practices [#best-practices] * **Resolve models during integration.** Fetch the model list when building your integration and re-fetch periodically (e.g. daily or on deployment) to stay current. There's no need to call it on every request — the list doesn't change that often. * **Respect info.limits and info.defaults.** Use the returned defaults as a starting point. Stay within min/max boundaries to avoid unexpected rounding or errors. Note that some required fields (like `seed` for image generation) may not be listed in the model response — refer to the task endpoint docs for the full set of required parameters. * **Pin slugs only when you need reproducibility.** If you need consistent results across calls, keep the same slug and seed. But check the model list periodically — a slug may be retired and replaced. * **Budget before scaling.** Larger models and higher resolution/steps cost more — see the [Pricing](/docs/v1/pricing) page for per-task rates. * **Handle deprecation gracefully.** If a model returns an error, re-fetch the model list and switch to a suitable alternative. *** For AI agents & LLMs [#for-ai-agents--llms] If you are an AI agent, MCP client, or LLM integrating with dryAPI: 1. **Call** `GET /api/v1/client/models` at the start of your session to get the current model list. Do not rely on model slugs from training data, cached documentation, or prior conversations — they may be outdated. 2. **Use** `filter[inference_types]` to narrow down to the task you need (e.g. `txt2img`, `txt2audio`, `aud2video`). 3. **Read** `info.limits` and `info.defaults` from the response to construct valid request parameters. Also consult the task endpoint docs for required fields that may not appear in the model response (e.g. `seed` for image generation). 4. **Pass** the `slug` field (not `name`) as the `model` parameter in task endpoints. 5. **If a model slug returns an error**, re-fetch the model list — the model may have been deprecated or replaced. *** Related docs [#related-docs] * [Model Selection endpoint](/docs/v1/api/utilities/model-selection) — the live API spec for fetching models. * [Pricing](/docs/v1/pricing) — cost per task and model tier. * [Execution Modes](/docs/v1/execution-modes-and-integrations/execution-modes-and-http-queue) — sync, async, webhooks, WebSockets. # OpenAPI (/docs/v1/openapi) The machine-readable schema is available at [openapi.json](/openapi.json). Browse the generated [API reference](/docs/v1/api-reference). # Pricing (/docs/v1/pricing) Example pricing is shown below for reference; exact, up-to-date rates are always available from the API. **dryAPI** uses a **pay-as-you-go pricing model**, where costs are calculated dynamically per task based on the resource usage, such as resolution, steps, duration, or number of output characters. The pricing examples shown on the public site ([https://dryapi.dev/#pricing](https://dryapi.dev/#pricing)) serve as reference points; final cost is determined by the API at runtime depending on the selected model and parameters. Pricing Overview [#pricing-overview] > **INFO** > > Up to date prices are always available via endpoint /price-calculation for the selected model | Task Type | Pricing Metric | Example Rate | Notes | | ------------------------------------------------- | ----------------------------------- | --------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------- | | Text-to-Image (Flux.1 schnell) | resolution × steps | 0.00136 USD for 512x512, 4 steps | Uses Flux Schnell as baseline in sample calculator | | Text-to-Image (Z-Image-Turbo INT8) | resolution × steps | 0.00405 USD for 512x512, 4 steps | Generates very realistic images | | Text-to-Image (Flux.2 Klein 4B BF16) | resolution × steps | 0.00186 USD for
512x512, 4 steps | Unified generation & editing | | Image-to-Image | steps (style transfer) | \~0.0132 USD for 512x512, 20 steps | Cost scales with steps and GPU time | | Text-to-Speech (TTS) | number of characters | 0.77 USD per 1 M characters | Adjustable speed multipliers (fast = 0.5× cost, slow = 2× cost). Supports voice cloning and voice design modes. | | Text-to-Music | duration + inference steps | Use `/price-calculation` endpoint | 10–600 second tracks; cost scales with duration and inference steps | | Text-to-Video | video duration + resolution | 0.001737 USD for 2s, 256×256 | 2–5 second clips; higher res or steps increase cost | | Image-to-Video | source image + motion interpolation | 0.001737 USD for 2s, 256×256 | 2–5 second output, smooth motion | | Video-to-Text (X, Twitch, Kick, YT Transcription) | video length | from 0.021 USD per hour | Supports timestamps, multilingual | | Image-to-Text (OCR) | output characters | 0.00928 USD per 1,000 output chars (for 1024×1024 images) | Also includes object detection, scene understanding | | Text-to-Embedding | number of tokens processed | 0.000068 USD per 1,000 tokens | Supports large-scale semantic search and RAG; cost scales linearly with token count | *** Pricing by Task [#pricing-by-task] **Text-to-Image (Image Generation)** * Users define width, height, steps via the API or UI. * Public example: Flux Schnell model is used to estimate cost in the UI; for example, 512x512 at 4 steps gives **0.00136 USD**. For the Z-Image-Turbo INT8 model with the same parameters, the price is **0.00405 USD**, but the advantage is very realistic images. * Higher resolutions and more steps yield better quality but incur higher cost. * Important: For models other than Flux Schnell, pricing is model-specific and calculated on the server side. **Text-to-Speech (TTS / Speech Generation)** * Charged per character in your input (e.g. 1M characters → **0.77 USD**). * Playback speed modifiers: * Standard (1.0×): base cost * Fast (2.0×): 0.5× the base cost * Slow (0.5×): 2.0× the base cost * Useful tip: using faster playback (2×) for drafts can reduce cost by \~50%. * All three TTS modes (custom\_voice, voice\_clone, voice\_design) use the same per-character pricing model. **Text-to-Music (Music Generation)** * Price depends on track duration (10–600 seconds) and the number of inference steps. * Turbo models use fewer steps (e.g. 8) and are cheaper; base models use more steps (e.g. 32+) for higher quality. * Use the `/price-calculation` endpoint with your `model`, `duration`, and `inference_steps` to get exact pricing before generation. **Text-to-Video** * Price depends on clip duration (2–5 seconds) and resolution. * Example public rate: **0.001737 USD** for a 2-second clip at 256x256. * You can scale resolution or duration, but cost increases accordingly. **Image-to-Image (Image Transformation)** * Transforms an existing image based on a new prompt or style. * Pricing scales with the number of inference steps and GPU time required — similar to Text-to-Image tasks. * Example: a 20-step transformation costs roughly the same as generating a 512×512 image. * Fewer steps → faster & cheaper transfers; more steps → better fidelity. **Image-to-Video** * Transform a static image into a motion clip (2–5 seconds) with interpolation. * Example: 256x256 for 2 seconds costs **0.001737 USD**. * Use lower resolution or shorter duration to reduce cost. * Use motion parameters in prompts to guide movement. **Video-to-Text (Transcription)** * Billed per hour of video processed. * Sample public rate: **0.021 USD per hour**. * For 5 minutes, cost is estimated at **0.003613 USD**. * Supports timestamps, multilingual transcription, and batching for better throughput. **Image-to-Text (OCR / VLM)** * Charged based on number of characters recognized in output. * Baseline rate: **0.00928 USD** per 1,000 output characters (for 1024×1024 images). * Example outputs: * Single photo (≈20 chars) → **0.000186 USD** * Math expression (\~350 chars) → **0.0032 USD** * Book page (\~1,500 chars) → **0.0139 USD** * Volume discounts available for bulk processing (100k+ images)—contact sales. **Text-to-Embedding (Vector Representations)** * Pricing is based on the number of tokens processed. * Sample public rate: **0.000093 USD** per 1,000 tokens (client-side pricing). * Embeddings are typically used for semantic search, retrieval-augmented generation (RAG), clustering, and similarity matching. * Costs scale linearly with token count, making it efficient even at large volumes. * Important: Different embedding models may have varying dimensionality (e.g. 768 vs. 1024), but pricing is standardized per token for simplicity. *** Best Practices & Guidance [#best-practices--guidance] * Use the public calculator as a guide, but always rely on the API's final cost calculation (model + parameters). * Avoid hardcoding prices or cost assumptions—always fetch or compute cost based on actual model usage. * For reproducibility (e.g. in production or experiments), pin model versions and seeds so results are consistent across runs. * Prepare fallback options in your integration: if a model is deprecated or disabled, switch to a sensible alternative automatically. * Monitor usage and budget: higher resolution, longer clips, or more steps increase costs proportionally. *** **Link to live pricing page for reference:** [https://dryapi.dev/#pricing](https://dryapi.dev/#pricing) # Quickstart (/docs/v1/quickstart) **dryAPI** is a high-performance inference platform built specifically for developers seeking a fast, reliable, and simple way to integrate cutting-edge AI capabilities into their applications. This guide will help you quickly set up your account, obtain your API key, load credits, and begin using our API. *** 1\. Sign In to Your Account [#1-sign-in-to-your-account] Create your free account at [dryapi.dev](https://dryapi.dev/register) to get started. All new users receive a **$5 sign-up bonus** with a **Basic** account — no credit card required. *** 2\. Obtain Your API Key [#2-obtain-your-api-key] dryAPI uses token-based authentication. Every request must include your personal API key, provided via an HTTP header: ``` Authorization: Bearer YOUR_API_KEY ``` To get your API key: * Sign up or log in to your account. * Navigate to Dashboard → Settings → API Keys. * Click "Create new secret key". * Your API key will be generated instantly. *** 3\. Load Credits to Your Account [#3-load-credits-to-your-account] dryAPI operates on a pay-as-you-go model. | Account Type | Description | | ------------ | ------------------------------------------------------ | | **Basic** | $5 welcome bonus, conservative rate limits for testing | | **Premium** | 300 RPM, unlimited daily requests across all endpoints | Your **$5 bonus** is available immediately upon registration for testing with Basic rate limits. To upgrade to **Premium** (300 RPM and unlimited daily requests), simply top up your account with any available amount ($10, $25, or $50) via Stripe. Your remaining bonus balance carries over after upgrade. To add funds, go to your [Dashboard → Billing](https://dryapi.dev/billing) section. > **INFO** > > For detailed rate limits per endpoint, see [Limits & Quotas](/docs/v1/limits-and-quotas). *** 4\. Start Using the API [#4-start-using-the-api] Once your API key is activated and your account has sufficient credits, you can start making requests to dryAPI immediately. **Available Services:** * **Text-to-Image** – Generate visuals from descriptive text prompts. * **Text-to-Speech (TTS)** – Convert text into high-quality spoken audio. Supports preset voices, voice cloning from reference audio, and voice design from text descriptions. * **Text-to-Music** – Generate music tracks from text descriptions with control over lyrics, tempo, key, and style. * **Video-to-Text** – Automatically transcribe audio and video files. Transcript from url X, Twitch, Kick, TikTok, YouTube. * **Audio-to-Text** - Ability to transcribe from X (Twitter) Spaces. * **Image-to-Text** – Extract written content from images using AI-powered optical character recognition (OCR). * **Text-to-Video** – Generate dynamic video content from descriptive text prompts using advanced generative models. * **Image-to-Video** – Transform static images into animated video sequences with motion synthesis and scene expansion. * **Image-to-Image** – Modify or restyle existing images based on new prompts, masks, or style instructions. * **Image Background Removal** – Remove backgrounds from images for product photos, portraits, and transparent PNGs. * **Image Upscale** – Upscale images to higher resolution using AI-powered super-resolution models. * **Text-to-Embedding** – Convert text into vector embeddings for semantic search, similarity matching, and retrieval-augmented generation (RAG). *** dryAPI is actively evolving — new AI services, models, and features will be added regularly to expand what's possible with our platform. Stay up to date by following our announcements. # Errors (/docs/v1/api/errors) > HTTP status codes and error responses returned by dryAPI dryAPI uses conventional HTTP response codes to indicate the success or failure of an API request. Codes in the `2xx` range indicate success. Codes in the `4xx` range indicate an error from the provided information (e.g., missing required parameter, unauthorized access). Codes in the `5xx` range indicate an error with dryAPI servers. HTTP Status Codes [#http-status-codes] | Code | Status | Description | | ----- | --------------------- | ---------------------------------------------------------------- | | `200` | OK | Request succeeded. Response contains requested data. | | `401` | Unauthorized | Invalid or missing API key. | | `404` | Not Found | The requested resource (job, model) does not exist. | | `422` | Unprocessable Entity | Request validation failed. Check the `errors` array for details. | | `429` | Too Many Request | Rate limit exceeded. | | `500` | Internal Server Error | Something went wrong on our end. Try again later. | Error Response Format [#error-response-format] All error responses follow a consistent JSON structure: ```json theme={null} { "data": null, "message": "Error general message", "errors": [], "statusCode": 401 } ``` * `data` (object | null): Always `null` for error responses. * `message` (string): Human-readable error description. * `errors` (array): Additional error details. For validation errors (422), contains field-specific messages. * `statusCode` (integer): HTTP status code (matches the response status). Error Types [#error-types] 401 Unauthorized [#401-unauthorized] Returned when authentication fails. **Common causes:** * Missing `Authorization` header * Invalid API key * Expired API key ```json theme={null} { "data": null, "message": "Unauthorized user.", "errors": [], "statusCode": 401 } ``` **Solution:** Verify your API key is correct and included in the `Authorization: Bearer ` header. *** 404 Not Found [#404-not-found] Returned when the requested resource doesn't exist. **Common causes:** * Invalid `request_id` when polling results * Model name doesn't exist * Request ID not found ```json theme={null} { "data": null, "message": "Request not found.", "errors": [], "statusCode": 404 } ``` **Solution:** Verify the resource identifier (`request_id`, model name) is correct. Use the [Model Selection](/docs/v1/api/utilities/model-selection) endpoint to get valid model names. *** 422 Unprocessable Entity [#422-unprocessable-entity] Returned when request validation fails. The `errors` array contains field-specific details. **Common causes:** * Missing required parameters * Invalid parameter values (out of range, wrong type) * Invalid image/video URL or format ```json theme={null} { "data": null, "message": "Validation failed", "errors": [ { "field": "width", "messages": ["The width must be between 64 and 2048."] }, { "field": "model", "messages": ["The selected model does not exist."] } ], "statusCode": 422 } ``` **Solution:** Check the `errors` array to identify which fields failed validation and correct them according to the API documentation. *** 500 Internal Server Error [#500-internal-server-error] Returned when an unexpected error occurs on our servers. ```json theme={null} { "data": null, "message": "Internal server error", "errors": [], "statusCode": 500 } ``` **Solution:** Wait a moment and retry your request. If the problem persists, check [status.dryapi.dev](https://status.dryapi.dev/) or contact support on [Discord](https://discord.com/invite/UFfK5YRBsr). Best Practices [#best-practices] > Implement error handling for all possible status codes in your application. > For 422 responses, iterate through the `errors` array to display field-specific messages to users. > For 500 errors, implement exponential backoff retry (e.g., 1s, 2s, 4s delays). > Log full error responses for debugging. Include `request_id` if available. Example Error Handling [#example-error-handling] ```python Python theme={null} import requests response = requests.post( "https://api.dryapi.dev/api/v1/client/txt2img", headers={ "Authorization": "Bearer YOUR_API_KEY", "Accept": "application/json" }, json={ "prompt": "a cat", "model": "flux-2-klein-4b-bf16", "width": 512, "height": 512, "steps": 4, "guidance": 0, "seed": -1, "loras": [] } ) if response.status_code == 200: data = response.json() request_id = data["data"]["request_id"] print(f"Job started: {request_id}") elif response.status_code == 401: print("Authentication failed. Check your API key.") elif response.status_code == 422: error_data = response.json() print(f"Validation error: {error_data['message']}") for error in error_data.get("errors", []): print(f" Field '{error['field']}': {error['messages']}") elif response.status_code == 500: print("Server error. Retrying...") else: print(f"Unexpected error: {response.status_code}") ``` ```javascript JavaScript theme={null} const response = await fetch("https://api.dryapi.dev/api/v1/client/txt2img", { method: "POST", headers: { "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", "Accept": "application/json" }, body: JSON.stringify({ prompt: "a cat", model: "Flux1schnell", width: 512, height: 512, steps: 4, guidance: 0, seed: -1, loras: [] }) }); if (response.ok) { const data = await response.json(); const requestId = data.data.request_id; console.log(`Job started: ${requestId}`); } else if (response.status === 401) { console.error("Authentication failed. Check your API key."); } else if (response.status === 422) { const errorData = await response.json(); console.error(`Validation error: ${errorData.message}`); errorData.errors?.forEach(err => { console.error(` Field '${err.field}': ${err.messages.join(", ")}`); }); } else if (response.status === 500) { console.error("Server error. Retrying..."); } else { console.error(`Unexpected error: ${response.status}`); } ``` # API Overview (/docs/v1/api/overview) > Complete reference of all dryAPI endpoints All endpoints use base URL `https://api.dryapi.dev` and require authentication via `Authorization: Bearer ` header. > **NOTE** > > Each generation/analysis endpoint has a corresponding `/price-calculation` endpoint to estimate costs before execution. Generation [#generation] Create images, videos, audio, and embeddings from text or images. | Method | Endpoint | Description | Docs | | ------ | ------------------------------------------------ | ----------------------------------- | ---------------------------------------------------- | | `POST` | `/api/v1/client/txt2img` | Generate image from text prompt | [→](/docs/v1/api/generation/text-to-image) | | `POST` | `/api/v1/client/txt2img/price-calculation` | Calculate text-to-image price | [→](/docs/v1/api/generation/text-to-image-price) | | `POST` | `/api/v1/client/txt2video` | Generate video from text prompt | [→](/docs/v1/api/generation/text-to-video) | | `POST` | `/api/v1/client/txt2video/price-calculation` | Calculate text-to-video price | [→](/docs/v1/api/generation/text-to-video-price) | | `POST` | `/api/v1/client/img2video` | Generate video from image (animate) | [→](/docs/v1/api/generation/image-to-video) | | `POST` | `/api/v1/client/img2video/price-calculation` | Calculate image-to-video price | [→](/docs/v1/api/generation/image-to-video-price) | | `POST` | `/api/v1/client/aud2video` | Generate video from audio + prompt | [→](/docs/v1/api/generation/audio-to-video) | | `POST` | `/api/v1/client/aud2video/price-calculation` | Calculate audio-to-video price | [→](/docs/v1/api/generation/audio-to-video-price) | | `POST` | `/api/v1/client/txt2audio` | Generate speech from text (TTS) | [→](/docs/v1/api/generation/text-to-speech) | | `POST` | `/api/v1/client/txt2audio/price-calculation` | Calculate text-to-speech price | [→](/docs/v1/api/generation/text-to-speech-price) | | `POST` | `/api/v1/client/txt2embedding` | Generate embeddings from text | [→](/docs/v1/api/generation/text-to-embedding) | | `POST` | `/api/v1/client/txt2embedding/price-calculation` | Calculate embedding price | [→](/docs/v1/api/generation/text-to-embedding-price) | | `POST` | `/api/v1/client/txt2music` | Generate music from text | [→](/docs/v1/api/generation/text-to-music) | | `POST` | `/api/v1/client/txt2music/price-calculation` | Calculate text-to-music price | [→](/docs/v1/api/generation/text-to-music-price) | Analysis [#analysis] Extract text and transcriptions from images, videos, and audio. | Method | Endpoint | Description | Docs | | ------ | ------------------------------------------------ | ------------------------------------------------------------ | ----------------------------------------------------- | | `POST` | `/api/v1/client/img2txt` | Extract text from image (OCR) | [→](/docs/v1/api/analysis/image-to-text) | | `POST` | `/api/v1/client/img2txt/price-calculation` | Calculate OCR price | [→](/docs/v1/api/analysis/image-to-text-price) | | `POST` | `/api/v1/client/vid2txt` | Transcribe video from URL (YouTube, X, TikTok, Twitch, Kick) | [→](/docs/v1/api/analysis/video-to-text) | | `POST` | `/api/v1/client/vid2txt/price-calculation` | Calculate video transcription price | [→](/docs/v1/api/analysis/video-to-text-price) | | `POST` | `/api/v1/client/aud2txt` | Transcribe X Spaces audio | [→](/docs/v1/api/analysis/audio-to-text-spaces) | | `POST` | `/api/v1/client/aud2txt/price-calculation` | Calculate X Spaces transcription price | [→](/docs/v1/api/analysis/audio-to-text-spaces-price) | | `POST` | `/api/v1/client/videofile2txt` | Transcribe uploaded video file | [→](/docs/v1/api/analysis/upload-video-file) | | `POST` | `/api/v1/client/videofile2txt/price-calculation` | Calculate video file transcription price | [→](/docs/v1/api/analysis/upload-video-file-price) | | `POST` | `/api/v1/client/audiofile2txt` | Transcribe uploaded audio file | [→](/docs/v1/api/analysis/upload-audio-file) | | `POST` | `/api/v1/client/audiofile2txt/price-calculation` | Calculate audio file transcription price | [→](/docs/v1/api/analysis/upload-audio-file-price) | Transformation [#transformation] Modify existing images. | Method | Endpoint | Description | Docs | | ------ | ---------------------------------------------- | ------------------------------------ | --------------------------------------------------------- | | `POST` | `/api/v1/client/img2img` | Transform image with text prompt | [→](/docs/v1/api/transformation/image-to-image) | | `POST` | `/api/v1/client/img2img/price-calculation` | Calculate image transformation price | [→](/docs/v1/api/transformation/image-to-image-price) | | `POST` | `/api/v1/client/img-rmbg` | Remove image background | [→](/docs/v1/api/transformation/background-removal) | | `POST` | `/api/v1/client/img-rmbg/price-calculation` | Calculate background removal price | [→](/docs/v1/api/transformation/background-removal-price) | | `POST` | `/api/v1/client/img-upscale` | Upscale image resolution | [→](/docs/v1/api/transformation/image-upscale) | | `POST` | `/api/v1/client/img-upscale/price-calculation` | Calculate image upscale price | [→](/docs/v1/api/transformation/image-upscale-price) | Utilities [#utilities] Account management and job status tracking. | Method | Endpoint | Description | Docs | | ------ | -------------------------------------------- | -------------------------------- | ------------------------------------------- | | `GET` | `/api/v1/client/balance` | Get current account balance | [→](/docs/v1/api/utilities/check-balance) | | `GET` | `/api/v1/client/request-status/{request_id}` | Check job status and get results | [→](/docs/v1/api/utilities/get-results) | | `GET` | `/api/v1/client/models` | List all available models | [→](/docs/v1/api/utilities/model-selection) | Workflow [#workflow] Typical API usage follows this pattern: Check available models [#check-available-models] Call `GET /api/v1/client/models` to get current models and their parameters. Calculate price (optional) [#calculate-price-optional] Call the `/price-calculation` endpoint with your parameters to estimate cost. Submit job [#submit-job] Call the main endpoint (e.g., `POST /api/v1/client/txt2img`) with your parameters. Response contains `request_id`. Poll for results [#poll-for-results] Call `GET /api/v1/client/request-status/{request_id}` until `status` is `done` or `error`. Download result [#download-result] When `status` is `done`, use `result_url` to download your generated content. Response Formats [#response-formats] ```json Job Submission (txt2img, txt2video, etc.) theme={null} { "data": { "request_id": "c08a339c-73e5-4d67-a4d5-231302fbff9a" } } ``` ```json Job Status (request-status) theme={null} { "data": { "status": "done", "progress": 100.0, "result_url": "https://...", "result": null, "preview": null } } ``` ```json Balance theme={null} { "balance": 19.72 } ``` ```json Models List theme={null} { "data": { "data": [ { "name": "Flux.1 schnell", "slug": "Flux1schnell", "inference_types": ["txt2img"], "info": { ... } } ] } } ``` ```json Error (4xx/5xx) theme={null} { "data": null, "message": "Error description", "errors": [], "statusCode": 401 } ``` > **NOTE** > > Response structure varies by endpoint. See individual endpoint documentation for exact schemas. See [Errors](/docs/v1/api/errors) for detailed error handling documentation. # OpenAPI Reference (/docs/v1/api-reference) {/* Auto-generated from Hono openapi route metadata and TypeBox validators. */} # Jobs (/docs/v1/api-reference/jobs) {/* Auto-generated from Hono openapi route metadata and TypeBox validators. */} # OpenAI Compatible (/docs/v1/api-reference/openai-compatible) {/* Auto-generated from Hono openapi route metadata and TypeBox validators. */} # RunPod Jobs (/docs/v1/api-reference/runpod-jobs) {/* Auto-generated from Hono openapi route metadata and TypeBox validators. */} # Webhooks (/docs/v1/api-reference/webhooks) {/* Auto-generated from Hono openapi route metadata and TypeBox validators. */} # Execution Modes & HTTP Queue (/docs/v1/execution-modes-and-integrations/execution-modes-and-http-queue) > How to receive job results via webhooks, WebSockets, or polling All dryAPI model endpoints use an **asynchronous job queue**. You submit a request, receive a `request_id`, and retrieve results using one of three methods: > Results pushed to your server (recommended). * [WebSockets](/docs/v1/execution-modes-and-integrations/websockets) - Real-time updates with live previews. > Query `/request-status` manually. *** Webhooks (Recommended) [#webhooks-recommended] > **INFO** > > For most integrations, use webhooks. They're the most reliable way to receive results without maintaining persistent connections or implementing polling logic. With webhooks, dryAPI sends an HTTP POST to your server when a job completes. Configure a global webhook URL in [account settings](https://dryapi.dev/settings/webhooks), or override per-request: ```bash theme={null} # 1. Submit job with webhook_url curl -X POST https://api.dryapi.dev/api/v1/client/txt2img \ -H "Authorization: Bearer $API_KEY" \ -H "Content-Type: application/json" \ -d '{ "prompt": "a beautiful sunset over mountains", "model": "Flux1schnell", "width": 1024, "height": 768, "guidance": 3.5, "steps": 4, "seed": -1, "webhook_url": "https://your-server.com/webhooks/dryapi" }' # 2. Response contains request_id # {"data": {"request_id": "123e4567-e89b-12d3-a456-426614174000"}} # 3. dryAPI POSTs to your webhook when done ``` **Webhook payload (job.completed):** ```json theme={null} { "event": "job.completed", "data": { "job_request_id": "123e4567-e89b-12d3-a456-426614174000", "status": "done", "job_type": "txt2img", "result_url": "https://storage.dryapi.dev/results/.../output.png", "processing_time_ms": 45000 } } ``` **Why webhooks:** * No polling required — results arrive automatically * Automatic retries with exponential backoff (up to 10 retries over \~24 hours) * Works with serverless and traditional backends * Secure with HMAC signature verification → [Full Webhooks Documentation](/docs/v1/execution-modes-and-integrations/webhooks) *** WebSockets (Real-time) [#websockets-real-time] For interactive applications that need instant feedback and live previews during generation: ```javascript theme={null} import Pusher from 'pusher-js'; const pusher = new Pusher('dryapi-api-prod-key', { wsHost: 'soketi.dryapi.dev', wsPort: 443, forceTLS: true, cluster: 'mt1', enabledTransports: ['ws', 'wss'], authorizer: (channel) => ({ authorize: async (socketId, callback) => { const res = await fetch('https://api.dryapi.dev/broadcasting/auth', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${API_TOKEN}` }, body: JSON.stringify({ socket_id: socketId, channel_name: channel.name }) }); callback(null, await res.json()); } }) }); pusher.subscribe(`private-client.${CLIENT_ID}`) .bind('request.status.updated', (data) => { console.log(`Job ${data.request_id}: ${data.status} (${data.progress}%)`); if (data.preview) displayPreview(data.preview); if (data.result_url) downloadResult(data.result_url); }); ``` **Why WebSockets:** * Instant updates (milliseconds latency) * Live preview images during generation * Progress percentage updates * Ideal for user-facing UIs → [Full WebSockets Documentation](/docs/v1/execution-modes-and-integrations/websockets) *** Polling (Fallback) [#polling-fallback] If webhooks or WebSockets aren't feasible, poll the status endpoint: ```bash theme={null} # 1. Submit job (without webhook_url) curl -X POST https://api.dryapi.dev/api/v1/client/txt2img \ -H "Authorization: Bearer $API_KEY" \ -H "Content-Type: application/json" \ -d '{ "prompt": "a beautiful sunset", "model": "Flux1schnell", "width": 512, "height": 512, "guidance": 3.5, "steps": 4, "seed": -1 }' # Response: {"data": {"request_id": "abc123..."}} # 2. Poll for results curl https://api.dryapi.dev/api/v1/client/request-status/abc123 \ -H "Authorization: Bearer $API_KEY" ``` **Response fields:** | Field | Description | | ------------ | ------------------------------------------- | | `status` | `pending`, `processing`, `done`, or `error` | | `progress` | Progress percentage (when available) | | `result_url` | Download URL (when `done`) | | `error` | Error details (when `error`) | > **WARNING** > > Polling adds latency, wastes resources with unnecessary requests, and provides no live previews. Use webhooks or WebSockets when possible. → [Get Results Endpoint Reference](/docs/v1/api/utilities/get-results) *** Choosing a Method [#choosing-a-method] | Scenario | Recommended | | ------------------------------------ | ----------- | | Backend service / serverless | Webhooks | | Interactive web app with progress UI | WebSockets | | Simple scripts / CLI tools | Polling | | Mobile app with real-time updates | WebSockets | | Batch processing pipeline | Webhooks | > **TIP** > > Use webhooks as your primary method with WebSockets for UI updates. This gives you reliability (webhook retries) plus great UX (instant progress). *** How Jobs Are Processed [#how-jobs-are-processed] Every model endpoint follows the same pattern: Submit request [#submit-request] Send `POST /api/v1/client/{task}` with your parameters (optionally include `webhook_url`). Receive request_id [#receive-request_id] Response contains `request_id` for tracking. Job queued [#job-queued] Request enters the queue with status `pending`. Worker processes [#worker-processes] GPU worker picks up the job, status becomes `processing`. Results delivered [#results-delivered] Via webhook POST, WebSocket event, or polling response. This queued model: * Keeps long-running jobs off the HTTP request path * Avoids timeout issues for video/audio generation * Enables efficient GPU scheduling across the distributed network * Provides a consistent pattern across all endpoints *** Quick Reference [#quick-reference] | Endpoint | Description | | ------------------------------------------------ | ---------------------------- | | `POST /api/v1/client/{task}` | Submit a job | | `GET /api/v1/client/request-status/{request_id}` | Check job status (polling) | | `POST {your_webhook_url}` | Receive webhook notification | | `wss://soketi.dryapi.dev` | WebSocket connection | # MCP Server (/docs/v1/execution-modes-and-integrations/mcp-server) > Describes the dryAPI MCP server, its available tools, and how to connect agents or IDE integrations to use dryAPI as a structured toolbox. > **WARNING** > > The MCP server is currently in beta. You may encounter occasional issues or unexpected behavior as we continue to refine the service. We actively welcome feedback and bug reports — join the conversation on [Discord](https://discord.com/invite/UFfK5YRBsr). In addition to the HTTP API, dryAPI exposes an **MCP (Model Context Protocol) server**. This allows AI assistants, IDE extensions, and MCP-aware tools to call dryAPI capabilities as structured tools instead of manually constructing HTTP requests. *** What is MCP? [#what-is-mcp] The **Model Context Protocol (MCP)** is an open standard that enables AI models and agents to interact with external tools and services in a structured way. Instead of crafting raw HTTP requests, your AI assistant discovers available tools and calls them using a standardized protocol. With dryAPI's MCP server, Claude, ChatGPT, Cursor, and other MCP-compatible clients can: * Generate images, videos, and audio directly within conversations * Transcribe YouTube / X / Twitch / Kick / TikTok videos or audio files * Remove backgrounds and upscale images * Check pricing before running expensive operations * Access all dryAPI capabilities through natural language New tools and capabilities will be added as the MCP server evolves. Follow our [Discord](https://discord.com/invite/UFfK5YRBsr) for updates and to share feature requests. The full source code for the MCP server is available on GitHub: [github.com/dryapi-ai/mcp-server-dryapi](https://github.com/dryapi-ai/mcp-server-dryapi) *** Server Details [#server-details] | Property | Value | | ----------------------- | ---------------------------- | | **MCP Server URL** | `https://mcp.dryapi.dev/mcp` | | **OAuth Client ID** | `dryapi-mcp` | | **OAuth Client Secret** | Your dryAPI API key | | **Transport** | Streamed HTTP | *** Available Tools [#available-tools] The dryAPI MCP server exposes the following tools: Image Generation & Manipulation [#image-generation--manipulation] | Tool | Description | | ------------------------------- | --------------------------------------------------------------------------------- | | `text_to_image` | Generate images from text prompts using AI diffusion models (Flux, Z-Image-Turbo) | | `image_to_image` | Transform existing images using text prompts (style transfer, editing) | | `image_to_text` | Extract text from images using OCR | | `image_remove_background` | Remove background from images (transparent PNG output) | | `image_upscale` | Upscale images to higher resolution | | `text_to_image_price` | Calculate price for text-to-image generation | | `image_to_image_price` | Calculate price for image transformation | | `image_to_text_price` | Calculate price for OCR extraction | | `image_remove_background_price` | Calculate price for background removal | | `image_upscale_price` | Calculate price for image upscaling | Video Generation & Processing [#video-generation--processing] | Tool | Description | | -------------------------------- | -------------------------------------------------------------- | | `text_to_video` | Generate videos from text prompts | | `image_to_video` | Animate static images into videos | | `audio_to_video` | Generate video conditioned on audio and text prompt | | `video_file_transcription` | Transcribe uploaded video files to text | | `video_url_transcription` | Transcribe videos from URLs (YouTube, X, Twitch, TikTok, Kick) | | `text_to_video_price` | Calculate price for text-to-video generation | | `image_to_video_price` | Calculate price for image-to-video generation | | `audio_to_video_price` | Calculate price for audio-to-video generation | | `video_file_transcription_price` | Calculate price for video file transcription | | `video_url_transcription_price` | Calculate price for video URL transcription | Audio & Speech [#audio--speech] | Tool | Description | | ------------------------------- | ----------------------------------------------------- | | `text_to_audio` | Convert text to natural-sounding speech (TTS) | | `text_to_music` | Generate music tracks from text descriptions | | `audio_transcription` | Transcribe uploaded audio files to text using Whisper | | `audio_url_transcription` | Transcribe audio from URLs (X/Twitter Spaces) | | `text_to_audio_price` | Calculate price for text-to-speech | | `text_to_music_price` | Calculate price for music generation | | `audio_transcription_price` | Calculate price for audio file transcription | | `audio_url_transcription_price` | Calculate price for audio URL transcription | Embeddings [#embeddings] | Tool | Description | | ------------------------- | -------------------------------------------- | | `text_to_embedding` | Generate text embeddings for semantic search | | `text_to_embedding_price` | Calculate price for embedding generation | Utility [#utility] | Tool | Description | | ---------------------- | ------------------------------------------------ | | `get_available_models` | List all available AI models with specifications | | `get_balance` | Check your dryAPI account balance | | `check_job_status` | Check status of submitted jobs | *** How to Connect [#how-to-connect] Claude (claude.ai) [#claude-claudeai] To use dryAPI MCP tools directly in Claude conversations: **Step 1.** Get your API key from the [dryAPI Dashboard](https://dryapi.dev/dashboard) **Step 2.** Add the MCP connector in Claude settings: * Go to **Settings** → **Connectors** * Click **Add Connector** or **Add MCP Server** * Select **New OAuth Connector** * Enter the following credentials: | Field | Value | | ----------------------- | ---------------------------- | | **OAuth Client ID** | `dryapi-mcp` | | **OAuth Client Secret** | Your dryAPI API key | | **Server URL** | `https://mcp.dryapi.dev/mcp` | **Step 3.** Grant permissions — After adding the connector, Claude will ask you to authorize the connection. Click **Allow** to enable dryAPI MCP tools in your conversations. **Step 4.** Start using dryAPI MCP by asking Claude to generate images, transcribe videos, or use any other capability. Make sure to mention "dryAPI MCP" in your prompt so Claude knows to use the MCP tools. **Example prompts:** * *"Using dryAPI MCP, generate an image of a futuristic city at sunset"* * *"With dryAPI MCP, transcribe this YouTube video: \[URL]"* * *"With dryAPI MCP, transcribe this Twitch video: \[URL]"* * *"Check my dryAPI MCP balance"* * *"Using dryAPI MCP, create a video of waves crashing on a beach"* *** Claude Desktop [#claude-desktop] To use dryAPI MCP in the Claude Desktop app, configure it via the config file with a Bearer token. This is the recommended approach for desktop — no OAuth setup required. **Config file setup:** Edit your Claude Desktop configuration file: * **macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json` * **Windows**: `%APPDATA%\Claude\claude_desktop_config.json` ```json theme={null} { "mcpServers": { "dryapi": { "url": "https://mcp.dryapi.dev/mcp", "headers": { "Authorization": "Bearer YOUR_API_KEY" } } } } ``` Replace `YOUR_API_KEY` with your actual dryAPI key. Save the file and restart Claude Desktop. *** Cursor IDE [#cursor-ide] To integrate dryAPI MCP into Cursor for AI-assisted development: **Step 1.** Get your API key from the [dryAPI Dashboard](https://dryapi.dev/dashboard) **Step 2.** Open Cursor Settings: * Press `Cmd/Ctrl + Shift + P` * Search for **"Cursor Settings"** or navigate to **Settings** → **Cursor Settings** **Step 3.** Add MCP Configuration: * Find the **MCP** or **Model Context Protocol** section * Add a custom MCP server configuration * Paste the following JSON (replace `YOUR_API_KEY` with your actual key): ```json theme={null} { "mcpServers": { "dryapi": { "name": "DRYAPI MCP", "url": "https://mcp.dryapi.dev/mcp", "headers": { "Authorization": "Bearer YOUR_API_KEY" } } } } ``` **Step 4.** Restart Cursor to apply the configuration. **Step 5.** Invoke dryAPI MCP in chat by using phrases like: * *"Using dryAPI MCP, generate an image of…"* * *"With dryAPI MCP, transcribe this audio…"* * *"Via dryAPI MCP, check my balance"* > **TIP** > > Cursor recognizes dryAPI MCP tools when you mention keywords like "using dryAPI MCP", "with dryAPI MCP", or "via MCP" in your prompts. *** ChatGPT [#chatgpt] To use dryAPI MCP tools in ChatGPT conversations: > **INFO** > > MCP is available in beta to **Pro, Plus, Business, Enterprise, and Education** accounts. The MCP apps work on both web and desktop, but Developer mode settings are only accessible in the **web version** at [chatgpt.com](https://chatgpt.com). **Step 1.** Get your API key from the [dryAPI Dashboard](https://dryapi.dev/dashboard) **Step 2.** Enable Developer mode: * Go to **Settings** → **Apps & Connectors** * Scroll to **Advanced settings** at the bottom * Enable **Developer mode** * Go back — a **Create App** button will appear next to Advanced settings **Step 3.** Create a new MCP App: * Click **Create App** * Fill in the following details: | Field | Value | | ----------------------- | --------------------------------- | | **Name** | `dryAPI` (or any name you prefer) | | **Description** | `dryAPI MCP` (optional) | | **MCP Server URL** | `https://mcp.dryapi.dev/mcp` | | **Authentication** | `OAuth` | | **OAuth Client ID** | `dryapi-mcp` | | **OAuth Client Secret** | Your dryAPI API key | **Step 4.** Check the risk acknowledgment checkbox ("I understand and want to continue") **Step 5.** Click **Create** **Step 6.** Start using dryAPI MCP by asking ChatGPT to generate images, transcribe videos, or use any other capability. **Example prompts:** * *"Using dryAPI MCP, generate an image of a cyberpunk cat"* * *"With dryAPI MCP, transcribe this YouTube video: \[URL]"* * *"Check my dryAPI MCP balance"* * *"With dryAPI MCP, transcribe this Kick video: \[URL]"* *** Self-Hosting [#self-hosting] You can run the MCP server on your own infrastructure. The full source code is available at [github.com/dryapi-ai/mcp-server-dryapi](https://github.com/dryapi-ai/mcp-server-dryapi) under the MIT license. Prerequisites [#prerequisites] * Python 3.10 or higher * `uv`, `pip`, or `conda` for package management * A dryAPI API key from the [Dashboard](https://dryapi.dev/dashboard) Quick Start [#quick-start] ```bash theme={null} git clone https://github.com/dryapi-ai/mcp-server-dryapi.git cd mcp-server-dryapi # Install dependencies (uv recommended) uv pip install -e . # Start the server python -m src.server_remote ``` The server will start on `http://localhost:8000` by default. For external access: ```bash theme={null} MCP_HOST=0.0.0.0 MCP_PORT=8000 python -m src.server_remote ``` Docker Deployment [#docker-deployment] ```bash theme={null} # Build and run docker build -t mcp-server-dryapi . docker run -d -p 8000:8000 --name mcp-server-dryapi mcp-server-dryapi # Or with Docker Compose docker-compose up -d ``` Cloud Deployment Options [#cloud-deployment-options] The server can be deployed to any platform that supports Python or Docker containers: Railway, Fly.io, Heroku, DigitalOcean App Platform, AWS ECS, GCP Cloud Run, and others. Detailed deployment instructions are available in [DEPLOYMENT.md](https://github.com/dryapi-ai/mcp-server-dryapi/blob/main/DEPLOYMENT.md) in the repository. Connecting a Self-Hosted Server [#connecting-a-self-hosted-server] Point your MCP client to your server URL instead of the default `https://mcp.dryapi.dev/mcp`: ```json theme={null} { "mcpServers": { "dryapi": { "url": "http://your-server-ip:8000/mcp", "headers": { "Authorization": "Bearer YOUR_API_KEY" } } } } ``` *** Supported Models [#supported-models] The MCP server provides access to all dryAPI models. Use the `get_available_models` tool to retrieve the full list with current specifications and limits. *** Usage Examples [#usage-examples] Generate an Image [#generate-an-image] Ask your AI assistant: > "Using dryAPI MCP, generate an image of an astronaut riding a horse on Mars, photorealistic style" The assistant will call `text_to_image` with appropriate parameters and return the generated image URL. Transcribe a YouTube Video [#transcribe-a-youtube-video] > "With dryAPI MCP, transcribe this YouTube video with timestamps: [https://www.youtube.com/watch?v=7qaiNfoMRts](https://www.youtube.com/watch?v=7qaiNfoMRts)" The assistant calls `video_url_transcription` and returns the full transcript. Convert Text to Speech [#convert-text-to-speech] > "Using dryAPI MCP, convert this text to speech with a British female voice: 'Welcome to our platform'" The assistant calls `text_to_audio` with the Kokoro model and appropriate voice settings. Remove Background from Image [#remove-background-from-image] > "Using dryAPI MCP, remove the background from this product photo" The assistant calls `image_remove_background` and returns a transparent PNG. Transcribe X/Twitter Spaces [#transcribe-xtwitter-spaces] > "With dryAPI MCP, transcribe this Twitter Space: [https://twitter.com/i/spaces/…](https://twitter.com/i/spaces/…)" The assistant calls `audio_url_transcription` and returns the full transcript. *** Architecture [#architecture] Smart Adaptive Polling [#smart-adaptive-polling] For async jobs, the server automatically polls for results with optimized intervals based on job type: | Job Type | Initial Delay | Max Delay | Timeout | | -------- | ------------- | --------- | ------- | | Audio | 1s | 5s | 5 min | | Image | 2s | 8s | 5 min | | Video | 5s | 30s | 15 min | Polling uses exponential backoff (1.5× multiplier by default), so jobs receive fast initial checks while heavier workloads avoid unnecessary load. Token Security [#token-security] The MCP server does **not** store your API token. Authentication works at the connection level: * **Remote hosted server**: OAuth 2.0 Authorization Code with PKCE, or Bearer token in HTTP headers * **Self-hosted server**: Bearer token forwarded per-request to the dryAPI API * Tokens are never persisted or logged; tools do **not** accept `dryapi_api_token` as a parameter *** When to Use MCP vs HTTP API [#when-to-use-mcp-vs-http-api] | Use Case | Recommended | | ---------------------------------- | -------------- | | AI assistants & chatbots | **MCP Server** | | IDE integrations (Cursor, VS Code) | **MCP Server** | | Backend services & workers | **HTTP API** | | Batch processing | **HTTP API** | | Direct programmatic control | **HTTP API** | | Agent-driven workflows | **MCP Server** | Use the **MCP server** when you want an AI agent to decide which tools to call, with which parameters, and in what order. Use the **HTTP API + queue** for typical backend integrations where you directly manage requests and results. *** Troubleshooting [#troubleshooting] Connection Issues [#connection-issues] * **Verify your API key** is valid and has sufficient balance * **Check the server URL** is exactly `https://mcp.dryapi.dev/mcp` * **For Claude:** Ensure OAuth Client ID is `dryapi-mcp` and Secret is your API key * **For Cursor / Claude Desktop:** Ensure Bearer token format — the Authorization header should be `Bearer YOUR_API_KEY` Tools Not Appearing [#tools-not-appearing] * Restart your MCP client (Claude, ChatGPT, Cursor) after configuration changes * **In Claude:** Make sure you clicked **Allow** when prompted to grant permissions * **In ChatGPT:** Ensure Developer mode is enabled in Advanced settings * Verify JSON syntax in configuration files (Cursor, Claude Desktop) * Check that your API key has the necessary permissions Jobs Stuck in Processing [#jobs-stuck-in-processing] * Use `check_job_status` tool with the job ID to monitor progress * Large video generation or transcription jobs may take several minutes * Check [status.dryapi.dev](https://status.dryapi.dev/) for system status Remote Connection Issues (Self-Hosted) [#remote-connection-issues-self-hosted] * Test the endpoint: `curl -N http://your-server:8000/mcp` * Check server logs: `docker logs mcp-server-dryapi` or `journalctl -u mcp-server-dryapi` * Verify firewall rules allow the configured port * For SSL issues, confirm certificates are valid and paths are correct in your proxy config # n8n dryAPI node (/docs/v1/execution-modes-and-integrations/n8n-deapi-node) This guide explains how to integrate dryAPI with a **self-hosted n8n instance** using the official dryAPI community node. The community node provides a simpler, no-code experience compared to the [HTTP Request-based approach](/docs/v1/execution-modes-and-integrations/n8n-integration). *** Why Use the Community Node? [#why-use-the-community-node] The `n8n-nodes-dryapi` community node offers several advantages over manually configuring HTTP Request nodes: | Feature | Community Node | HTTP Request Approach | | -------------------- | ------------------------------- | --------------------------------- | | **Setup Complexity** | One-time installation | Manual configuration per workflow | | **Job Completion** | Automatic webhook-based waiting | Manual polling loop required | | **Binary Data** | Auto-downloaded and attached | Manual download step needed | | **Error Handling** | Built-in with clear messages | Manual status checking | | **Credential Reuse** | Shared across all operations | Configure per node | *** Prerequisites [#prerequisites] Before you begin, ensure you have: * A **self-hosted n8n instance** accessible via **HTTPS** (required for webhook callbacks) * A **dryAPI API key** from the [dryAPI Dashboard](https://dryapi.dev/docs/quickstart#2-obtain-your-api-key) * A **Webhook Secret** from [dryAPI Webhook Settings](https://dryapi.dev/settings/webhooks) > **WARNING** > > The dryAPI node uses webhooks to receive job completion notifications. Your n8n instance must be accessible via HTTPS for generation operations to work. *** Installation [#installation] Option 1: GUI Installation (Recommended) [#option-1-gui-installation-recommended] 1. In your n8n instance, go to **Settings** > **Community Nodes** 2. Click **Install a community node** 3. Enter `n8n-nodes-dryapi` and click **Install** 4. Restart n8n if prompted Option 2: Manual Installation (docker) [#option-2-manual-installation-docker] If you're running n8n via docker: ```bash theme={null} docker exec -it sh mkdir ~/.n8n/nodes cd ~/.n8n/nodes npm i n8n-nodes-dryapi ``` Then restart your n8n instance. *** Credential Configuration [#credential-configuration] After installation, configure your dryAPI credentials: 1. In n8n, go to **Credentials** > **Add Credential** 2. Search for **dryAPI API** and select it 3. Fill in the required fields: | Field | Description | Where to Get It | | ------------------ | --------------------------------------- | ----------------------------------------------------------------------------------- | | **API Key** | Your dryAPI API key for authentication | [dryAPI Quickstart Guide](https://dryapi.dev/docs/quickstart#2-obtain-your-api-key) | | **Webhook Secret** | Secret for verifying webhook signatures | [dryAPI Webhook Settings](https://dryapi.dev/settings/webhooks) | 4. Click **Save** to store the credentials > **NOTE** > > The Webhook Secret is used to verify that incoming webhook notifications are genuinely from dryAPI. Keep it secure and never share it publicly. *** Available Operations [#available-operations] The dryAPI node provides two node types: dryAPI Node (Regular Operations) [#dryapi-node-regular-operations] Use this node to perform AI operations within your workflow. **Image Operations** [#image-operations] | Operation | Description | Models | | --------------------- | --------------------------------- | -------------------------------------------------------- | | **Generate** | Generate images from text prompts | FLUX.1 Schnell, FLUX.2 Klein 4B BF16, Z-Image Turbo INT8 | | **Remove Background** | Remove background from images | Ben2 | | **Upscale** | Increase image resolution by 4x | RealESRGAN x4 | Image input operations (**Remove Background**, **Upscale**) accept JPG, JPEG, PNG, GIF, BMP, and WebP files up to 10 MB. **Video Operations** [#video-operations] | Operation | Description | Models | | -------------- | ------------------------------------------------------------------------------- | -------------------------------------------- | | **Generate** | Generate video from text or image(s) | LTX-Video 0.9.8 13B, LTX-2 19B Distilled FP8 | | **Transcribe** | Transcribe video to text (YouTube, Twitch, X, Kick, TikTok URLs or file upload) | Whisper Large V3 | Video file transcription accepts MP4, MPEG, MOV, AVI, WMV, and OGG files up to 10 MB. **Audio Operations** [#audio-operations] | Operation | Description | Models | | -------------- | ----------------------------- | ---------------- | | **Transcribe** | Transcribe audio file to text | Whisper Large V3 | Audio transcription accepts AAC, MP3, OGG, WAV, WebM, and FLAC files up to 10 MB. **Prompt Operations** [#prompt-operations] | Operation | Description | | ------------------------ | --------------------------------------------------- | | **Image Prompt Booster** | Optimize prompts for text-to-image generation | | **Video Prompt Booster** | Optimize prompts for text/image-to-video generation | dryAPITrigger Node (Webhook Trigger) [#dryapitrigger-node-webhook-trigger] Use this node to start workflows when dryAPI sends job status updates. This is useful for: * Building event-driven workflows * Processing results from jobs submitted outside n8n * Monitoring job progress across multiple systems *** How the Webhook-Based Waiting Works [#how-the-webhook-based-waiting-works] Generation operations (image, video, transcription) use an efficient webhook-based pattern instead of polling: ```text theme={null} 1. Execute Phase +-----------+ POST /txt2img +-----------+ | dryAPI | ---------------------> | dryAPI | | Node | (includes webhook) | Server | +-----------+ +-----------+ | v Workflow pauses (frees memory) 2. Processing Phase (no n8n resources used) +-----------+ +-----------+ | n8n | <-- job.processing | dryAPI | | (waiting) | (acknowledged) | (working) | +-----------+ +-----------+ 3. Resume Phase +-----------+ +-----------+ | n8n | <-- job.completed | dryAPI | | (resumes) | (with result_url) | (done) | +-----------+ +-----------+ | v Workflow continues with generated content ``` **Key benefits:** * No polling loop consuming API calls * Workflow pauses and frees memory during processing * Results include binary data ready for downstream nodes *** Example Workflow: Text-to-Image Generation [#example-workflow-text-to-image-generation] This example demonstrates a simple image generation workflow. Workflow Overview [#workflow-overview] ```text theme={null} +------------------+ +-------------------+ | Manual Trigger | ---> | dryAPI Node | | | | (Image: Generate) | +------------------+ +-------------------+ | v Generated image as binary data output ``` Step 1: Add a Trigger [#step-1-add-a-trigger] Add a **Manual Trigger** (or Schedule, Webhook, etc.) to start your workflow. Step 2: Add the dryAPI Node [#step-2-add-the-dryapi-node] 1. Add a **dryAPI** node to your workflow 2. Select your **dryAPI API** credentials 3. Configure the operation: | Setting | Value | | ---------------- | -------------------------------------- | | **Resource** | Image | | **Operation** | Generate | | **Model** | FLUX.2 Klain (or your preferred model) | | **Prompt** | `Red Bull F1 car from 2025` | | **Aspect Ratio** | Square, Landscape, or Portrait | 4. Optionally configure: * **Negative Prompt** — Elements to exclude from the image * **Resolution** — Select image dimensions other than the default ones, depending on your needs * **Seed** — For reproducible results (use `-1` for random) * **Steps** — Number of inference steps (higher = more detail) Step 3: Run the Workflow [#step-3-run-the-workflow] 1. Click **Test Workflow** or **Execute Workflow** 2. The node will: * Submit the generation request to dryAPI * Pause the workflow while waiting * Resume automatically when the image is ready 3. The output contains the generated image as binary data Using the Generated Image [#using-the-generated-image] The image is available in the `data` binary field. Connect downstream nodes to: * **Write Binary File** — Save to disk * **Send Email** — Attach to an email * **HTTP Request** — Upload to cloud storage * **Slack/Discord** — Share in a channel *** Using the dryAPITrigger Node [#using-the-dryapitrigger-node] The **dryAPITrigger** node listens for webhook events from dryAPI, enabling event-driven workflows. Setup [#setup] 1. Add a **dryAPITrigger** node to a new workflow 2. Select your **dryAPI API** credentials 3. Configure event filtering: | Setting | Description | | -------------------------- | ----------------------------------------------------------------------- | | **Events** | Select which events trigger the workflow: Processing, Completed, Failed | | **Download Binary Result** | Automatically download the result file for completed jobs | 4. **Activate the workflow** to make the webhook URL live 5. Copy the **Webhook URL** displayed in the node 6. Add this URL to your [dryAPI Webhook Settings](https://dryapi.dev/settings/webhooks) Event Types [#event-types] | Event | Description | Typical Use | | ------------------ | -------------------------- | --------------------------------- | | **job.processing** | Job has started processing | Update status in external system | | **job.completed** | Job finished successfully | Process the generated content | | **job.failed** | Job encountered an error | Handle errors, send notifications | *** Comparison: Community Node vs HTTP Request [#comparison-community-node-vs-http-request] | Aspect | Community Node | HTTP Request Approach | | ----------------------- | ----------------------------- | --------------------------------------------- | | **Nodes Required** | 1 (dryAPI node) | 5+ (Submit, Poll loop, Check, Wait, Download) | | **Polling Logic** | Automatic webhook | Manual polling loop with Wait node | | **Binary Handling** | Auto-downloaded | Manual HTTP Request to download | | **Error Messages** | Clear, contextual | Raw API responses | | **Credential Setup** | Once per n8n instance | Once per n8n instance | | **Rate Limit Handling** | Built-in with helpful message | Manual detection and handling | | **Code Required** | None | Expressions for URL templating | *** Troubleshooting [#troubleshooting] HTTPS Required [#https-required] Generation operations require your n8n instance to be accessible via HTTPS for webhook callbacks. **Solutions:** * Use a reverse proxy (nginx, Caddy, Traefik) with SSL termination * Use a tunnel service (ngrok, Cloudflare Tunnel) for development * Ensure your SSL certificate is valid and not self-signed Webhook Verification Failures [#webhook-verification-failures] If you see webhook signature verification errors: 1. Verify your **Webhook Secret** matches the one in [dryAPI Webhook Settings](https://dryapi.dev/settings/webhooks) 2. Ensure your n8n server clock is synchronized (signature includes timestamp) 3. Check that no proxy is modifying the request body Timeout Errors [#timeout-errors] Operations have a configurable **Wait Timeout** with defaults that vary by type: | Operation Type | Default Timeout | Max Timeout | | ---------------------------- | --------------- | ----------- | | Generation (image, video) | 60 seconds | 240 seconds | | Transcription (video, audio) | 120 seconds | 600 seconds | For long-running operations: 1. Select the dryAPI node 2. Expand **Options** 3. Increase **Wait Timeout** to allow more time Rate Limiting [#rate-limiting] If you see "upgrade your plan" errors, you've hit dryAPI's rate limits. Consider upgrading your dryAPI plan for higher limits. *** Example Workflow Download [#example-workflow-download] An example n8n workflow demonstrating all available operations is available in the [GitHub repository](https://github.com/dryapi-ai/n8n-nodes-dryapi/blob/main/examples/dryAPI_guide.json). 1. Download [`dryAPI_guide.json`](https://raw.githubusercontent.com/dryapi-ai/n8n-nodes-dryapi/main/examples/dryAPI_guide.json) 2. In n8n, go to **Workflows** > **Import from File** 3. Select the downloaded file 4. Configure your dryAPI credentials 5. Explore the example nodes and sticky notes *** Resources [#resources] * [n8n Community Nodes Documentation](https://docs.n8n.io/integrations/community-nodes/) * [n8n Integration (HTTP Request approach)](/docs/v1/execution-modes-and-integrations/n8n-integration) * [dryAPI API Reference](/docs/v1/api/overview) * [Execution Modes & HTTP Queue](/docs/v1/execution-modes-and-integrations/execution-modes-and-http-queue) * [Model Selection Guide](/docs/v1/api/utilities/model-selection) * [GitHub Repository](https://github.com/dryapi-ai/n8n-nodes-dryapi) * [NPM Package](https://www.npmjs.com/package/n8n-nodes-dryapi) # n8n Integration (/docs/v1/execution-modes-and-integrations/n8n-integration) This guide explains how to integrate dryAPI with n8n to automate AI-powered workflows such as image generation, video transcription, and more. > **NOTE** > > For a simpler, no-code experience, use the [dryAPI Community Node](/docs/v1/execution-modes-and-integrations/n8n-dryapi-node) instead. It handles webhook-based waiting, binary downloads, and error handling automatically — with just one node. The guide below covers the manual HTTP Request approach, which works with both self-hosted n8n and n8n Cloud. *** What is n8n? [#what-is-n8n] **n8n** is an open-source workflow automation tool that allows you to connect different services and APIs together. With dryAPI's HTTP API, you can build powerful automation workflows that generate images, transcribe videos, create speech, and more — all without writing code. *** Prerequisites [#prerequisites] Before you begin, ensure you have: * An **n8n instance** (self-hosted or [n8n Cloud](https://n8n.io/)) * A **dryAPI API key** from the [dryAPI Dashboard](https://dryapi.dev/dashboard) * Basic understanding of n8n workflows *** Authentication Setup [#authentication-setup] All dryAPI endpoints require Bearer token authentication. In n8n, configure this once and reuse it across your workflow: 1. In your HTTP Request node, set **Authentication** to `Generic Credential Type` 2. Set **Generic Auth Type** to `Bearer Auth` 3. Create a new credential with your dryAPI API key as the token *** Example Workflow: Text-to-Image Generation [#example-workflow-text-to-image-generation] This example demonstrates a complete workflow that generates an image from a text prompt using dryAPI's asynchronous job model. Workflow Overview [#workflow-overview] The workflow follows dryAPI's [queued execution model](/docs/v1/execution-modes-and-integrations/execution-modes-and-http-queue): 1. **Submit job** — POST request to start image generation 2. **Poll status** — Check job status in a loop 3. **Check completion** — Verify if `result_url` exists 4. **Download result** — Fetch the generated image ``` +---------------------+ | Manual Trigger | +----------+----------+ | v +---------------------+ | HTTP Request | POST /api/v1/client/txt2img | (Submit Job) | +----------+----------+ | v +---------------------+ | HTTP Request1 |<-----------+ | (Check Status) | | +----------+----------+ | | | v | +---------------------+ | | If | | | (result_url exists) | | +----------+----------+ | | | +-----+-----+ | | | | True False | | | | v v | +----------+ +----------+ | | HTTP | | Wait |----------+ | Request2 | | (3 sec) | |(Download)| +----------+ +----------+ ``` *** Step 1: Trigger Node [#step-1-trigger-node] Add a **Manual Trigger** (or any trigger like Webhook, Schedule) to start the workflow. *** Step 2: Submit Generation Request (HTTP Request) [#step-2-submit-generation-request-http-request] Add an **HTTP Request** node with the following configuration: | Setting | Value | | --------------------- | ---------------------------------------------- | | **Method** | `POST` | | **URL** | `https://api.dryapi.dev/api/v1/client/txt2img` | | **Authentication** | Generic Credential Type | | **Generic Auth Type** | Bearer Auth | | **Bearer Auth** | Select your dryAPI credential | | **Send Body** | Enabled (toggle ON) | | **Body Content Type** | JSON | | **Specify Body** | Using JSON | **JSON Body:** ```json theme={null} { "seed": 1312321313, "loras": [], "model": "zimageturbo-int8", "steps": 8, "width": 1024, "height": 1024, "prompt": "Red Bull F1 car from 2025", "guidance": 3.5, "negative_prompt": null } ``` The response will contain a `request_id`: ```json theme={null} { "data": { "request_id": "c08a339c-73e5-4d67-a4d5-231302fbff9a" } } ``` *** Step 3: Poll Job Status (HTTP Request1) [#step-3-poll-job-status-http-request1] Add a second **HTTP Request** node to check the job status: | Setting | Value | | --------------------- | ------------------------------------------------------------------------------------------------------ | | **Method** | `GET` | | **URL** | `https://api.dryapi.dev/api/v1/client/request-status/{{ $node["HTTP Request"].json.data.request_id }}` | | **Authentication** | Generic Credential Type | | **Generic Auth Type** | Bearer Auth | | **Bearer Auth** | Select your dryAPI credential | > **NOTE** > > The URL uses n8n expression syntax to reference the `request_id` from the previous node. The response includes job status: ```json theme={null} { "data": { "status": "done", "progress": 100, "result_url": "https://depinprod.s3.pl-waw.scw.cloud/depin-result/..." } } ``` *** Step 4: Check if Result is Ready (If Node) [#step-4-check-if-result-is-ready-if-node] Add an **If** node to check whether the job has completed: | Setting | Value | | -------------- | ----------------------------- | | **Conditions** | | | **Value 1** | `{{ $json.data.result_url }}` | | **Operation** | `exists` | Connect the outputs: * **True** → HTTP Request2 (download result) * **False** → Wait node (retry loop) *** Step 5: Wait Before Retry (Wait Node) [#step-5-wait-before-retry-wait-node] Add a **Wait** node for the **False** branch: | Setting | Value | | --------------- | ------------------- | | **Resume** | After Time Interval | | **Wait Amount** | `3` | | **Wait Unit** | Seconds | > **WARNING** > > Connect the Wait node output back to **HTTP Request1** to create the polling loop. *** Step 6: Download Result (HTTP Request2) [#step-6-download-result-http-request2] Add a final **HTTP Request** node for the **True** branch: | Setting | Value | | -------------------------------------------- | ----------------------------- | | **Method** | `GET` | | **URL** | `{{ $json.data.result_url }}` | | **Authentication** | None | | **Options → Response → Response Format** | File | | **Options → Response → Put Output in Field** | `data` | The generated image is now available in your workflow for further processing (save to disk, upload to cloud storage, send via email, etc.). *** Tips & Best Practices [#tips--best-practices] Polling Interval [#polling-interval] Adjust the Wait node timing based on task type: | Task Type | Recommended Wait | | ------------------- | ---------------- | | Text-to-Image | 2–5 seconds | | Image-to-Image | 2–5 seconds | | Text-to-Video | 10–30 seconds | | Audio-to-Video | 10–30 seconds | | Text-to-Music | 10–30 seconds | | Video Transcription | 5–15 seconds | | Audio Transcription | 3–10 seconds | Error Handling [#error-handling] Add error handling to your workflow: * Check for `status: "error"` in the polling response * Set a maximum number of loop iterations to avoid infinite loops (use a counter with Set node) * Use n8n's built-in **Error Trigger** node for workflow-level error handling Reusable Credentials [#reusable-credentials] Create a single Bearer Auth credential named "dryAPI" and reuse it across all HTTP Request nodes. *** Other Endpoints [#other-endpoints] Use the same polling pattern for all dryAPI endpoints: | Service | POST Endpoint | | ------------------------ | ------------------------------ | | Text-to-Image | `/api/v1/client/txt2img` | | Image-to-Image | `/api/v1/client/img2img` | | Text-to-Video | `/api/v1/client/txt2video` | | Image-to-Video | `/api/v1/client/img2video` | | Text-to-Speech | `/api/v1/client/txt2audio` | | Text-to-Music | `/api/v1/client/txt2music` | | Audio-to-Video | `/api/v1/client/aud2video` | | Video-to-Text (URL) | `/api/v1/client/vid2txt` | | Video-to-Text (File) | `/api/v1/client/videofile2txt` | | Audio-to-Text (File) | `/api/v1/client/audiofile2txt` | | Audio-to-Text (X Spaces) | `/api/v1/client/aud2txt` | | Background Removal | `/api/v1/client/img-rmbg` | | OCR (Image-to-Text) | `/api/v1/client/img2txt` | | Text-to-Embedding | `/api/v1/client/txt2embedding` | All endpoints follow the same pattern: 1. `POST` to submit the job → receive `request_id` 2. `GET /api/v1/client/request-status/{request_id}` → poll status 3. When `status: "done"` → use `result_url` or `result` *** Resources [#resources] * [n8n Documentation](https://docs.n8n.io/) * [dryAPI Community Node](/docs/v1/execution-modes-and-integrations/n8n-dryapi-node) * [dryAPI API Reference](/docs/v1/api/overview) * [Execution Modes & HTTP Queue](/docs/v1/execution-modes-and-integrations/execution-modes-and-http-queue) * [Model Selection](/docs/v1/api/utilities/model-selection) # Webhooks (/docs/v1/execution-modes-and-integrations/webhooks) > Receive real-time notifications about job status changes Overview [#overview] Webhooks allow you to receive real-time HTTP notifications when your inference jobs change status, eliminating the need to poll the `/request-status` endpoint. > **INFO** > > Webhooks are sent as `POST` requests to your specified URL with a JSON payload and security headers for verification. Configuration [#configuration] Global Webhook URL [#global-webhook-url] Configure a global webhook URL in your [account settings](https://dryapi.dev/settings/webhooks). All jobs will send notifications to this URL unless overridden. Per-Request Override [#per-request-override] You can override the global webhook URL on any job request by including the `webhook_url` parameter: ```json theme={null} { "prompt": "a beautiful sunset over mountains", "model": "flux-2-klein-4b-bf16", "webhook_url": "https://your-server.com/webhooks/dryapi" } ``` > **WARNING** > > Only HTTPS URLs are accepted. HTTP URLs will be rejected for security. Events [#events] Webhooks are sent on the following status transitions: | Event | Trigger | Description | | ---------------- | ---------------------- | --------------------------------------------- | | `job.processing` | `pending → processing` | Job assigned to a worker, processing started | | `job.completed` | `processing → done` | Job completed successfully, results available | | `job.failed` | `processing → error` | Job failed during processing | Request Format [#request-format] Headers [#headers] All webhook requests include these headers: | Header | Description | Example | | ---------------------- | -------------------------------------- | -------------------------------------------- | | `X-DryAPI-Signature` | HMAC-SHA256 signature for verification | `sha256=5d41402abc4b2a76b9719d911017c592...` | | `X-DryAPI-Timestamp` | Unix timestamp when webhook was sent | `1705315800` | | `X-DryAPI-Event` | Event type that triggered the webhook | `job.completed` | | `X-DryAPI-Delivery-Id` | Unique identifier for this delivery | `550e8400-e29b-41d4-a716-446655440001` | | `Content-Type` | Always `application/json` | `application/json` | | `User-Agent` | Identifies the sender | `DryAPI-Webhook/1.0` | Payload Structure [#payload-structure] Sent when a worker starts processing your job. ```json theme={null} { "event": "job.processing", "delivery_id": "550e8400-e29b-41d4-a716-446655440000", "timestamp": "2024-01-15T10:30:00.000Z", "data": { "job_request_id": "123e4567-e89b-12d3-a456-426614174000", "status": "processing", "previous_status": "pending", "job_type": "txt2img", "started_at": "2024-01-15T10:30:00.000Z" } } ``` | Field | Type | Description | | ---------------------- | ----------------- | ---------------------------------------- | | `data.job_request_id` | string (UUID) | Your job's unique identifier | | `data.status` | string | Current status: `processing` | | `data.previous_status` | string | Previous status: `pending` | | `data.job_type` | string | Type of job (e.g., `txt2img`, `vid2txt`) | | `data.started_at` | string (ISO 8601) | When processing began | Sent when your job completes successfully. ```json theme={null} { "event": "job.completed", "delivery_id": "550e8400-e29b-41d4-a716-446655440001", "timestamp": "2024-01-15T10:30:45.000Z", "data": { "job_request_id": "123e4567-e89b-12d3-a456-426614174000", "status": "done", "previous_status": "processing", "job_type": "txt2img", "completed_at": "2024-01-15T10:30:45.000Z", "result_url": "https://storage.dryapi.dev/results/.../output.png", "processing_time_ms": 45000 } } ``` | Field | Type | Description | | ------------------------- | ----------------- | ------------------------------- | | `data.job_request_id` | string (UUID) | Your job's unique identifier | | `data.status` | string | Current status: `done` | | `data.previous_status` | string | Previous status: `processing` | | `data.job_type` | string | Type of job | | `data.completed_at` | string (ISO 8601) | When job completed | | `data.result_url` | string (URL) | URL to download the result | | `data.processing_time_ms` | integer | Processing time in milliseconds | Sent when your job fails during processing. ```json theme={null} { "event": "job.failed", "delivery_id": "550e8400-e29b-41d4-a716-446655440002", "timestamp": "2024-01-15T10:30:45.000Z", "data": { "job_request_id": "123e4567-e89b-12d3-a456-426614174000", "status": "error", "previous_status": "processing", "job_type": "txt2img", "failed_at": "2024-01-15T10:30:45.000Z", "error_code": "WORKER_TIMEOUT", "error_message": "Worker failed to respond within the allowed time" } } ``` | Field | Type | Description | | ---------------------- | ----------------- | -------------------------------- | | `data.job_request_id` | string (UUID) | Your job's unique identifier | | `data.status` | string | Current status: `error` | | `data.previous_status` | string | Previous status: `processing` | | `data.job_type` | string | Type of job | | `data.failed_at` | string (ISO 8601) | When the job failed | | `data.error_code` | string | Machine-readable error code | | `data.error_message` | string | Human-readable error description | **Error Codes:** | Code | Description | | ------------------------- | ------------------------------------ | | `WORKER_TIMEOUT` | Worker didn't respond in time | | `PROCESSING_ERROR` | Error during inference | | `AGE_RESTRICTED` | Content flagged as age-restricted | | `CONTEXT_LENGTH_EXCEEDED` | Input exceeded model's context limit | | `INVALID_INPUT` | Invalid input data | | `UNKNOWN_ERROR` | Unexpected error | Security [#security] Signature Verification [#signature-verification] Every webhook includes an HMAC-SHA256 signature in the `X-DryAPI-Signature` header. **Always verify this signature** to ensure the request came from dryAPI. **Signature format:** `sha256=` **How to verify:** 1. Get the timestamp from `X-DryAPI-Timestamp` header 2. Get the raw JSON body (don't parse it first) 3. Concatenate: `timestamp + "." + raw_body` 4. Calculate HMAC-SHA256 using your webhook secret 5. Compare with the signature (use timing-safe comparison) ```javascript Node.js theme={null} const crypto = require('crypto'); function verifyWebhook(req, secret) { const signature = req.headers['x-dryapi-signature']; const timestamp = req.headers['x-dryapi-timestamp']; const body = req.body.toString(); // Raw request body as string // Check timestamp is within 5 minutes const now = Math.floor(Date.now() / 1000); if (Math.abs(now - parseInt(timestamp)) > 300) { return false; // Reject old requests (replay attack prevention) } // Calculate expected signature const message = `${timestamp}.${body}`; const expected = 'sha256=' + crypto .createHmac('sha256', secret) .update(message) .digest('hex'); // Timing-safe comparison return crypto.timingSafeEqual( Buffer.from(signature), Buffer.from(expected) ); } ``` ```python Python theme={null} import hmac import hashlib import time def verify_webhook(headers, body, secret): signature = headers.get('X-DryAPI-Signature', '') timestamp = headers.get('X-DryAPI-Timestamp', '') # Check timestamp is within 5 minutes now = int(time.time()) if abs(now - int(timestamp)) > 300: return False # Reject old requests # Calculate expected signature message = f"{timestamp}.{body}" expected = 'sha256=' + hmac.new( secret.encode(), message.encode(), hashlib.sha256 ).hexdigest() # Timing-safe comparison return hmac.compare_digest(signature, expected) ``` ```php PHP theme={null} function verifyWebhook(array $headers, string $body, string $secret): bool { $signature = $headers['X-DryAPI-Signature'] ?? ''; $timestamp = $headers['X-DryAPI-Timestamp'] ?? ''; // Check timestamp is within 5 minutes if (abs(time() - (int) $timestamp) > 300) { return false; // Reject old requests } // Calculate expected signature $message = $timestamp . '.' . $body; $expected = 'sha256=' . hash_hmac('sha256', $message, $secret); // Timing-safe comparison return hash_equals($expected, $signature); } ``` ```go Go theme={null} package main import ( "crypto/hmac" "crypto/sha256" "encoding/hex" "fmt" "math" "strconv" "time" ) func verifyWebhook(signature, timestamp, body, secret string) bool { // Check timestamp is within 5 minutes ts, _ := strconv.ParseInt(timestamp, 10, 64) now := time.Now().Unix() if math.Abs(float64(now-ts)) > 300 { return false } // Calculate expected signature message := fmt.Sprintf("%s.%s", timestamp, body) mac := hmac.New(sha256.New, []byte(secret)) mac.Write([]byte(message)) expected := "sha256=" + hex.EncodeToString(mac.Sum(nil)) // Timing-safe comparison return hmac.Equal([]byte(signature), []byte(expected)) } ``` Best Practices [#best-practices] > Never process webhooks without verifying the HMAC signature first. > Reject webhooks with timestamps older than 5 minutes to prevent replay attacks. > Only configure HTTPS endpoints. HTTP is rejected automatically. > Use `delivery_id` to detect and handle duplicate deliveries. Retry Policy [#retry-policy] If your endpoint fails to respond with a `2xx` status code, we'll retry delivery with exponential backoff: | Attempt | Delay | Cumulative Time | | ------- | ---------- | --------------- | | 1 | Immediate | 0 | | 2 | 1 minute | 1 min | | 3 | 2 minutes | 3 min | | 4 | 5 minutes | 8 min | | 5 | 10 minutes | 18 min | | 6 | 30 minutes | 48 min | | 7 | 1 hour | 1h 48min | | 8 | 3 hours | 4h 48min | | 9 | 6 hours | 10h 48min | | 10 | 12 hours | 22h 48min | After 10 failed attempts (\~24 hours), the webhook is marked as failed. > **WARNING** > > **Circuit Breaker:** After 10 consecutive failed deliveries across any webhooks for your account, webhooks are automatically disabled. Re-enable them in your account settings after fixing your endpoint. Response Requirements [#response-requirements] Your endpoint should: * Return a `2xx` status code (200-299) within **10 seconds** * Not follow redirects (3xx responses are treated as failures) * Process the webhook asynchronously if needed (respond quickly, process later) ```javascript theme={null} // Example: Express.js endpoint app.post('/webhooks/dryapi', express.raw({ type: 'application/json' }), (req, res) => { // Verify signature first if (!verifyWebhook(req, process.env.DRYAPI_WEBHOOK_SECRET)) { return res.status(401).send('Invalid signature'); } const event = JSON.parse(req.body); // Respond immediately res.status(200).send('OK'); // Process asynchronously processWebhookAsync(event); }); ``` Testing [#testing] Use [webhook.site](https://webhook.site) to test webhooks during development: 1. Get a unique URL from webhook.site 2. Configure it as your webhook URL (per-request or global) 3. Submit a job and watch the webhooks arrive 4. Verify headers and payloads match the expected format > **TIP** > > You can also use tools like ngrok to expose your local development server to receive webhooks. # WebSockets (/docs/v1/execution-modes-and-integrations/websockets) > Receive real-time job status updates via WebSocket connections Overview [#overview] WebSockets provide real-time job status updates through a persistent connection. Unlike polling, updates are pushed instantly as they happen, including live preview images during generation. > **INFO** > > WebSockets are ideal for interactive applications where you need instant feedback on job progress. Quick Start [#quick-start] Install the required packages: ```bash theme={null} npm install pusher-js laravel-echo ``` Connect and listen for updates: ```javascript theme={null} import Pusher from 'pusher-js'; const CLIENT_ID = 'your-client-id'; // From your dashboard const API_TOKEN = 'your-api-token'; // From authentication const pusher = new Pusher('depin-api-prod-key', { wsHost: 'soketi.dryapi.dev', wsPort: 443, forceTLS: true, cluster: 'mt1', enabledTransports: ['ws', 'wss'], authorizer: (channel) => ({ authorize: async (socketId, callback) => { const res = await fetch('https://api.dryapi.dev/broadcasting/auth', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${API_TOKEN}` }, body: JSON.stringify({ socket_id: socketId, channel_name: channel.name }) }); callback(null, await res.json()); } }) }); pusher.subscribe(`private-client.${CLIENT_ID}`) .bind('request.status.updated', (data) => { console.log(`Job ${data.request_id}: ${data.status} (${data.progress}%)`); if (data.result_url) console.log('Result:', data.result_url); }); ``` When to Use WebSockets vs Webhooks [#when-to-use-websockets-vs-webhooks] | Feature | WebSockets | Webhooks | | ------------------- | ------------------------------- | -------------------------------- | | Latency | Instant (milliseconds) | Near-instant (seconds) | | Connection | Persistent | Per-event HTTP request | | Progress updates | Yes, with image previews | No | | Server requirements | WebSocket client | HTTP endpoint | | Reliability | Requires active connection | Automatic retries | | Best for | Interactive UIs, real-time apps | Backend integrations, serverless | > **TIP** > > For maximum reliability, use both: WebSockets for real-time UI updates and webhooks as a backup for critical notifications. Configuration [#configuration] Connection Details [#connection-details] | Setting | Value | | -------- | -------------------- | | Host | `soketi.dryapi.dev` | | Port | `443` | | Protocol | WSS (secure) | | App Key | `depin-api-prod-key` | Required Credentials [#required-credentials] * **Client ID:** Your unique identifier (from [dashboard](https://dryapi.dev/dashboard)) * **API Token:** Your authentication token (see [Authentication](/authentication)) Connecting [#connecting] We use a Pusher-compatible protocol. You can use any Pusher client library. Using Laravel Echo (Recommended for Frontend) [#using-laravel-echo-recommended-for-frontend] ```javascript theme={null} import Echo from 'laravel-echo'; import Pusher from 'pusher-js'; window.Pusher = Pusher; const echo = new Echo({ broadcaster: 'pusher', key: 'depin-api-prod-key', wsHost: 'soketi.dryapi.dev', wsPort: 443, wssPort: 443, forceTLS: true, enabledTransports: ['ws', 'wss'], cluster: 'mt1', authorizer: (channel) => ({ authorize: (socketId, callback) => { fetch('https://api.dryapi.dev/broadcasting/auth', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${YOUR_API_TOKEN}` }, body: JSON.stringify({ socket_id: socketId, channel_name: channel.name }) }) .then(response => response.json()) .then(data => callback(null, data)) .catch(error => callback(error)); } }) }); // Subscribe to your channel echo.private(`client.${YOUR_CLIENT_ID}`) .listen('.request.status.updated', (data) => { console.log('Job update:', data); }); ``` Using Pusher Client Directly [#using-pusher-client-directly] ```javascript JavaScript theme={null} import Pusher from 'pusher-js'; const pusher = new Pusher('depin-api-prod-key', { wsHost: 'soketi.dryapi.dev', wsPort: 443, wssPort: 443, forceTLS: true, enabledTransports: ['ws', 'wss'], cluster: 'mt1', authorizer: (channel) => ({ authorize: async (socketId, callback) => { try { const response = await fetch('https://api.dryapi.dev/broadcasting/auth', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${YOUR_API_TOKEN}` }, body: JSON.stringify({ socket_id: socketId, channel_name: channel.name }) }); callback(null, await response.json()); } catch (error) { callback(error); } } }) }); const channel = pusher.subscribe(`private-client.${YOUR_CLIENT_ID}`); channel.bind('request.status.updated', (data) => { console.log('Job update:', data); }); ``` ```python Python theme={null} import pysher import time YOUR_API_TOKEN = 'your-api-token' YOUR_CLIENT_ID = 'your-client-id' pusher = pysher.Pusher( key='depin-api-prod-key', custom_host='soketi.dryapi.dev', secure=True, port=443, auth_endpoint='https://api.dryapi.dev/broadcasting/auth', auth_endpoint_headers={ 'Authorization': f'Bearer {YOUR_API_TOKEN}' } ) def on_connect(data): channel = pusher.subscribe(f'private-client.{YOUR_CLIENT_ID}') channel.bind('request.status.updated', lambda data: print(f'Update: {data}')) pusher.connection.bind('pusher:connection_established', on_connect) pusher.connect() while True: time.sleep(1) ``` Channels [#channels] Each client has a private channel scoped to their account: ``` private-client.{client_id} ``` > **WARNING** > > Private channels require authentication. You can only subscribe to your own channel. > **INFO** > > When using Laravel Echo, use `.listen('.request.status.updated', ...)` with a dot prefix. With raw Pusher, use `.bind('request.status.updated', ...)` without the dot. Events [#events] request.status.updated [#requeststatusupdated] Sent whenever a job's status changes or progress is updated. **Event Payload:** ```json theme={null} { "request_id": "123e4567-e89b-12d3-a456-426614174000", "status": "in_progress", "preview": "data:image/jpeg;base64,/9j/4AAQSkZJRg...", "result_url": null, "progress": "45.50" } ``` | Field | Type | Description | | ------------ | -------------- | ------------------------------------------------------- | | `request_id` | string | Job's unique identifier (UUID) | | `status` | string | Current status: `processing`, `in_progress`, or `done` | | `preview` | string \| null | Base64 preview image (image generation jobs only) | | `result_url` | string \| null | Signed download URL (only when `done`) | | `progress` | string | Progress percentage as decimal string (e.g., `"45.50"`) | > **WARNING** > > The `result_url` is a signed URL that expires. Download promptly or use the job status endpoint to get a fresh URL. Status Flow [#status-flow] ``` pending → processing → in_progress (multiple) → done ↘ ↗ ─────── error ───────── ``` | Status | Description | WebSocket Event | | ------------- | ------------------------------ | ------------------------------ | | `pending` | Job queued, waiting for worker | No | | `processing` | Worker assigned, starting | Yes | | `in_progress` | Actively generating | Yes (with previews) | | `done` | Completed successfully | Yes (with result URL) | | `error` | Failed | Via [webhooks](/webhooks) only | Complete Examples [#complete-examples] React Hook [#react-hook] ```typescript theme={null} import { useEffect, useState, useCallback } from 'react'; import Echo from 'laravel-echo'; import Pusher from 'pusher-js'; interface JobUpdate { request_id: string; status: 'processing' | 'in_progress' | 'done'; preview: string | null; result_url: string | null; progress: string; } export function useJobUpdates(clientId: string, apiToken: string) { const [updates, setUpdates] = useState>(new Map()); const [connected, setConnected] = useState(false); useEffect(() => { window.Pusher = Pusher; const echo = new Echo({ broadcaster: 'pusher', key: 'depin-api-prod-key', wsHost: 'soketi.dryapi.dev', wsPort: 443, wssPort: 443, forceTLS: true, enabledTransports: ['ws', 'wss'], cluster: 'mt1', authorizer: (channel) => ({ authorize: (socketId, callback) => { fetch('https://api.dryapi.dev/broadcasting/auth', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${apiToken}` }, body: JSON.stringify({ socket_id: socketId, channel_name: channel.name }) }) .then(res => res.json()) .then(data => callback(null, data)) .catch(err => callback(err)); } }) }); echo.connector.pusher.connection.bind('connected', () => setConnected(true)); echo.connector.pusher.connection.bind('disconnected', () => setConnected(false)); echo.private(`client.${clientId}`) .listen('.request.status.updated', (data: JobUpdate) => { setUpdates(prev => new Map(prev).set(data.request_id, data)); }); return () => { echo.leave(`client.${clientId}`); echo.disconnect(); }; }, [clientId, apiToken]); const getJobUpdate = useCallback((requestId: string) => updates.get(requestId), [updates]); return { updates, connected, getJobUpdate }; } ``` Node.js Backend [#nodejs-backend] ```javascript theme={null} import Pusher from 'pusher-js'; const CLIENT_ID = process.env.DRYAPI_CLIENT_ID; const API_TOKEN = process.env.DRYAPI_API_TOKEN; const pusher = new Pusher('depin-api-prod-key', { wsHost: 'soketi.dryapi.dev', wsPort: 443, wssPort: 443, forceTLS: true, enabledTransports: ['ws', 'wss'], cluster: 'mt1', authorizer: (channel) => ({ authorize: async (socketId, callback) => { try { const response = await fetch('https://api.dryapi.dev/broadcasting/auth', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${API_TOKEN}` }, body: JSON.stringify({ socket_id: socketId, channel_name: channel.name }) }); callback(null, await response.json()); } catch (error) { callback(error); } } }) }); pusher.connection.bind('connected', () => console.log('Connected')); pusher.connection.bind('error', (err) => console.error('Error:', err)); const channel = pusher.subscribe(`private-client.${CLIENT_ID}`); channel.bind('pusher:subscription_succeeded', () => console.log('Subscribed')); channel.bind('request.status.updated', (data) => { console.log(`Job ${data.request_id}: ${data.status} (${data.progress}%)`); if (data.preview) console.log('Preview available'); if (data.result_url) console.log('Download:', data.result_url); }); process.on('SIGINT', () => { pusher.disconnect(); process.exit(); }); ``` Authentication [#authentication] Private channels require authorization via the broadcasting auth endpoint. **Endpoint:** `POST https://api.dryapi.dev/broadcasting/auth` **Headers:** ``` Authorization: Bearer Content-Type: application/json ``` **Request:** ```json theme={null} { "socket_id": "123456.789012", "channel_name": "private-client.42" } ``` **Response:** ```json theme={null} { "auth": "depin-api-prod-key:signature..." } ``` > **INFO** > > The Pusher client libraries handle this automatically via the `authorizer` callback. Connection Management [#connection-management] Keep-Alive [#keep-alive] The WebSocket server expects a ping every 30 seconds. Most Pusher client libraries handle this automatically. If implementing a custom client, send a `pusher:ping` event within the timeout window to maintain the connection. Reconnection [#reconnection] The Pusher client handles reconnection automatically with exponential backoff. ```javascript theme={null} // Monitor connection state pusher.connection.bind('state_change', (states) => { console.log('State:', states.current); // States: initialized, connecting, connected, unavailable, failed, disconnected }); // Clean up when done pusher.unsubscribe(`private-client.${clientId}`); pusher.disconnect(); ``` Troubleshooting [#troubleshooting] * Verify your API token is valid * Check that you're using `soketi.dryapi.dev` as the host * Ensure port 443 is not blocked by your firewall * Confirm your client ID matches your API token * Verify channel name format: `private-client.{your_client_id}` * Check that your API token has not been revoked * Use `.request.status.updated` with Echo (dot prefix) or `request.status.updated` with Pusher (no dot) * Verify subscription succeeded via `pusher:subscription_succeeded` event * Ensure jobs are submitted with the same client credentials * The client library reconnects automatically * Monitor `state_change` events to track connection health * Consider using [webhooks](/webhooks) as a backup # FAQ — Frequently Asked Questions (/docs/v1/other/faq-frequently-asked-questions) 1\. **How do I get access to the dryAPI panel?** [#1-how-do-i-get-access-to-the-dryapi-panel] Register or log in (also via Google OAuth) and after authentication you will automatically gain access to the Control Panel, where you can directly create an API key and get access the full capabilities of the platform. *** 2\. **How can I get my API key?** [#2-how-can-i-get-my-api-key] Simply sign up or log in, then navigate to your Dashboard → Settings → API Keys and click "Create new secret key" to instantly generate your API key. *** 3\. **Do I need to fund my account before using the API?** [#3-do-i-need-to-fund-my-account-before-using-the-api] **No.** Upon registration, you receive a **$5 bonus** to get started immediately with Basic rate limits. You do not need to make a payment to start testing. Once you make **any payment** (top-up), your account automatically upgrades to **Premium**, unlocking the 300 RPM limit and unlimited daily requests. *** 4\. **How is authentication handled?** [#4-how-is-authentication-handled] Every API request requires an `Authorization` header with your personal token: ``` Authorization: Bearer YOUR_API_KEY ``` *** 5\. **How do I retrieve the results of my tasks?** [#5-how-do-i-retrieve-the-results-of-my-tasks] After submitting a task, you'll receive a `request_id`. Use this ID with the **Get Results** endpoint (`GET /api/v1/client/request-status/{request_id}`) to fetch your generated image, video, audio, or transcription. *** 6\. **Are there any rate limits?** [#6-are-there-any-rate-limits] **Yes.** The limits depend on your account type: * **Basic (Free):** Designed for testing. Limits are restrictive, ranging from **1 to 10 RPM** (Requests Per Minute) depending on the endpoint, with daily caps. * **Premium:** Activated by any available payment. Offers a unified high limit of **300 RPM** across all endpoints with **unlimited daily requests**. If you exceed these limits, you'll receive a `429 Too Many Requests` response. For High Volume Production requirements beyond Premium limits, please contact support. *** 7\. **Can I choose between different AI models?** [#7-can-i-choose-between-different-ai-models] Yes. Visit the **Model Selection** endpoint to browse available models, or check the **Models** page for a complete list. You can specify the desired model using the `model` parameter when making API requests. *** 8\. **What file types are supported?** [#8-what-file-types-are-supported] **Video** (Video-to-Text, Image-to-Video): * Max size: 100 MB * Supported formats: mp4, avi, mov, mkv, webm **Audio** (Audio-to-Text): * Max size: 50 MB (recommended), up to 100 MB * Supported formats: mp3, wav, m4a, flac, ogg **Images** (Image-to-Image, OCR, Background Removal): * Max size: 10 MB * Supported formats: jpg, png, webp *** 9\. **What services does dryAPI offer?** [#9-what-services-does-dryapi-offer] dryAPI provides the following AI-powered services: * **Text-to-Image** — Generate images from text prompts (Flux, Z-Image-Turbo) * **Image-to-Image** — Transform and edit existing images * **Image Background Removal** — Remove backgrounds for transparent PNGs * **Text-to-Video** — Generate videos from text descriptions * **Image-to-Video** — Animate static images into videos * **Text-to-Speech (TTS)** — Convert text to natural-sounding audio with preset voices, voice cloning, or voice design * **Text-to-Music** — Generate music tracks from text descriptions with lyrics, tempo, key, and style control * **Video-to-Text** — Transcribe videos from YouTube, Twitch, Kick, TikTok, X, and file uploads * **Audio-to-Text** — Transcribe audio files and X/Twitter Spaces * **Image-to-Text (OCR)** — Extract text from images * **Text-to-Embedding** — Generate vector embeddings for semantic search *** 10\. **Can I use dryAPI with AI assistants like Claude or Cursor?** [#10-can-i-use-dryapi-with-ai-assistants-like-claude-or-cursor] Yes! dryAPI offers an **MCP (Model Context Protocol) server** that allows AI assistants and IDE extensions to call dryAPI capabilities as structured tools. You can connect Claude, Cursor, and other MCP-compatible clients to generate images, transcribe videos, and more directly within conversations. See the **MCP Server** documentation for setup instructions. *** 11\. **Can I use dryAPI with n8n or other automation tools?** [#11-can-i-use-dryapi-with-n8n-or-other-automation-tools] Yes! dryAPI works seamlessly with **n8n** and other workflow automation platforms. You can build automated workflows that generate images, transcribe videos, create speech, and more using dryAPI's HTTP API. The integration uses standard HTTP Request nodes with Bearer token authentication. See the **n8n Integration** documentation for a complete step-by-step guide with example workflows. *** 12\. **Is dryAPI ready for production use?** [#12-is-dryapi-ready-for-production-use] Yes. dryAPI is built to support production-grade workloads. All models and services are optimized for speed, reliability, and scalability. The platform offers 300 RPM immediately after the first account top-up. *** 13\. **What should I do if I get an error?** [#13-what-should-i-do-if-i-get-an-error] Check the error code and make sure: * `401` — Your API key is valid * `403` — Your account has sufficient permissions * `429` — You haven't exceeded rate limits * `500` — Server error (check [status.dryapi.dev](https://status.dryapi.dev/)) Also verify your request parameters are correct. If the issue persists, contact our support team at [**support@dryapi.dev**](mailto:support@dryapi.dev) or join our [Discord](https://discord.com/invite/UFfK5YRBsr) for help. # Payment Methods (/docs/v1/other/payment-methods) dryAPI uses a prepaid credit balance. All API usage is charged against your credits, and you can top up your balance directly from the dashboard using Stripe. Single payments (one-off top-ups) [#single-payments-one-off-top-ups] On the **Balance** page you can make a one-off payment: * Choose a top-up amount (e.g. **10 USD**, **25 USD**, **50 USD**). * Pay securely via **Stripe** (card and supported local methods). * The selected amount is immediately converted into credits and added to your account balance. Use this option if you prefer to control every top-up manually. *** Automatic payments (auto top-ups) [#automatic-payments-auto-top-ups] You can also enable **automatic top-ups** to keep your projects running without interruption: * Pick a recurring top-up amount (e.g. **10 USD**, **25 USD**, **50 USD**). * When your balance drops below **2.00 USD**, dryAPI will automatically: * charge the selected amount via Stripe, and * add the corresponding credits to your account. * You can turn automatic top-ups on or off at any time from the **Balance** page. This is recommended for production workloads where you don't want jobs to fail due to insufficient credits. *** Other payment options & B2B billing [#other-payment-options--b2b-billing] At the moment, **Stripe** is the primary payment provider for dryAPI. For **B2B customers**, payment terms and billing methods (e.g. custom invoices, larger commitments) are discussed individually. If you are interested in a B2B agreement, please contact us at **[support@dryapi.dev](mailto:support@dryapi.dev)**. # SDKs & Integrations (/docs/v1/other/sdks-and-integrations) Python SDK [#python-sdk] The official Python SDK for dryAPI. Generate images, videos, audio, transcriptions, embeddings, and more — through a type-safe Python interface with sync and async support. * [GitHub Repository](https://github.com/dryapi-ai/dryapi-python-sdk) - dryapi-ai/dryapi-python-sdk Installation [#installation] ```bash theme={null} pip install dryapi-python-sdk ``` **Requirements:** Python 3.9+ Quick Start [#quick-start] ```python theme={null} from dryapi import DryapiClient client = DryapiClient(api_key="sk-your-api-key") # Generate an image job = client.images.generate( prompt="a cat floating in a nebula, photorealistic", model="Flux_2_Klein_4B_BF16", width=1024, height=1024, steps=4, seed=-1, ) # Wait for the result (polls with exponential backoff) result = job.wait() print(result.result_url) ``` Features [#features] * **Full API coverage** — images, video, audio (TTS, voice cloning, music), transcription, embeddings, OCR, prompt enhancement * **Sync + Async** — `DryapiClient` and `AsyncDryapiClient` * **Job polling** — automatic exponential backoff with `.wait()` * **Auto-retry** — built-in retry on rate limits (429) and server errors (5xx) * **Type-safe** — full type hints, Pydantic v2 models, `py.typed` marker * **Webhook verification** — HMAC-SHA256 signature validation * **Price calculation** — every method has a `_price` counterpart to check cost before submitting > **TIP** > > For full documentation, configuration options, usage examples, and API reference, visit the [GitHub repository](https://github.com/dryapi-ai/dryapi-python-sdk). *** Coming Soon [#coming-soon] We're working on official SDKs for: * Node.js / TypeScript # Support & Contact (/docs/v1/other/support-and-contact) For any technical assistance, API-related questions, or troubleshooting issues, feel free to contact our support team directly. X: [**https://x.com/dryAPI\_**](https://x.com/dryAPI_) Discord: [**https://discord.gg/UFfK5YRBsr**](https://discord.gg/UFfK5YRBsr) Github: [**https://github.com/dryapi-ai**](https://github.com/dryapi-ai) Email: [**support@dryapi.dev**](mailto:support@dryapi.dev) # Audio-to-Text (X Spaces) Price Calculation (/docs/v1/api/analysis/audio-to-text-spaces-price) > Endpoint for calculating price for audio to text inference (Twitter Spaces) OpenAPI [#openapi] # Audio-to-Text (X Spaces Transcription) (/docs/v1/api/analysis/audio-to-text-spaces) > Endpoint for requesting audio transcription (Twitter Spaces) > **NOTE** > > **Prerequisite:** To ensure a successful request, you must first consult the [Model Selection](/docs/v1/api/utilities/model-selection) endpoint to identify a valid model `slug`, check specific **limits** and **features**, and verify **LoRA** availability. Technical Notes & Constraints [#technical-notes--constraints] Spaces Support [#spaces-support] * **Completed Spaces Only**: The API does not support live (ongoing) X Spaces. If a URL for an active Space is provided, the API will return a validation error. Please ensure the Space has ended before submission. * **Max Duration**: 90 minutes Progress Tracking (URL/Spaces) [#progress-tracking-urlspaces] * **Download Phase:** Due to external stream handling, the task progress will remain at 0% for the entire duration of the audio download. * **Transcription Phase**: Once the download is complete, the progress status will jump to 50% and update incrementally until finished. * A prolonged 0% status is normal behavior for long X Spaces. > **INFO** > > Transcription for standard video posts on X is handled via the [Video-to-Text](/docs/v1/api/analysis/video-to-text) endpoint. OpenAPI [#openapi] # Image-to-Text Price Calculation (/docs/v1/api/analysis/image-to-text-price) > Endpoint for calculating price for image2text (OCR) inference OpenAPI [#openapi] # Image-to-Text (OCR) (/docs/v1/api/analysis/image-to-text) > Endpoint for requesting image2text (OCR) inference > **NOTE** > > **Prerequisite:** To ensure a successful request, you must first consult the [Model Selection](/docs/v1/api/utilities/model-selection) endpoint to identify a valid model `slug`, check specific **limits** and **features**, and verify **LoRA** availability. OpenAPI [#openapi] # Upload Audio File Price Calculation (/docs/v1/api/analysis/upload-audio-file-price) > Endpoint for requesting audio transcription price OpenAPI [#openapi] # Upload Audio File (Audio-to-Text) (/docs/v1/api/analysis/upload-audio-file) > Endpoint for requesting audio transcription > **NOTE** > > **Prerequisite:** To ensure a successful request, you must first consult the [Model Selection](/docs/v1/api/utilities/model-selection) endpoint to identify a valid model `slug`, check specific **limits** and **features**, and verify **LoRA** availability. OpenAPI [#openapi] # Upload Video File Price Calculation (/docs/v1/api/analysis/upload-video-file-price) > Endpoint for calculating price for video to text inference OpenAPI [#openapi] # Upload Video File (Video-to-Text) (/docs/v1/api/analysis/upload-video-file) > Endpoint for requesting video transcription > **NOTE** > > **Prerequisite:** To ensure a successful request, you must first consult the [Model Selection](/docs/v1/api/utilities/model-selection) endpoint to identify a valid model `slug`, check specific **limits** and **features**, and verify **LoRA** availability. OpenAPI [#openapi] # Video-to-Text Price Calculation (/docs/v1/api/analysis/video-to-text-price) > Endpoint for calculating price for video to text inference OpenAPI [#openapi] # Video-to-Text (Transcription) (/docs/v1/api/analysis/video-to-text) > Unique Platform Support: dryAPI is one of the few APIs offering direct transcription from YT, TikTok, Twitch VODs, X and Kick videos — no need to download files first. Just paste the URL. > **NOTE** > > **Prerequisite:** To ensure a successful request, you must first consult the [Model Selection](/docs/v1/api/utilities/model-selection) endpoint to identify a valid model `slug`, check specific **limits** and **features**, and verify **LoRA** availability. OpenAPI [#openapi] # Audio-to-Video Price Calculation (/docs/v1/api/generation/audio-to-video-price) > Endpoint for calculating price for audio2video inference OpenAPI [#openapi] # Audio-to-Video (/docs/v1/api/generation/audio-to-video) > Endpoint for requesting audio2video inference Audio-to-Video generates video clips conditioned on an audio file and a text prompt. You can optionally provide first and last frame images to control the visual start and end points. The endpoint returns a task ID to track processing status. > **NOTE** > > **Prerequisite:** To ensure a successful request, you must first consult the [Model Selection](/docs/v1/api/utilities/model-selection) endpoint to identify a valid model `slug`, check specific **limits** and **features**. OpenAPI [#openapi] # Image-to-Video Price Calculation (/docs/v1/api/generation/image-to-video-price) > Endpoint for calculating price for image2video inference OpenAPI [#openapi] # Image-to-Video (/docs/v1/api/generation/image-to-video) > Endpoint for requesting image2video inference > **NOTE** > > **Prerequisite:** To ensure a successful request, you must first consult the [Model Selection](/docs/v1/api/utilities/model-selection) endpoint to identify a valid model `slug`, check specific **limits** and **features**, and verify **LoRA** availability. Please **omit** the LoRA parameter by default during initial testing. OpenAPI [#openapi] # Text-to-Embedding Price Calculation (/docs/v1/api/generation/text-to-embedding-price) > Endpoint for calculating price for text to embedding inference OpenAPI [#openapi] # Text-to-Embedding (/docs/v1/api/generation/text-to-embedding) > Endpoint for requesting text to embedding inference > **NOTE** > > **Prerequisite:** To ensure a successful request, you must first consult the [Model Selection](/docs/v1/api/utilities/model-selection) endpoint to identify a valid model `slug`, check specific **limits** and **features**, and verify **LoRA** availability. OpenAPI [#openapi] # Text-to-Image Price Calculation (/docs/v1/api/generation/text-to-image-price) > Endpoint for calculating price for text2img inference OpenAPI [#openapi] # Text-to-Image (/docs/v1/api/generation/text-to-image) > Endpoint for requesting text2img inference Text-to-Image generates images from text prompts. The endpoint returns a ready-to-use image URL and a task ID to track processing status. Ideal for apps needing automated image creation. > **NOTE** > > **Prerequisite:** To ensure a successful request, you must first consult the [Model Selection](/docs/v1/api/utilities/model-selection) endpoint to identify a valid model `slug`, check specific **limits** and **features**, and verify **LoRA** availability. Please **omit** the LoRA parameter by default during initial testing. OpenAPI [#openapi] # Text-to-Music Price Calculation (/docs/v1/api/generation/text-to-music-price) > Endpoint for calculating price for text2music inference. Requires duration and inference\_steps parameters. OpenAPI [#openapi] # Text-to-Music (/docs/v1/api/generation/text-to-music) > Endpoint for requesting text2music inference Text-to-Music generates music tracks from text descriptions. You can control genre, tempo, key, time signature, and even provide lyrics. Optionally upload a `reference_audio` file for style transfer — the model will use it as a stylistic reference for the generated track. The endpoint returns a task ID to track processing status. Ideal for apps needing automated music creation — background tracks, jingles, or full songs with vocals. > **NOTE** > > **Prerequisite:** To ensure a successful request, you must first consult the [Model Selection](/docs/v1/api/utilities/model-selection) endpoint to identify a valid model `slug` and check specific **limits**. > **WARNING** > > **Reference audio requirements (optional):** > > * Supported formats: MP3, WAV, FLAC, OGG, M4A > * Maximum file size: 10 MB > * Duration must be within model-specific limits > > This endpoint uses `multipart/form-data` content type to support file uploads. OpenAPI [#openapi] # Text-to-Speech Price Calculation (/docs/v1/api/generation/text-to-speech-price) > Endpoint for calculating price for text2audio inference. Either text or count\_text must be provided. OpenAPI [#openapi] # Text-to-Speech (TTS) (/docs/v1/api/generation/text-to-speech) > Endpoint for requesting text2audio inference Text-to-Speech converts text into natural-sounding audio. The endpoint supports three TTS modes via the `mode` parameter: * **`custom_voice`** (default) — Use a preset voice from the model's voice library. Requires the `voice` parameter. * **`voice_clone`** — Clone a voice from a short reference audio clip. Requires the `ref_audio` parameter (3–10 seconds, max 10 MB). Optionally provide `ref_text` with a transcript of the reference audio for improved accuracy. * **`voice_design`** — Create a new voice from a natural language description. Requires the `instruct` parameter (e.g. `"A warm female voice with a British accent"`). > **NOTE** > > **Prerequisite:** To ensure a successful request, you must first consult the [Model Selection](/docs/v1/api/utilities/model-selection) endpoint to identify a valid model `slug`, check specific **limits** and **features**, and verify available **languages** and **voices**. > **WARNING** > > **Mode-specific required fields:** > > * `custom_voice` — `voice` is required. > * `voice_clone` — `ref_audio` is required. `ref_text` is optional but recommended. > * `voice_design` — `instruct` is required. > > If `mode` is omitted, the API defaults to `custom_voice`. OpenAPI [#openapi] # Text-to-Video Price Calculation (/docs/v1/api/generation/text-to-video-price) > Endpoint for calculating price for text2video inference OpenAPI [#openapi] # Text-to-Video (/docs/v1/api/generation/text-to-video) > Endpoint for requesting text2video inference > **NOTE** > > **Prerequisite:** To ensure a successful request, you must first consult the [Model Selection](/docs/v1/api/utilities/model-selection) endpoint to identify a valid model `slug`, check specific **limits** and **features**, and verify **LoRA** availability. OpenAPI [#openapi] # Image Prompt Booster Price (/docs/v1/api/prompt-enhancement/image-prompt-booster-price) > Calculate the cost of enhancing a text-to-image prompt before execution. OpenAPI [#openapi] # Image Prompt Booster (/docs/v1/api/prompt-enhancement/image-prompt-booster) > Enhance text-to-image prompts for better AI generation results. > **NOTE** > > **Tip:** Provide at least a basic concept or subject. The more context you give, the more targeted the enhancement will be. OpenAPI [#openapi] # Image-to-Image Prompt Booster Price (/docs/v1/api/prompt-enhancement/image-to-image-prompt-booster-price) > Calculate the cost of enhancing an image-to-image transformation prompt before execution. OpenAPI [#openapi] # Image-to-Image Prompt Booster (/docs/v1/api/prompt-enhancement/image-to-image-prompt-booster) > Enhance image-to-image transformation prompts with visual context awareness. Requires a reference image. > **NOTE** > > **Visual context required:** This endpoint requires a reference image. The enhancement is tailored specifically to work with your source image's content, style, and composition. OpenAPI [#openapi] # Prompt Enhancement (/docs/v1/api/prompt-enhancement/overview) > AI-powered prompt optimization tools that transform basic ideas into detailed, professional prompts for better generation results. Overview [#overview] Prompt Enhancement is a suite of AI-powered tools that optimize your prompts for better generation results. Whether you're creating images, videos, or speech, these endpoints analyze your input and return enhanced versions with improved detail, structure, and effectiveness. Available Boosters [#available-boosters] | Booster | Endpoint | Use Case | | --------------------------------------------------------------------------------------- | -------------------------- | ------------------------------ | | [Image Prompt Booster](/docs/v1/api/prompt-enhancement/image-prompt-booster) | `POST /prompt/image` | Text-to-image generation | | [Video Prompt Booster](/docs/v1/api/prompt-enhancement/video-prompt-booster) | `POST /prompt/video` | Text/image-to-video generation | | [Speech Prompt Booster](/docs/v1/api/prompt-enhancement/speech-prompt-booster) | `POST /prompt/speech` | Text-to-speech synthesis | | [Image-to-Image Booster](/docs/v1/api/prompt-enhancement/image-to-image-prompt-booster) | `POST /prompt/image2image` | Image transformation | | [Sample Prompts](/docs/v1/api/prompt-enhancement/sample-prompts) | `GET /prompts/samples` | Generate creative ideas | How It Works [#how-it-works] Send your basic prompt [#send-your-basic-prompt] Submit your simple idea or concept to the appropriate booster endpoint. AI enhancement [#ai-enhancement] Our AI analyzes your input and enriches it with relevant details, style keywords, and quality modifiers. Use enhanced prompt [#use-enhanced-prompt] Use the returned optimized prompt with any generation endpoint for improved results. Example: Image Prompt Enhancement [#example-image-prompt-enhancement] Request [#request] ```bash theme={null} curl -X POST https://api.dryapi.dev/api/v1/client/prompt/image \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "prompt": "a cat in space" }' ``` Response [#response] ```json theme={null} { "prompt": "A majestic cat floating gracefully in the depths of outer space, surrounded by glittering stars and distant galaxies, cosmic nebula colors reflecting in its curious eyes, cinematic lighting, ultra-detailed fur texture, 8K resolution, artstation trending", "negative_prompt": "blurry, low quality, distorted, deformed" } ``` Example: Video Prompt Enhancement [#example-video-prompt-enhancement] Request (with reference image) [#request-with-reference-image] ```bash theme={null} curl -X POST https://api.dryapi.dev/api/v1/client/prompt/video \ -H "Authorization: Bearer YOUR_API_KEY" \ -F "prompt=ocean waves at sunset" \ -F "image=@reference.jpg" ``` Response [#response-1] ```json theme={null} { "prompt": "Cinematic ocean waves crashing against rocky shores at golden hour, warm sunset colors reflecting on water surface, smooth camera pan following the wave motion, volumetric light rays through clouds, peaceful atmosphere, 4K quality, slow motion effect", "negative_prompt": "static, choppy, low resolution, artificial looking" } ``` Example: Sample Prompts Generator [#example-sample-prompts-generator] Request [#request-1] ```bash theme={null} curl -X GET "https://api.dryapi.dev/api/v1/client/prompts/samples?type=text2image&topic=cyberpunk" \ -H "Authorization: Bearer YOUR_API_KEY" ``` Response [#response-2] ```json theme={null} { "success": true, "data": { "type": "text2image", "prompt": "A neon-lit cyberpunk street market at midnight, holographic advertisements floating above crowded alleyways, rain-slicked pavement reflecting pink and blue lights, vendors selling exotic tech gadgets, steam rising from food stalls, ultra-detailed, cinematic composition" } } ``` Pricing [#pricing] Each booster has a corresponding price calculation endpoint. Costs are minimal compared to generation itself but can significantly improve output quality. > **TIP** > > Always check costs with the price calculation endpoints before processing large batches. This helps you estimate total expenses accurately. Best Practices [#best-practices] 1. **Provide context** — The more specific your input, the better the enhancement 2. **Use negative prompts** — Most boosters also optimize your negative prompt 3. **Include reference images** — For video and image-to-image boosters, reference images dramatically improve results 4. **Batch wisely** — Calculate prices first when processing multiple prompts # Sample Prompts Price (/docs/v1/api/prompt-enhancement/sample-prompts-price) > Calculate the cost of generating sample prompts before execution. OpenAPI [#openapi] # Sample Prompts Generator (/docs/v1/api/prompt-enhancement/sample-prompts) > Generate creative sample prompts for AI inference tasks. Perfect for inspiration, testing, or quick starting points. > **NOTE** > > **Supported types:** `text2image` and `text2speech`. Optionally provide a `topic` parameter to guide the generation toward a specific theme. OpenAPI [#openapi] # Speech Prompt Booster Price (/docs/v1/api/prompt-enhancement/speech-prompt-booster-price) > Calculate the cost of enhancing a text-to-speech prompt before execution. OpenAPI [#openapi] # Speech Prompt Booster (/docs/v1/api/prompt-enhancement/speech-prompt-booster) > Enhance text-to-speech input for more natural, expressive audio generation. > **NOTE** > > **Language support:** Specify the `lang_code` parameter to optimize the text for a specific language's pronunciation and phrasing patterns. OpenAPI [#openapi] # Video Prompt Booster Price (/docs/v1/api/prompt-enhancement/video-prompt-booster-price) > Calculate the cost of enhancing a video prompt before execution. OpenAPI [#openapi] # Video Prompt Booster (/docs/v1/api/prompt-enhancement/video-prompt-booster) > Enhance text-to-video or image-to-video prompts. Optionally include a reference image for context-aware enhancement. > **NOTE** > > **Multimodal support:** This endpoint accepts an optional reference image. When provided, the enhancement will be tailored to complement the visual content. OpenAPI [#openapi] # Image Background Removal Price Calculation (/docs/v1/api/transformation/background-removal-price) > Endpoint for calculating price for image background removal inference OpenAPI [#openapi] # Image Background Removal (/docs/v1/api/transformation/background-removal) > Endpoint for requesting image background removal inference > **NOTE** > > **Prerequisite:** To ensure a successful request, you must first consult the [Model Selection](/docs/v1/api/utilities/model-selection) endpoint to identify a valid model `slug`, check specific **limits** and **features**, and verify **LoRA** availability. OpenAPI [#openapi] # Image-to-Image Price Calculation (/docs/v1/api/transformation/image-to-image-price) > Endpoint for calculating price for img2img inference OpenAPI [#openapi] # Image-to-Image (/docs/v1/api/transformation/image-to-image) > Endpoint for requesting img2img inference. Accepts either a single image via "image" or multiple images via "images\[]" (mutually exclusive). > **NOTE** > > **Prerequisite:** To ensure a successful request, you must first consult the [Model Selection](/docs/v1/api/utilities/model-selection) endpoint to identify a valid model `slug`, check specific **limits** and **features**, and verify **LoRA** availability. Please **omit** the LoRA parameter by default during initial testing. OpenAPI [#openapi] # Image Upscale Price Calculation (/docs/v1/api/transformation/image-upscale-price) > Endpoint for calculating price for image upscaling inference OpenAPI [#openapi] # Image Upscale (/docs/v1/api/transformation/image-upscale) > Endpoint for requesting image upscaling inference > **NOTE** > > **Prerequisite:** To ensure a successful request, you must first consult the [Model Selection](/docs/v1/api/utilities/model-selection) endpoint to identify a valid model `slug` and check specific **limits**. OpenAPI [#openapi] # Check Balance (/docs/v1/api/utilities/check-balance) > Endpoint for requesting client current balance. OpenAPI [#openapi] # Get Results (/docs/v1/api/utilities/get-results) > Check job status and retrieve results via polling > **INFO** > > **Consider using webhooks or WebSockets instead of polling.** > > Polling requires repeated API calls and adds latency. For production applications, we recommend: > > * **[Webhooks](/docs/v1/execution-modes-and-integrations/webhooks)** — Results pushed to your server automatically (best for backends) > * **[WebSockets](/docs/v1/execution-modes-and-integrations/websockets)** — Real-time updates with live previews (best for interactive UIs) > > See [Execution Modes](/docs/v1/execution-modes-and-integrations/execution-modes-and-http-queue) for a full comparison. OpenAPI [#openapi] # Model Selection (/docs/v1/api/utilities/model-selection) > Endpoint for fetching all available models. OpenAPI [#openapi]