Extend Kestra with the API​Extend ​Kestra with the ​A​P​I

Extend Kestra by using the API.


Kestra is API-first, so it’s straightforward to connect external systems to your flows or call the platform directly. This guide focuses on the Kestra API itself and how you can extend or integrate Kestra from other services.

Using the API Reference

The docs include references for both the Open Source and Cloud & Enterprise APIs so you know exactly what endpoints are available. Opening the Open Source reference shows a structured layout that’s easy to scan:

api_reference

Making Requests with Authentication

If you have Basic Auth enabled or you’re using the Enterprise Edition, authenticate each request. With cURL you can pass credentials via -u username:password. The example below uses the defaults from the Kestra Docker Compose:

bash
curl -X POST -u '[email protected]:kestra' http://localhost:8080/api/v1/executions/company.team/hello_world

Enterprise users can generate API tokens and send them as Bearer headers:

bash
curl -X POST http://localhost:8080/api/v1/executions/company.team/hello_world \
-H "Authorization: Bearer YOUR_API_TOKEN"

The remaining examples assume authentication is disabled.

Create a Flow

To create a flow via API, open the Flows section and look for the /api/v1/main/flows POST endpoint. It expects a YAML payload containing the flow definition.

Our body of Content-Type application/x-yaml will look like the example below:

yaml
id: created_by_api
namespace: company.team

tasks:
  - id: hello
    type: io.kestra.plugin.core.log.Log
    message: Hello World! 🚀

Send the request with cURL:

bash
curl -X POST http://localhost:8080/api/v1/main/flows -H "Content-Type:application/x-yaml" -d "id: created_by_api
namespace: company.team

tasks:
  - id: hello
    type: io.kestra.plugin.core.log.Log
    message: Hello World! 🚀"

The response looks like this:

json
{
  "id": "created_by_api",
  "namespace": "company.team",
  "revision": 1,
  "disabled": false,
  "deleted": false,
  "tasks":
    [
      {
        "id": "hello",
        "type": "io.kestra.plugin.core.log.Log",
        "message": "Hello World! \uD83D\uDE80",
      },
    ],
  "source": "id: created_by_api\nnamespace: company.team\n\ntasks:\n  - id: hello\n    type: io.kestra.plugin.core.log.Log\n    message: Hello World! \uD83D\uDE80",
}

Execute a Flow

To execute a flow, provide the namespace and flow ID. The sample flow below (hello_world) lives in the company.team namespace and accepts a string input:

yaml
id: hello_world
namespace: company.team

inputs:
  - id: greeting
    type: STRING
    defaults: hey

tasks:
  - id: hello
    type: io.kestra.plugin.core.log.Log
    message: "{{ inputs.greeting }}"

Because the input has a default, we can call the POST endpoint /api/v1/main/executions/{namespace}/{id} without providing additional data:

bash
curl -X POST \
http://localhost:8080/api/v1/main/executions/company.team/hello_world

To override inputs, send them as form data with -F:

bash
curl -X POST \
http://localhost:8080/api/v1/main/executions/company.team/hello_world \
-F greeting="hey there"

The response includes execution metadata and a link to the UI:

json
{
    "id": "MYkTmLrI36s10iVXHwRbR",
    "namespace": "company.team",
    "flowId": "hello_world",
    "flowRevision": 10,
    "inputs": {
        "greeting": "hey"
    },
    "labels": [
        {
            "key": "system.correlationId",
            "value": "MYkTmLrI36s10iVXHwRbR"
        }
    ],
    "state": {
        "current": "CREATED",
        "histories": [
            {
                "state": "CREATED",
                "date": "2024-11-21T16:31:27.943162175Z"
            }
        ],
        "duration": 0.044177500,
        "startDate": "2024-11-21T16:31:27.943162175Z"
    },
    "originalId": "MYkTmLrI36s10iVXHwRbR",
    "deleted": false,
    "metadata": {
        "attemptNumber": 1,
        "originalCreatedDate": "2024-11-21T16:31:27.943194342Z"
    },
    "url": "http://localhost:8080//ui/executions/company.team/hello_world/MYkTmLrI36s10iVXHwRbR"
}

