पाठ 20 / 25

Calling a Workflow Through the API

App keys, inputs and outputs.

POST inputs, receive outputs

Each published app has an API with its own app API key. For a workflow app you send a POST request to the workflow run endpoint (/v1/workflows/run) with inputs matching the start node variables, a response_mode (blocking or streaming) and a user identifier; the blocking response includes the run id, status and outputs. Chat apps use a chat-messages endpoint with a conversation id. Call the API from your backend so the key is never exposed in browsers, handle errors and timeouts, and log the run id. Dify's node names, menus and options change between versions; check the current Dify documentation.

From editor to integration

Published apps are available as web apps and through an API you can call from any system.

Three ideas: blocking API calls, streaming, publishing.
Figure 7.1 — Blocking calls, streaming and publishing.

A client tested against a local mock server, run

I ran this with plain Python 3 (scikit-learn 1.9.1 where imported). It models or tests one piece of a Dify app locally; Dify itself was not running. A small client posts inputs to a local server that mimics the workflow-run response shape. With a key starting app- it gets the outputs; with a wrong key it receives HTTP 401. This tests the client code only; check the real request and response fields in Dify's API reference for your version.

import json, threading
from http.server import BaseHTTPRequestHandler, HTTPServer
from urllib.request import Request, urlopen

class MockDify(BaseHTTPRequestHandler):      # stands in for a Dify server, for local testing only
    def do_POST(self):
        body = json.loads(self.rfile.read(int(self.headers["Content-Length"])))
        ok = self.headers.get("Authorization", "").startswith("Bearer app-")
        reply = {"workflow_run_id": "run-1", "data": {"status": "succeeded",
                 "outputs": {"answer": f"Echo: {body['inputs']['query']}"}}} if ok else {"code": "unauthorized"}
        self.send_response(200 if ok else 401); self.send_header("Content-Type", "application/json"); self.end_headers()
        self.wfile.write(json.dumps(reply).encode())
    def log_message(self, *a): pass

server = HTTPServer(("127.0.0.1", 0), MockDify); threading.Thread(target=server.serve_forever, daemon=True).start()
BASE = f"http://127.0.0.1:{server.server_port}/v1"

def run_workflow(query, api_key):
    payload = {"inputs": {"query": query}, "response_mode": "blocking", "user": "user-123"}
    req = Request(f"{BASE}/workflows/run", data=json.dumps(payload).encode(), method="POST",
                  headers={"Authorization": f"Bearer {api_key}", "Content-Type": "application/json"})
    try:
        with urlopen(req, timeout=10) as r:
            return json.loads(r.read())["data"]["outputs"]
    except Exception as e:
        return f"error: {e}"
print(run_workflow("reset password", "app-demo-key"))
print(run_workflow("reset password", "wrong-key"))
server.shutdown()

Output:

{'answer': 'Echo: reset password'}
error: HTTP Error 401: Unauthorized

One key per integration

Create separate API keys per calling system so you can rotate or revoke one without breaking the others.

त्वरित जाँच: Where should the Dify app API key be used?

  • In a public JavaScript bundle
  • In your backend server, never in browser code
  • In the prompt text
  • In the end node output
Answer

In your backend server, never in browser code — Keys in browsers can be stolen.