This document details the architecture and flow of API requests within the Dify platform. It covers key aspects such as API authentication mechanisms, user and tenant context tracking, different response modes (streaming vs blocking), enforcement of billing and feature quotas, and trace ID propagation for observability.
This leaf page complements other API-specific documentation:
Background on tenancy, authentication, and roles is described in 8.2 and 8.3 For overall system topology see 2.1
Dify exposes two primary API surfaces serving different purposes and authentication methods:
| API Type | Base Path | Purpose | Authentication | Typical Clients |
|---|---|---|---|---|
| Console API | /console/api | Internal management (apps, datasets, monitoring) | Session-based login (Passport) + CSRF | Web console UI |
| Service API | /api or /v1 | External application access (chat messages, completions, workflows) | API Key (Bearer Token) | External clients, SDKs, integrations |
| Inner API | /inner/api | Internal communication among Dify components | Shared secrets / payload validation | Plugin daemon, internal workers |
The Flask app factory (api/app_factory.py) registers separate Blueprints for these APIs:
console (for Console API)service_api (for Service API)inner_api (for internal communications)Each Blueprint organizes related Flask-RestX namespaces and resource routes, e.g., ChatApi, WorkflowRunApi, PluginReverseInvocationApi.
Sources:
Service API requests require API Key authentication using Authorization: Bearer <token> header. This is enforced via the validate_app_token decorator present on API handlers.
validate_app_token Decorator WorkflowValidates the API token using validate_and_get_api_token("app"), checking token existence and validity api/controllers/service_api/wraps.py105-170
Loads the corresponding App model verifying:
status == "normal"enable_api == TrueFetches/creates an EndUser model if fetch_user_arg is specified, extracting the user identifier from request (query, JSON, or form), then calling EndUserService.get_or_create_end_user(app_model, user_id) api/controllers/service_api/wraps.py126-143
Injects app_model and optionally end_user into controller method keyword arguments.
Updates Flask-Login’s current_user context to the identified end user or tenant owner account, enabling downstream permission and context resolution api/controllers/service_api/wraps.py146-166
Sources:
Dify APIs support two response modes controlled by the response_mode parameter in requests, affecting how clients receive LLM or workflow output.
| Mode | Behavior | Use Case |
|---|---|---|
| Blocking | Waits for full execution then returns JSON | Synchronous clients needing the complete response |
| Streaming (SSE) | Sends incremental Server-Sent Events payloads | Real-time rendering of chat or workflow progress |
Streaming responses use text/event-stream MIME type for SSE.
Event generation is coordinated by classes like AppQueueManager which listen for events such as agent_thought, message, workflow_finished.
Initial response headers propagate trace IDs to allow observability of streaming session api/app_factory.py101-118
Sources:
For observability and tracing, Dify integrates OpenTelemetry (OTEL) and enriches log context.
Request Initialization: before_request hook calls init_request_context() to:
request_idOpenTelemetry Setup: The ext_otel.py extension initializes a TracerProvider configured to propagate context and generate trace and span IDs api/extensions/ext_otel.py54-75
Logging Context Filters: Custom logging filters like TraceContextFilter and IdentityContextFilter augment logs with:
trace_id (OTEL Trace ID)span_id (OTEL Span ID)req_id (Request ID for internal correlation) api/extensions/ext_logging.py35-51Response Headers: An after_request handler injects the current trace ID into response headers as X-Trace-Id for client and downstream correlation api/app_factory.py101-118
Sources:
Dify's Cloud and Enterprise editions enforce usage quotas, license validation, and feature gating integrated into the API request flow.
On each request, a before_request hook validates license status when Enterprise mode is enabled. This uses cached license status from EnterpriseService.get_cached_license_status(). Unauthorized requests if license is expired or inactive cause forced logout api/app_factory.py68-96
Feature limits (apps, members, knowledge base vector space, upload quotas) are provided by FeatureService.get_features(), which gathers info from internal config and Billing APIs api/services/feature_service.py190-207
BillingService.quota_reserve(). This ensures that tenants cannot exceed their paid limits and enables quota commitment or release on request success/failure api/services/billing_service.py240-245cloud_edition_billing_resource_check inject quota and limit checks for specific resource types (e.g., vector space, document uploads) that preemptively block requests exceeding tenant limits api/controllers/console/wraps.py187-209Sources:
This page outlined the detailed API architecture of Dify, focusing on:
validate_app_tokenThe natural language conceptual model of clients and users was connected to specific code entities such as decorators, Flask Blueprints, and service classes, enabling new developers to locate key implementation points quickly.
End of 9.1 "API Architecture and Request Flow"
Sources:
Refresh this wiki
This wiki was recently refreshed. Please wait 6 days to refresh again.