See the Executions documentation for additional examples.

Get Information from an Execution

The execution response returns the execution ID, which you can use to fetch additional details once the run completes. Using MYkTmLrI36s10iVXHwRbR from the earlier example, call the GET endpoint /api/v1/main/executions/{executionId}:

bash
curl -X GET http://localhost:8080/api/v1/main/executions/MYkTmLrI36s10iVXHwRbR

The response includes state transitions, durations, and outputs:

Response Body

Modify the flow to emit an output:

yaml
id: hello_world
namespace: company.team

tasks:
  - id: hello
    type: io.kestra.plugin.core.debug.Return
    format: "This is an output"

Fetching execution 59uQXHbkMy5YwHEDom72Xv now shows the output payload:

Response Body

Accessing the KV Store

Kestra’s KV Store keeps flows stateful. You can create, update, and delete entries via the API—either from code running inside a flow or from external systems.

Add a key/value pair with the PUT endpoint /api/v1/main/namespaces/{namespace}/kv/{key}. The example below writes "Hello, World" to my_key in the company.team namespace:

bash
curl -X PUT -H "Content-Type: application/json" http://localhost:8080/api/v1/main/namespaces/company.team/kv/my_key -d '"Hello, World"'

Verify in Kestra that the entry exists:

kv_api

Update the value by sending a different body, for example "This is a modified value":

bash
curl -X PUT -H "Content-Type: application/json" http://localhost:8080/api/v1/main/namespaces/company.team/kv/my_key -d '"This is a modified value"'

Kestra shows the key as updated:

modified_kv

Opening the entry reveals the new value.

modified_value_kv

Fetch the value with the GET endpoint /api/v1/main/namespaces/{namespace}/kv/{key}:

bash
curl -X GET http://localhost:8080/api/v1/main/namespaces/company.team/kv/my_key

The response contains the type and value:

json
{
    "type": "STRING",
    "value": "This is a modified value"
}

See the KV Store documentation for more operations.

Get and Upload Namespaces Files

Beyond flows, you can manage namespace files via the API.

Use the GET endpoint /api/v1/main/namespaces/{namespace}/files/directory to list files in a namespace:

files

For company.team:

bash
curl -X GET http://localhost:8080/api/v1/main/namespaces/company.team/files/directory

The response is an array of file metadata:

json
[
    {
        "type": "File",
        "size": 13,
        "fileName": "example.txt",
        "lastModifiedTime": 1731430406183,
        "creationTime": 1731430400773
    },
    {
        "type": "File",
        "size": 27,
        "fileName": "example.js",
        "lastModifiedTime": 1731415024668,
        "creationTime": 1730997234841
    },
    {
        "type": "File",
        "size": 19,
        "fileName": "example.sh",
        "lastModifiedTime": 1731415024667,
        "creationTime": 1730997234839
    },
    {
        "type": "File",
        "size": 171,
        "fileName": "example.ion",
        "lastModifiedTime": 1731430044778,
        "creationTime": 1731430012804
    },
    {
        "type": "File",
        "size": 21,
        "fileName": "example.py",
        "lastModifiedTime": 1731415024667,
        "creationTime": 1729781670534
    }
]

Use the GET endpoint /api/v1/main/namespaces/{namespace}/files to fetch file contents:

Example request for example.txt:

bash
curl -X GET 'http://localhost:8080/api/v1/main/namespaces/company.team/files?path=example.txt'

which returns:

text
Hello, World!

Upload files using the POST endpoint /api/v1/main/namespaces/{namespace}/files. The example below uploads api_example.py with the following content:

python
import requests

r = requests.get("https://kestra.io")
print({r.status_code})

Run:

bash
curl -X POST 'http://localhost:8080/api/v1/main/namespaces/company.team/files?path=api_example.py' -H "Content-Type:multipart/form-data" -F "fileContent=@api_example.py"

After the upload, the file appears in the Namespace editor:

upload_file

Was this page helpful?