> For the complete documentation index, see [llms.txt](https://docs.n8n.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.n8n.io/deploy/host-n8n/deploy-as-an-oem-integration/manage-workflows.md).

# Manage workflows

{% hint style="info" %}
**OEM agreement required**

OEM deployment of n8n requires a separate commercial agreement with n8n. [Contact n8n](mailto:license@n8n.io) for more information.
{% endhint %}

When managing an n8n OEM deployment spanning across teams or organizations, you will likely need to run the same (or similar) workflows for multiple users. There are two available options for doing so:

| Solution                                                              | Pros                                                               | Cons                                           |
| --------------------------------------------------------------------- | ------------------------------------------------------------------ | ---------------------------------------------- |
| Create a workflow for each user                                       | No limitation on how workflow starts (can use any trigger)         | Requires managing multiple workflows.          |
| Create a single workflow, and pass it user credentials when executing | Simplified workflow management (only need to change one workflow). | To run the workflow, your product must call it |

{% hint style="warning" %}
The APIs referenced in this document are subject to change at any time. Be sure to check for continued functionality with each version upgrade.
{% endhint %}

## Workflow per user <a href="#workflow-per-user" id="workflow-per-user"></a>

There are three general steps to follow:

* Obtain the credentials for each user, and any additional parameters that may be required based on the workflow.
* Create the [n8n credentials](#user-content-fn-1)[^1] for this user.
* Create the workflow.

### 1. Obtain user credentials <a href="#id-1-obtain-user-credentials" id="id-1-obtain-user-credentials"></a>

Here you need to capture all credentials for any node/service this user must authenticate with, along with any additional parameters required for the particular workflow. The credentials and any parameters needed will depend on your workflow and what you are trying to do.

### 2. Create user credentials <a href="#id-2-create-user-credentials" id="id-2-create-user-credentials"></a>

After all relevant credential details have been obtained, you can proceed to create the relevant service credentials in n8n. This can be done using the Editor UI or API call.

#### Using the Editor UI <a href="#using-the-editor-ui" id="using-the-editor-ui"></a>

1. From the menu select **Credentials** > **New**.
2. Use the drop-down to select the **Credential type** to create, for example *Airtable*. ![Create New Credentials drop-down](/files/oG27AVE0mgf2uaKwe7J9)
3. In the **Create New Credentials** modal, enter the corresponding credentials details for the user, and select the nodes that will have access to these credentials. ![Create New Credentials modal](/files/crWBvdewy0kieOcBviwe)
4. Click **Create** to finish and save.

#### Using the API <a href="#using-the-api" id="using-the-api"></a>

The frontend API used by the Editor UI can also be called to achieve the same result. The API endpoint is in the format: `https://<n8n-domain>/rest/credentials`.

For example, to create the credentials in the Editor UI example above, the request would be:

```
POST https://<n8n-domain>/rest/credentials
```

With the request body:

```json
{
   "name":"MyAirtable",
   "type":"airtableApi",
   "nodesAccess":[
      {
         "nodeType":"n8n-nodes-base.airtable"
      }
   ],
   "data":{
      "apiKey":"q12we34r5t67yu"
   }
}
```

The response will contain the ID of the new credentials, which you will use when creating the workflow for this user:

```json
{
   "data":{
      "name":"MyAirtable",
      "type":"airtableApi",
      "data":{
         "apiKey":"q12we34r5t67yu"
      },
      "nodesAccess":[
         {
            "nodeType":"n8n-nodes-base.airtable",
            "date":"2021-09-10T07:41:27.770Z"
         }
      ],
      "id":"29",
      "createdAt":"2021-09-10T07:41:27.777Z",
      "updatedAt":"2021-09-10T07:41:27.777Z"
   }
}
```

### 3. Create the workflow <a href="#id-3-create-the-workflow" id="id-3-create-the-workflow"></a>

Best practice is to have a “base” workflow that you then duplicate and customize for each new user with their credentials (and any other details).

You can duplicate and customize your template workflow using either the Editor UI or API call.

#### Using the Editor UI <a href="#using-the-editor-ui" id="using-the-editor-ui"></a>

1. From the menu select **Workflows** > **Open** to open the template workflow to be duplicated.
2. Select **Workflows** > **Duplicate**, then enter a name for this new workflow and click **Save**. ![Duplicate workflow](/files/jAHmw68s7c71DHguEeXJ)
3. Update all relevant nodes to use the credentials for this user (created above).
4. **Save** this workflow and set it to **Active** using the toggle in the top-right corner.

#### Using the API <a href="#using-the-api" id="using-the-api"></a>

1. Fetch the JSON of the template workflow using the endpoint: `https://<n8n-domain>/rest/workflows/<workflow_id>`

```
GET https://<n8n-domain>/rest/workflows/1012
```

The response will contain the JSON data of the selected workflow:

```json
{
  "data": {
    "id": "1012",
    "name": "Nathan's Workflow",
    "active": false,
    "nodes": [
      {
        "parameters": {},
        "name": "Start",
        "type": "n8n-nodes-base.start",
        "typeVersion": 1,
        "position": [
          130,
          640
        ]
      },
      {
        "parameters": {
          "authentication": "headerAuth",
          "url": "https://internal.users.n8n.cloud/webhook/custom-erp",
          "options": {
            "splitIntoItems": true
          },
          "headerParametersUi": {
            "parameter": [
              {
                "name": "unique_id",
                "value": "recLhLYQbzNSFtHNq"
              }
            ]
          }
        },
        "name": "HTTP Request",
        "type": "n8n-nodes-base.httpRequest",
        "typeVersion": 1,
        "position": [
          430,
          300
        ],
        "credentials": {
          "httpHeaderAuth": "beginner_course"
        }
      },
      {
        "parameters": {
          "operation": "append",
          "application": "appKBGQfbm6NfW6bv",
          "table": "processingOrders",
          "options": {}
        },
        "name": "Airtable",
        "type": "n8n-nodes-base.airtable",
        "typeVersion": 1,
        "position": [
          990,
          210
        ],
        "credentials": {
          "airtableApi": "Airtable"
        }
      },
      {
        "parameters": {
          "conditions": {
            "string": [
              {
                "value1": "={{$json[\"orderStatus\"]}}",
                "value2": "processing"
              }
            ]
          }
        },
        "name": "IF",
        "type": "n8n-nodes-base.if",
        "typeVersion": 1,
        "position": [
          630,
          300
        ]
      },
      {
        "parameters": {
          "keepOnlySet": true,
          "values": {
            "number": [
              {
                "name": "=orderId",
                "value": "={{$json[\"orderID\"]}}"
              }
            ],
            "string": [
              {
                "name": "employeeName",
                "value": "={{$json[\"employeeName\"]}}"
              }
            ]
          },
          "options": {}
        },
        "name": "Set",
        "type": "n8n-nodes-base.set",
        "typeVersion": 1,
        "position": [
          800,
          210
        ]
      },
      {
        "parameters": {
          "functionCode": "let totalBooked = items.length;\nlet bookedSum = 0;\n\nfor(let i=0; i < items.length; i++) {\n  bookedSum = bookedSum + items[i].json.orderPrice;\n}\nreturn [{json:{totalBooked, bookedSum}}]\n"
        },
        "name": "Function",
        "type": "n8n-nodes-base.function",
        "typeVersion": 1,
        "position": [
          800,
          400
        ]
      },
      {
        "parameters": {
          "webhookUri": "https://discord.com/api/webhooks/865213348202151968/oD5_WPDQwtr22Vjd_82QP3-_4b_lGhAeM7RynQ8Js5DzyXrQEnj0zeAQIA6fki1JLtXE",
          "text": "=This week we have {{$json[\"totalBooked\"]}} booked orders with a total value of {{$json[\"bookedSum\"]}}. My Unique ID: {{ $(\"HTTP Request\").params.headerParameters.parameters[0].value }}"
        },
        "name": "Discord",
        "type": "n8n-nodes-base.discord",
        "typeVersion": 1,
        "position": [
          1000,
          400
        ]
      },
      {
        "parameters": {
          "triggerTimes": {
            "item": [
              {
                "mode": "everyWeek",
                "hour": 9
              }
            ]
          }
        },
        "name": "Cron",
        "type": "n8n-nodes-base.cron",
        "typeVersion": 1,
        "position": [
          220,
          300
        ]
      }
    ],
    "connections": {
      "HTTP Request": {
        "main": [
          [
            {
              "node": "IF",
              "type": "main",
              "index": 0
            }
          ]
        ]
      },
      "Start": {
        "main": [
          []
        ]
      },
      "IF": {
        "main": [
          [
            {
              "node": "Set",
              "type": "main",
              "index": 0
            }
          ],
          [
            {
              "node": "Function",
              "type": "main",
              "index": 0
            }
          ]
        ]
      },
      "Set": {
        "main": [
          [
            {
              "node": "Airtable",
              "type": "main",
              "index": 0
            }
          ]
        ]
      },
      "Function": {
        "main": [
          [
            {
              "node": "Discord",
              "type": "main",
              "index": 0
            }
          ]
        ]
      },
      "Cron": {
        "main": [
          [
            {
              "node": "HTTP Request",
              "type": "main",
              "index": 0
            }
          ]
        ]
      }
    },
    "createdAt": "2021-07-16T11:15:46.066Z",
    "updatedAt": "2021-07-16T12:05:44.045Z",
    "settings": {},
    "staticData": null,
    "tags": []
  }
}
```

1. Save the returned JSON data and update any relevant credentials and fields for the new user.
2. Create a new workflow using the updated JSON as the request body at endpoint: `https://<n8n-domain>/rest/workflows`

```
POST https://<n8n-domain>/rest/workflows/
```

The response will contain the ID of the new workflow, which you will use in the next step.

1. Lastly, publish the new workflow:

```
PATCH https://<n8n-domain>/rest/workflows/1012
```

Passing the additional value `active` in your JSON payload:

```json
// ...
"active":true,
"settings": {},
"staticData": null,
"tags": []
```

## Single workflow <a href="#single-workflow" id="single-workflow"></a>

There are four steps to follow to implement this method:

* Obtain the credentials for each user, and any additional parameters that may be required based on the workflow. See [Obtain user credentials](#1-obtain-user-credentials) above.
* Create the n8n credentials for this user. See [Create user credentials](#2-create-user-credentials) above.
* Create the workflow.
* Call the workflow as needed.

### Create the workflow <a href="#create-the-workflow" id="create-the-workflow"></a>

The details and scope of this workflow will vary greatly according to the individual use case, however there are a few design implementations to keep in mind:

* This workflow must be triggered by a [Webhook](/integrations/builtin/core-nodes/n8n-nodes-base.webhook.md) node.
* The incoming webhook call must contain the user’s credentials and any other workflow parameters required.
* Each node where the user’s credentials are needed should use an [expression](/build/work-with-data/expressions-versus-data-nodes.md) so that the node’s credential field reads the credential provided in the webhook call.
* Save and publish the workflow, ensuring the production URL is selected for the Webhook node. Refer to [webhook node](/integrations/builtin/core-nodes/n8n-nodes-base.webhook.md) for more information.

### Call the workflow <a href="#call-the-workflow" id="call-the-workflow"></a>

For each new user, or for any existing user as may be needed, call the webhook defined as the workflow trigger and provide the necessary credentials (and any other workflow parameters).

[^1]: In n8n, credentials store authentication information to connect with specific apps and services. After creating credentials with your authentication information (username and password, API key, OAuth secrets, etc.), you can use the associated app node to interact with the service.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.n8n.io/deploy/host-n8n/deploy-as-an-oem-integration/manage-workflows.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
