---
schema_version: "1"
id: 55bc3e9757401bc95626a24aca29224d321b0a20b2e9737463303070d89e832b
title: Publishing Methods
collection: tableau
version: current
locale: en-us
portal_url: https://docs.salesforce.com/tableau/current/en-us/api/rest_api/REST/rest_api_ref_publishing.md
canonical_url: https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref_publishing.htm
source_site: help.tableau.com
content_type: documentation
content_hash: a378e8a7dd44ac0c5302434c8a4e241905c8a342ab377861ca55445ca676b118
description: "Using the publishing methods of the Tableau Server REST API you can:"
---
[Skip to main content](#main-content)

# Publishing Methods

Using the publishing methods of the Tableau Server REST API you can:

- Publish a small workbook, data source, or flow file to a site in a single call
- Publish a larger workbook, data source, or flow file to a site in multiple calls

This functionality relates to the UI elements and concepts described at: [Publishing Workbooks and Data Sources](https://help.tableau.com/current/pro/desktop/en-us/publish_overview.htm).

## Use Postman

Our Postman collection of requests enables you to construct, send, and examine HTTP requests to the Tableau Server or Tableau Cloud API without writing initial code. Postman is a free online app used by many developers for prototyping API calls, investigating issues, and generating request code in a variety of languages.

[Postman: Publishing](https://www.postman.com/salesforce-developers/salesforce-developers/folder/4yekwgx/publishing)

## Append to File Upload

Uploads a block of data and appends it to the data that is already uploaded.

Call this method after an upload has been initiated using [Initiate File Upload](#initiate_file_upload), as many times as needed to upload all the blocks and complete the file. (A file is limited to 10,000 blocks.) You can safely make multiple simultaneous calls to this method as long as you use the sequenceID parameter in the URI querystring. Doing so will upload the blocks in parallel and decrease the time needed to complete the file, provided there is enough available bandwidth.

When the final block of data has been uploaded, you call [Publish Data Source](#publish_data_source), [Publish Flow](#publish_flow), or [Publish Workbook](#publish_workbook) to commit the file.

For more information, see [Publishing Resources](https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_concepts_publish.htm).

#### URI

PUT /api/api-version/sites/site-id/fileUploads/upload-session-id?sequenceID=sequence-id

#### Parameter Values

<table class="api-parameters-table">
                                <colgroup>
                                    <col class="api-parameters-table-col-1-extra-wide">
                                    <col>
                                </colgroup>
                                <tbody>
                                    <tr>
                                        <td><span class="api-placeholder">api-version</span>
                                        </td>
                                        <td>The version of the API to use, such as <code><span class="mc-variable Variables.REST-API-Version variable">3.29</span></code>. For more information, see <a href="https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_concepts_versions.htm" class="xref">REST API and Resource Versions</a>.</td>
                                    </tr>
                                    <tr>
                                        <td><span class="api-placeholder">site-id</span>
                                        </td>
                                        <td>The ID of the site to upload the file to.</td>
                                    </tr>
                                    <tr>
                                        <td><span class="api-placeholder">upload-session-id</span>
                                        </td>
                                        <td>The ID of the upload session. You get this value when you start an upload session using <a href="#initiate_file_upload"><span class="api-command-ref">Initiate File Upload</span></a>.</td>
                                    </tr>
                                    <tr>
                                        <td>
                                            <p><span class="api-placeholder">sequence-id</span>
                                            </p>
                                        </td>
                                        <td>
                                            <p>(Optional) A long integer that you choose, indicative of the block's order in the complete sequence.</p>
                                            <p>After you append all the blocks and call the <a href="#publish_data_source">Publish Data Source</a>, <a href="#publish_flow">Publish Flow</a>, or
        <a href="#publish_workbook">Publish Workbook</a> method, the <strong class="api-command-ref">sequenceID</strong> is used to order the blocks, low <span class="api-command-ref">sequenceID</span> to high <span class="api-command-ref">sequenceID</span>, and the combined blocks are written as the file. Therefore, the <span class="api-command-ref">sequenceID</span> should be incremented for each block (though it doesn't have to incremented by 1).</p>
                                            <p>If you don't include <strong class="api-command-ref">sequenceID</strong> in the URI querystring, the uploaded blocks are processed in the order they arrive. Network conditions can cause blocks to arrive out of order, which could result in a corrupted file if <strong class="api-command-ref">sequenceID</strong> isn't used.</p>
                                            <p class="note">Note: The <span class="api-command-ref">sequenceID</span> parameter is available starting in API version 3.27 (Tableau Cloud December 2025 / Server 2025.3). If you're using API version 3.26 (Tableau Cloud June 2025 / Server 2025.1) or earlier, the file is assembled using each block's arrival time.</p>
                                        </td>
                                    </tr>
                                </tbody>
                            </table>

#### Request Body

The content of the file to be uploaded is included in a MIME multipart message. For more information, see [Publishing Resources](https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_concepts_publish.htm).

#### Permissions

Users who are not server administrators or site administrators can call this method only if they have publishing rights on the site.

#### Required scope for JWT authorization

Introduced in Tableau Cloud June 2022 (API 3.16) and Tableau Server 2022.3 (API 3.17).

```
tableau:file_uploads:create
```

For more information, see [Access scopes for UATs](https://help.tableau.com/current/api/cloud-manager/en-us/docs/unified_access_tokens.html#scopes) (Cloud) and access scopes for connected apps: [Cloud](https://help.tableau.com/current/online/en-us/connected_apps_scopes.htm), [Server-Windows](https://help.tableau.com/current/server/en-us/connected_apps_scopes.htm), or [Server-Linux](https://help.tableau.com/current/server-linux/en-us/connected_apps_scopes.htm).

#### Response Code

200

#### Response Body

```
<tsResponse>
  <fileUpload uploadSessionId=upload-session-id
              fileSize=size-of-file-in-megabytes-after-append />
</tsResponse>
```

#### Version

Version 2.0 and later. For more information, see [REST API and Resource Versions](https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_concepts_versions.htm).

#### Errors

<table class="api-error-table"><colgroup><col class="api-error-table-col-1"> <col class="api-error-table-col-2"> <col class="api-error-table-col-3"> <col></colgroup><tbody><tr><th>HTTP status</th><th><code>error</code> Code</th><th>Condition</th><th>Details</th></tr><tr><td>400</td><td>400000</td><td>Bad request</td><td>The content of the request body is missing or incomplete, or contains malformed XML.</td></tr><tr><td>400</td><td>400016</td><td>File size too large</td><td>The attached file exceeds the configured maximum attachment size for a single append call. The maximum allowable size will be reported in the error response.</td></tr><tr><td>400</td><td>400019</td><td>Malformed request body</td><td>The XML content in the MIME multipart request is not empty.</td></tr><tr><td>400</td><td>400020</td><td>Missing file data</td><td>There is no attachment in the request with the file data to be appended to the upload.</td></tr><tr><td>403</td><td>403007</td><td>Not a publisher</td><td>A non-administrator user attempted to initiate a file upload, but the caller doesn't have publishing rights on the site.</td></tr><tr><td>403</td><td>403016</td><td>Upload failure</td><td>The file could not be uploaded for some other reason than those specified earlier.</td></tr><tr><td>404</td><td>404000</td><td>Site not found</td><td>The site ID in the URI doesn't correspond to an existing site.</td></tr><tr><td>404</td><td>404015</td><td>File upload not found</td><td>The file upload ID in the URI doesn't correspond to an existing file upload.</td></tr><tr><td>405</td><td>405000</td><td>Invalid request method</td><td>Request type was not <span class="api-command-ref">PUT</span>.</td></tr></tbody></table>

For more information, see [Handling Errors](https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_concepts_errors.htm).

## Initiate File Upload

Initiates the upload process for a file. After the upload has been initiated, you call [Append to File Upload](#append_to_file_upload) to send individual blocks of the file to the server. When the complete file has been sent to the server, you call [Publish Data Source](#publish_data_source), [Publish Flow](#publish_flow), or [Publish Workbook](#publish_workbook) to commit the upload.

Initiate File Upload returns an upload session ID that you pass to [Append to File Upload](#append_to_file_upload) or one of the publishing methods in order to identify the upload session.

The file size that is returned in the response is initialized to zero (0) megabytes, because no data has yet been loaded. Subsequent calls to [Append to File Upload](#append_to_file_upload) or the publishing APIs update this value.

For more information, see [Publishing Resources](https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_concepts_publish.htm).

#### URI

POST /api/api-version/sites/site-id/fileUploads

#### Parameter Values

<table class="api-parameters-table"><colgroup><col class="api-parameters-table-col-1"> <col></colgroup><tbody><tr><td><span class="api-placeholder">api-version</span></td><td>The version of the API to use, such as <code><span class="mc-variable Variables.REST-API-Version variable">3.29</span></code>. For more information, see <a href="https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_concepts_versions.htm" class="xref">REST API and Resource Versions</a>.</td></tr><tr><td><span class="api-placeholder">site-id</span></td><td>The ID of the site to upload the file to.</td></tr></tbody></table>

#### Request Body

None

#### Permissions

Users who are not server administrators or site administrators can initiate a file upload only if they have publishing rights on the site.

#### Required scope for JWT authorization

Introduced in Tableau Cloud June 2022 (API 3.16) and Tableau Server 2022.3 (API 3.17).

```
tableau:file_uploads:create
```

For more information, see [Access scopes for UATs](https://help.tableau.com/current/api/cloud-manager/en-us/docs/unified_access_tokens.html#scopes) (Cloud) and access scopes for connected apps: [Cloud](https://help.tableau.com/current/online/en-us/connected_apps_scopes.htm), [Server-Windows](https://help.tableau.com/current/server/en-us/connected_apps_scopes.htm), or [Server-Linux](https://help.tableau.com/current/server-linux/en-us/connected_apps_scopes.htm).

#### Response Code

201

#### Response Body

```
<tsResponse>
  <fileUpload uploadSessionId=new-upload-session-id
     fileSize=0 />
</tsResponse>
```

#### Version

Version 2.0 and later. For more information, see [REST API and Resource Versions](https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_concepts_versions.htm).

#### Errors

<table class="api-error-table"><colgroup><col class="api-error-table-col-1"> <col class="api-error-table-col-2"> <col class="api-error-table-col-3"> <col></colgroup><tbody><tr><th>HTTP status</th><th><code>error</code> Code</th><th>Condition</th><th>Details</th></tr><tr><td>400</td><td>400000</td><td>Bad request</td><td>The content of the request body is missing or incomplete, or contains malformed XML.</td></tr><tr><td>403</td><td>403015</td><td>Access to Favorites forbidden</td><td>A non-administrator user attempted to initiate a file upload, but the caller doesn't have publishing rights on the site.</td></tr><tr><td>404</td><td>404000</td><td>Site not found</td><td>The site ID in the URI doesn't correspond to an existing site.</td></tr><tr><td>405</td><td>405000</td><td>Invalid request method</td><td>Request type was not <span class="api-command-ref">POST</span>.</td></tr></tbody></table>

For more information, see [Handling Errors](https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_concepts_errors.htm).

## Publish Data Source

Publishes a data source on the specified site, or appends data to an existing data source.

To make other changes to a published data source, call [Update Data Source](https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref_data_sources.htm#update_data_source) or [Update Data Source Connection](https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref_data_sources.htm#update_data_source_connection).

**Version**: Available in API 2.0 and later.

**License**: Available for Tableau Server and Tableau Cloud.

**Permissions**: You can publish a data source if you have implicit or explicit Publish permissions for the data source, or are a Tableau administrator.

Note: The `queryTaggingEnabled` attribute is returned only for administrator users.

**Access Scope**: `tableau:datasources:create`

For more information, see [Versions](https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_concepts_versions.htm), [Permissions](https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_concepts_permissions.htm), [Access scopes for UATs](https://help.tableau.com/current/api/cloud-manager/en-us/docs/unified_access_tokens.html#scopes) (Cloud), and access scopes for [Cloud](https://help.tableau.com/current/online/en-us/connected_apps_scopes.htm), [Server-Windows,](https://help.tableau.com/current/server/en-us/connected_apps_scopes.htm) or [Server-Linux](https://help.tableau.com/current/server-linux/en-us/connected_apps_scopes.htm).

This method is used in two ways. You can call it to publish a data source in a single request. To do that, you include the content of the data source file in the body of the request. The maximum size of a file that can be published in a single request is 64 MB. If you want to avoid having the publishing process time out, you can use the _asJob_ parameter to make data source publication asynchronous.

Alternatively, you can publish a data source in multiple parts. To do that, you initiate a file upload by calling [Initiate File Upload](#initiate_file_upload), send portions of the file to the server using [Append to File Upload](#append_to_file_upload), and then commit the upload by calling Publish Data Source. In this case, Publish Data Source doesn't contain the file to publish.

**Extracts with multiple table options**  
Starting in v2021.4, you can publish multi table Hyper extract files created using the [Hyper API](https://help.tableau.com/current/api/hyper_api/en-us/docs/hyper_api_create_update.html). The data must include a single [fact table](https://en.wikipedia.org/wiki/Fact_table) containing the foreign keys that relate the tables to each other. The Hyper API infers the data object model, but does not perform any validation, such as referential integrity checking. If the Hyper API can’t infer the data object model of a Hyper extract, for instance, because there is more than one fact table, then attempting to publish the extract will fail. Prior to v2021.4, there was no way to append data to an extract with multiple tables using the REST API.

**Data Sources stored locally**  
When you publish a data source from your local computer to the server, you must make sure that the server has all the components that are required in order for other users to see and interact with the data source. For example, if the data source is based on an Excel spreadsheet, you typically publish a packaged data source (`.tdsx` file) that contains all the components for that data source.

**Replace data source**  
Starting in version 2025.1, you can use the replace parameter. You can include `overwrite`, `append`, and `replace` in a single request, but only one of these parameters can be set to true. If more than one is set to true, the request returns an HTTP 400 error.

**Working with Parquet files**  
\- When publishing a Parquet file to a data source through a live-to-Hyper connection, the files are converted to Hyper files. You may want to publish a copy of your original Parquet file to retain that data in its native format.  
\- A data source with a live-to-Hyper connection to data in a Hyper file converted from Parquet can only have a single connection.  
\- When incrementally updating that data from that connection, using the Update Hyper in Data Source method, the Parquet file is not converted to Hyper.

**Composed data sources and extended data sources**  
Starting in REST API version 3.29 (Cloud 262 and Server 2026.2), you can publish composed and extended data sources.  
  
When you publish a composed data source, you must include a `parentDataSourceUrls` element in addition to the `.tds` file so the composed data source is correctly linked to its parents. Include one entry for every published data source that is a direct parent of the composed data source. These correspond to the `datasource-url` tags serialized in the `.tds` file's data source tree. Include only the immediate parent data sources that the data source you are publishing depends on.  
  
When you publish an extended data source, include the `.tds` file as usual; no `parentDataSourceUrls` element is required.

For more information, see [Publishing Resources](https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_concepts_publish.htm).

#### URI

POST /api/api-version/sites/site-luid/datasources

POST /api/api-version/sites/site-luid/datasources?overwrite=overwrite-flag&asJob=asJob-value

POST /api/api-version/sites/site-luid/datasources?append=append-flag

POST /api/api-version/sites/site-luid/datasources?uploadSessionId=upload-session-id&datasourceType=datasource-file-type&overwrite=overwrite-flag&append=append-flag&replace=replace-flag

#### URI Parameter Values

<table class="api-parameters-table">
                        <colgroup>
                            <col class="api-parameters-table-col-1-wide">
                            <col>
                        </colgroup>
                        <tbody>
                            <tr>
                                <td><span class="api-placeholder">api-version</span>
                                </td>
                                <td>The version of the API to use, such as <code><span class="mc-variable Variables.REST-API-Version variable">3.29</span></code>. For more information, see <a href="https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_concepts_versions.htm" class="xref">REST API and Resource Versions</a>.</td>
                            </tr>
                            <tr>
                                <td><span class="api-placeholder">site-luid</span>
                                </td>
                                <td>The LUID of the site to publish to.</td>
                            </tr>
                            <tr>
                                <td><span class="api-placeholder">overwrite-flag</span>
                                </td>
                                <td><span class="api-command-ref">true</span> to overwrite a data source that has the same name, or <span class="api-command-ref">false</span>
                                        to fail if the specified data source already exists. The default is <span class="api-command-ref">false</span>. If <span class="api-placeholder">overwrite-flag</span>
                                        is set to <span class="api-command-ref">true</span> but the data source doesn't already exist, the operation succeeds.
                                        <p>You can include both the  <span class="api-command-ref">overwrite</span> and <span class="api-command-ref">append</span> parameters in a request, but they cannot both be <span class="api-command-ref">true.</span></p></td>
                            </tr>
                            <tr>
                                <td><span class="api-placeholder">replace-flag</span>
                                </td>
                                <td>(New in 2025.1) A boolean value (<strong>true </strong>or <strong>false</strong>). Set to <strong>true </strong>to replace the data in an existing data source. The default is <strong>false</strong>.</td>
                            </tr>
                            <tr>
                                <td><span class="api-placeholder">asJob-value</span>
                                </td>
                                <td>A Boolean value that is used to publish data sources asynchronously. If you set this value to <i>false</i> (the default), the publishing process runs as a synchronous process. If a data source is very large, the process might time out before it finishes. If you set this value to <i>true</i>, the process runs asynchronously, and a job will start to perform the publishing process and return the job ID. You can check the status of the import job by calling <a href="https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref_jobs_tasks_and_schedules.htm#query_job">Query Job</a>.
									</td>
                            </tr>
                            <tr>
                                <td><span class="api-placeholder">append-flag</span>
                                </td>
                                <td><span class="api-command-ref">true</span> to append the data being published to an existing data source that has the same name. The default
                                        is <span class="api-command-ref">false</span>. If <span class="api-placeholder">append-flag</span>
                                        is set to <span class="api-command-ref">true</span> but the data source doesn't already exist, the operation fails.
                                <p>
									In order to append data to a published data source on Tableau Server, both the source file and the published file must be
									an extract with the file extension <code>.hyper</code> or <code>.tde</code>. The schema of the source and the published extract must match.
								</p><p>If an extract was stored using the multiple tables option, you can't append data to it.</p><p>You can include both the  <span class="api-command-ref">overwrite</span> and <span class="api-command-ref">append</span> parameters in a request, but they cannot both be <span class="api-command-ref">true.</span></p></td>
                            </tr>
                            <tr>
                                <td><span class="api-placeholder">upload-session-luid</span>
                                </td>
                                <td>If you are calling this method to commit a file that was uploaded in parts, this value contains the upload session LUID that was generated by a call to
                                        <a href="#initiate_file_upload"><span class="api-command-ref">Initiate File Upload</span></a>. If this value is not included, the server assumes
                                        that the body of the request contains the file to be published.
                                    </td>
                            </tr>
                            <tr>
                                <td><span class="api-placeholder">datasource-file-type</span>
                                </td>
                                <td><span class="api-command-ref">hyper</span>, <span class="api-command-ref">tds</span>, <span class="api-command-ref">tdsx</span>, or <span class="api-command-ref">tde</span> the kind of file
                                        that you are uploading. This value is required if you are calling <span class="api-command-ref">Publish Data Source</span> in order to
                                        commit a file that was previously uploaded using <span class="api-command-ref">Append to File Upload</span>. The value is not used if you upload a file in the
                                        body of the request.
                                    </td>
                            </tr>
                        </tbody>
                    </table>

#### Request Body

The content type in the header of requests to publish a data source must use the mixed multipart content type with a boundary string definition, in the form of: `Content-Type: multipart/mixed; boundary=boundary-string`.

**Publishing a file in the request body**

```
--boundary-string
Content-Disposition: name="request_payload"
Content-Type: text/xml
<tsRequest>
	<datasource
	name="datasource-name"
	useRemoteQueryAgent="remote-query-agent-flag"
	description="datasource-description">
	<connectionCredentials
	name="connection-username"
	password="connection-password"
	embed="embed-flag"
	oAuth="oauth-flag" />
	<project
	id="project-id" />
	<parentDataSourceUrls>parent-datasource-url</parentDataSourceUrls>
	</datasource>
</tsRequest>
--boundary-string
Content-Disposition: name="tableau_datasource"; filename="SALES.TDSX"
Content-Type: application/octet-stream
content-of-datasource-file
--boundary-string--
```

**Committing a file previously uploaded**

```
--boundary-string
Content-Disposition: name="request_payload"
Content-Type: text/xml
<tsRequest>
	<datasource
	name="datasource-name" >
	<connectionCredentials
	name="connection-username"
	password="connection-password"
	embed="embed-flag"
	oAuth="oauth-flag" />
	<project
	id="project-id" />
	<parentDataSourceUrls>parent-datasource-url</parentDataSourceUrls>
	</datasource>
</tsRequest>
	--boundary-string--
```

**Publishing a file in the request body**

```
Content-Length: 16301
Content-Type: multipart/form-data; boundary=----------------------my_boundary_string
----------------------my_boundary_string
Content-Disposition: form-data; name="part1.json"
Content-Type: application/json
{
  "datasource": {
	"name": "datasource-name",
	"useRemoteQueryAgent": "remote-query-agent-flag",
	"description": "datasource-description",
	"connectionCredentials": {
	"name": "connection-username",
	"password": "connection-password",
	"embed": "embed-flag",
	"oAuth": "oauth-flag"
	},
  "project": {
	"id": "project-id"
	},
  "parentDataSourceUrls": [
  "parent-datasource-url"
   ]
   }
 }
 ----------------------my_boundary_string
Content-Disposition: form-data; name="datasource.tdsx"
Content-Type: application/octet-stream
content-of-datasource-file
----------------------my_boundary_string--
```

**Committing a file previously uploaded**

```
Content-Length: 16301
Content-Type: multipart/form-data; boundary=----------------------my_boundary_string
----------------------my_boundary_string
Content-Disposition: form-data; name="part1.json"
Content-Type: application/json
{
  "datasource": {
	"name": "datasource-name",
	"connectionCredentials": {
	"name": "connection-username",
	"password": "connection-password",
	"embed": "embed-flag",
	"oAuth": "oauth-flag"
	},
  "project": {
	"id": "project-id"
	},
  "parentDataSourceUrls": [
	"parent-datasource-url"
	]
  }
}
----------------------my_boundary_string--
```

#### Request Attributes

<table class="api-parameters-table">
                        <colgroup>
                            <col class="api-parameters-table-col-1-extra-wide">
                            <col>
                        </colgroup>
                        <tbody>
                            <tr>
                                <td><span class="api-placeholder">boundary-string</span>
                                </td>
                                <td>(Required) A string of characters that is guaranteed to be unique within the body of the request, and that is used to delimit sections of the request body. This value
                                        must be declared as a header that has this format:
                                        <p><code>Content-type: multipart/mixed; boundary=boundary-string</code></p></td>
                            </tr>
                            <tr>
                                <td><span class="api-placeholder">datasource-name</span>
                                </td>
                                <td>(Required) The name to assign to the data source when it is saved on the server.</td>
                            </tr>
                            <tr>
                                <td><span class="api-placeholder">remote-query-agent-flag</span>
                                </td>
                                <td>(Optional) When <code>true</code>, this flag will <a href="https://help.tableau.com/current/online/en-us/to_enable_bridge_live_connections.htm" target="_blank">allow your Tableau Cloud site to use Tableau Bridge clients</a>. Bridge allows you to maintain data sources with live connections to supported on-premises data sources.
							</td>
                            </tr>
                            <tr>
                                <td><span class="api-placeholder">datasource-description</span>
                                </td>
                                <td>(Optional) A description of the data source.</td>
                            </tr>
                            <tr>
                                <td><span class="api-placeholder">connection-username</span>
                                </td>
                                <td>(Optional) If the data source connection requires credentials, the <span class="api-command-ref">&lt;connectionCredentials&gt;</span> elements is included and this attribute specifies the connection username. If the element is included but is not required, the server ignores the element and its attributes.<p>If your auth type allows secrets to be passed as generic username and password variables, use this attribute for the appropriate secret, such as client id. (Example auth types include 2-legged OAuth, like Service Principal OAuth with Databricks and Client Credentials OAuth with Snowflake.)</p></td>
                            </tr>
                            <tr>
                                <td><span class="api-placeholder">connection-password</span>
                                </td>
                                <td>(Optional) If the data source connection requires credentials, the <span class="api-command-ref">&lt;connectionCredentials&gt;</span> elements is included and this attribute specifies the connection password. If the element is included but is not required, the server ignores the element and its attributes.<p>If your auth type allows secrets to be passed as generic username and password variables, use this attribute for the appropriate secret, such as client secret. (Example auth types include 2-legged OAuth, like Service Principal OAuth with Databricks and Client Credentials OAuth with Snowflake.)</p></td>
                            </tr>
                            <tr>
                                <td><span class="api-placeholder">embed-flag</span>
                                </td>
                                <td>(Optional) If the data source connection requires credentials, the <span class="api-command-ref">&lt;connectionCredentials&gt;</span> element is included. Setting this attribute to <span class="api-command-ref">true</span> instructs the server to save the credentials.</td>
                            </tr>
                            <tr>
                                <td><span class="api-placeholder">oauth-flag</span>
                                </td>
                                <td>(Optional) If the data source connection is configured to use OAuth, set this to <code class="api-command-ref">true</code> to specify
									that the value of the <span class="api-command-ref">name</span> attribute in the
									<span class="api-command-ref">connectionCredentials</span> element is an OAuth username. In that case, no password is
									required and the value of the <span class="api-command-ref">embed</span> attribute specifies whether to embed the OAuth
									credential with the data source.<p>If your auth type allows secrets to be passed as generic username and password variables, set the <span class="api-command-ref">oAuth</span> attribute to <code>false</code>. (Example auth types include 2-legged OAuth, like Service Principal OAuth with Databricks and Client Credentials OAuth with Snowflake.)</p><p>For more information on OAuth, see the OAuth Connections section of the <a href="https://help.tableau.com/current/online/en-us/protected_auth.htm" target="_blank">Tableau Cloud</a> or <a href="https://help.tableau.com/current/server/en-us/protected_auth.htm" target="_blank">Tableau Server</a> Product Help.</p></td>
                            </tr>
                            <tr>
                                <td><span class="api-placeholder">project-id</span>
                                </td>
                                <td>The LUID of the project to assign the data source to. If the project is not specified, the data source will be published to the default project.</td>
                            </tr>
                            <tr>
                                <td><span class="api-placeholder">datasource-file-name</span>
                                </td>
                                <td>The file name (including extension) of the data source file to upload. This attribute is used in the request body only if the
                                        request also includes the content of the data source file; it is not used if you are committing a file uploaded using
                                        previous requests.
                                    </td>
                            </tr>
                            <tr>
                                <td><span class="api-placeholder">	content-of-datasource-file</span>
                                </td>
                                <td>The content of the data source file, if the request includes the file. The maximum size of a file that can be uploaded in one call is 64&nbsp;MB.</td>
                            </tr>
                            <tr>
                                <td><span class="api-placeholder">askDataEnablement</span>
                                </td>
                                <td>
									This attribute is not available in API 3.12 and later (Tableau Cloud September 2021 / Server 2021.3).
								</td>
                            </tr>
                            <tr>
                                <td><span class="api-placeholder">parentDataSourceUrls</span>
                                </td>
                                <td>The name (URL) of the immediately referenced published data source that the data source being published depends on. For a composed data source, you must include one entry for each top-level parent data source in the data model.
</td>
                            </tr>
                        </tbody>
                    </table>

#### cURL Example

`curl "http://MY_SERVER/api/3.4/sites/ff2a8360-3c2b-4b05-a793-7607c602e1fb/datasources" -X POST -H "X-Tableau-Auth:6fSulU7ET8yjpHteQj56MQ|LrkEdTHcmPkWFcD8wOEy29hlVXm8iPo4" -H "Content-Type: multipart/mixed;" -F "request_payload=@publish-datasource.xml" -F "tableau_datasource=@data-source.tds"`

**Content of publish-datasource.xml**:

```
<tsRequest>
  <datasource name="datasource1" description="This is a data source named datasource1." >
    <project id="522dc5c5-e1da-47b9-8e07-f02929ff5ceb" />
  </datasource>
</tsRequest>
```

#### Response Code

201

#### Response Body

```
<tsResponse>
  <datasource
	id="75b71d2f-e8d3-42af-b654-d953659326ee"
	name="Sales"
	contentUrl="mySite"
	description="Sales Data Source"
	useRemoteQueryAgent="True"
	webpageUrl="https://my_server/#/datasources/222"
	type="excel-direct"
	createdAt="2016-02-12T23:36:09Z"
	updatedAt="2020-12-16T15:33:03Z"
	isCertified="False"
	certificationNote="This is a certification note."
	encryptExtracts="True">
	  <project
		id="56c86f04-b834-4a08-a561-86497bb4b2df"
		name="Visualization"/>
	  <owner id="20148c74-7818-4eb8-b2a1-9f3f5f582613"/>
	  <tags/>
  </datasource>
</tsResponse>
```

```
{
  "datasource": {
	"id": "75b71d2f-e8d3-42af-b654-d953659326ee",
	"name": "Sales",
	"contentUrl": "mySite",
	"description": "Sales Data Source",
	"useRemoteQueryAgent": "True",
	"webpageUrl": "https://my_server/#/datasources/222",
	"type": "excel-direct",
	"createdAt": "2016-02-12T23:36:09Z",
	"updatedAt": "2020-12-16T15:33:03Z",
	"isCertified": "False",
	"certificationNote": "This is a certification note.",
	"encryptExtracts": "True",
	"project": {
	  "id": "56c86f04-b834-4a08-a561-86497bb4b2df",
	  "name": "Visualization"
	},
	"owner": {
	  "id": "20148c74-7818-4eb8-b2a1-9f3f5f582613"
	},
	"tags": []
  }
}
```

The `createdAt` and `updatedAt` attribute values are returned in UTC format (YYYY-MM-DDTHH:MM:SSZ).

#### Response Headers

`Location: /api/3.29/sites/site-id/datasources/id-from-server`

#### Errors

<table class="api-error-table"><colgroup><col class="api-error-table-col-1"> <col class="api-error-table-col-2"> <col class="api-error-table-col-3"> <col></colgroup><tbody><tr><th>HTTP status</th><th><code>error</code> Code</th><th>Condition</th><th>Details</th></tr><tr><td>400</td><td>400000</td><td>Bad request</td><td>The request message is missing or incomplete, or contains malformed XML. Make sure that the <span class="api-command-ref">Content-Length</span> value is set.</td></tr><tr><td>400</td><td>400000</td><td>Missing data source</td><td>There is no attachment in the request for the data source.</td></tr><tr><td>400</td><td>400008</td><td>Invalid <span class="api-command-ref">overwrite</span> value</td><td>The <span class="api-command-ref">overwrite</span> parameter must be set to <span class="api-command-ref">true</span> or <span class="api-command-ref">false</span>.</td></tr><tr><td>400</td><td>400008</td><td>Invalid <span class="api-command-ref">append</span> value</td><td>The <span class="api-command-ref">append</span> parameter must be set to <span class="api-command-ref">true</span> or <span class="api-command-ref">false</span>.</td></tr><tr><td>400</td><td>400008</td><td>Invalid <span class="api-command-ref">embed</span> value</td><td>The request body contains a <span class="api-command-ref">&lt;connectionCredentials&gt;</span> element and it has an <span class="api-command-ref">embed</span>&nbsp;attribute whose value is not <span class="api-command-ref">true</span>&nbsp;or&nbsp;<span class="api-command-ref">false</span>.</td></tr><tr><td>400</td><td>400010</td><td>Invalid data source filename</td><td>The name of the data source file did not end with the suffix <code>.hyper</code>, <code>.tds</code>, <code>.tdsx</code>, or <code>.tde</code>.</td></tr><tr><td>400</td><td>400010</td><td>Missing or invalid file type</td><td>The request included an <span class="api-command-ref">uploadSessionId</span>&nbsp;parameter but no file type, or the file type was something other than <span class="api-command-ref">hyper</span>, <span class="api-command-ref">tds</span>, <span class="api-command-ref">tdsx</span>, or <span class="api-command-ref">tde</span>.</td></tr><tr><td>400</td><td>400010</td><td>Unexpected attachments</td><td>The message had both a <span class="api-placeholder">uploadSessionId</span> parameter and an attachment, or the message contained more than one attachment.</td></tr><tr><td>400</td><td>400011</td><td>Publishing error</td><td>The data source could not be published for some other reason than those specified earlier.</td></tr><tr><td>400</td><td>400011</td><td>Bad Request</td><td>The request is invalid. This can occur if more than one of the conflict resolution parameters (<strong>overwrite</strong>, <strong>append</strong>, or <strong>replace</strong>) is set to <code>true</code>. Only one of these parameters can be true in a single request.</td></tr><tr><td>400</td><td>400019</td><td>Malformed request body</td><td>The request message is missing or incomplete, or contains malformed XML. Make sure that the <span class="api-command-ref">Content-Length</span> value is set.</td></tr><tr><td>400</td><td>400055</td><td>Incompatible <span class="api-command-ref">overwrite</span> and <span class="api-command-ref">append</span> values</td><td>The <span class="api-command-ref">overwrite</span> and <span class="api-command-ref">append</span> parameter cannot both be set to <span class="api-command-ref">true</span>.</td></tr><tr><td>400</td><td>400129</td><td>Invalid Ask Data enablement</td><td>The enablement setting in the request body is not valid for the current server configuration.</td></tr><tr><td>403</td><td>403007</td><td>Insufficient publishing permission</td><td>A non-administrator user attempted to publish a data source, but the caller doesn't have sufficient project permissions.</td></tr><tr><td>403</td><td>403007</td><td>Unlicensed publishing forbidden</td><td>A non-administrator user who is unlicensed attempted to publish a data source. This is disallowed for all projects (including the default project).</td></tr><tr><td>403</td><td>403007</td><td>Overwrite forbidden</td><td>A data source with the specified name already exists and the <span class="api-command-ref">overwrite</span> parameter was not set to <span class="api-command-ref">true</span>.</td></tr><tr><td>403</td><td>403007</td><td>Problem connecting to data source</td><td>There was a problem connecting to a data source.&nbsp;This can be due to missing or invalid connection credentials or because the referenced data source is not available on the server.</td></tr><tr><td>403</td><td>403008</td><td>Insufficient storage quota</td><td>The data source could not be published because there is not enough storage remaining on the server to accommodate its size.</td></tr><tr><td>404</td><td>404000</td><td>Site not found</td><td>The site ID in the URI doesn't correspond to an existing site.</td></tr><tr><td>404</td><td>404004</td><td>Data source not found</td><td>The <span class="api-command-ref">append</span> parameter is <span class="api-command-ref">true</span> but the data source name specified in the request body does not correspond to an existing data source.</td></tr><tr><td>404</td><td>404005</td><td>Project not found</td><td>The project ID in the request body doesn't correspond to an existing project on the site.</td></tr><tr><td>404</td><td>404015</td><td>File upload not found</td><td>The file upload session ID in the request body doesn't correspond to an existing file upload on the site.</td></tr><tr><td>405</td><td>405000</td><td>Invalid request method</td><td>Request type was not <span class="api-command-ref">POST</span>.</td></tr></tbody></table>

For more information, see [Handling Errors](https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_concepts_errors.htm).

## Publish Flow

Publishes a flow on the specified site.

To make other changes to a published flow, call [Update Flow](https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref_flow.htm#update_flow) or [Update Flow Connection](https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref_flow.htm#update_flow_connection).

**Version**: Available in API 3.3 and later.

**License**: No additional license required.

**Permissions**: Users who are not server administrators or site administrators can publish a flow only if the flow belongs to a project that they have permissions to publish to, have a site role that allows publishing and have write permissions on the flow if overwriting.

**Access Scope**: `tableau:flows:create`

- Scope added in Tableau Cloud June 2022 (API 3.16) and Tableau Server 2022.3 (API 3.17).

For more information, see [Versions](https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_concepts_versions.htm), [Permissions](https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_concepts_permissions.htm), [Access scopes for UATs](https://help.tableau.com/current/api/cloud-manager/en-us/docs/unified_access_tokens.html#scopes) (Cloud), and access scopes for [Cloud](https://help.tableau.com/current/online/en-us/connected_apps_scopes.htm), [Server-Windows,](https://help.tableau.com/current/server/en-us/connected_apps_scopes.htm) or [Server-Linux](https://help.tableau.com/current/server-linux/en-us/connected_apps_scopes.htm).

You can publish a flow in a single request or in multiple parts.

To publish a flow in a single request you include the content of the workbook file in the body of the request. The maximum size of a file that can be published in a single request is 64 MB.

To publish a flow in multiple parts, you initiate a file upload by calling [Initiate File Upload](https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref.htm#initiate_file_upload), send portions of the file to the server using [Append to File Upload](https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref.htm#append_to_file_upload), and then commit the upload by calling Publish Flow. In this case, Publish Flow doesn't contain the file to publish but the `uploadSessionId` and the `flowType` parameters are required.

#### URI

POST /api/api-version/sites/site-id/flows

POST /api/api-version/sites/site-id/flows?overwrite=overwrite-flag

POST /api/api-version/sites/site-id/flows?overwrite=overwrite-flag&uploadSessionId=upload-session-id&flowType=flow-file-type

#### Parameter Values

<table class="api-parameters-table"><colgroup><col class="api-parameters-table-col-1-wide"> <col></colgroup><tbody><tr><td><span class="api-placeholder">api-version</span></td><td>The version of the API to use, such as <code><span class="mc-variable Variables.REST-API-Version variable">3.29</span></code>. For more information, see <a href="https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_concepts_versions.htm" class="xref">REST API and Resource Versions</a>.</td></tr><tr><td><span class="api-placeholder">site-id</span></td><td>The ID of the site to publish to.</td></tr><tr><td><span class="api-placeholder">overwrite-flag</span></td><td>(Optional) <span class="api-command-ref">true</span> to overwrite a flow that has the same name, or <span class="api-command-ref">false</span> to fail if the specified flow already exists. The default is <span class="api-command-ref">false</span>. If overwrite-flag is set to <span class="api-command-ref">true</span> but the flow doesn't already exist, the operation succeeds.</td></tr><tr><td><span class="api-placeholder">upload-session-id</span></td><td>If you are calling this method to commit a file that was uploaded in parts, this value contains the upload session ID that was generated by a call to Initiate File Upload. If this value is not included, the server assumes that the body of the request contains the file to be published.</td></tr><tr><td><span class="api-placeholder">flow-file-type</span></td><td><span class="api-command-ref">tfl</span> or <span class="api-command-ref">tflx</span> to indicate whether you have uploaded a flow file (tfl) or a packaged flow file (tflx). This value is only necessary and required if you upload a file in multiple parts. In the Publish Flow call after completing file upload, specify the file type.</td></tr></tbody></table>

#### Publishing a file in the Request Body

```
--boundary-string
Content-Disposition: name="request_payload"
Content-Type: text/xml
<tsRequest>
	<flow name="flow-name" >
		<project id="project-id" />
	</flow>
	<connections>
      <connection id="connection-id"
        serverAddress="server-address"
        serverPort="port-number">
          <connectionCredentials
            name="connection-username"
            password="connection-password"
            embed="embed-flag"
            oAuth="oauth-flag" />
		</connection>
	</connections>
</tsRequest>

--boundary-string
Content-Disposition: name="tableau_flow"; filename="flow-file-name"
Content-Type: application/octet-stream
content-of-flow-file
--boundary-string--
```

#### Attribute Values

<table class="api-parameters-table">
                        <colgroup>
                            <col class="api-parameters-table-col-1-wide">
                            <col>
                        </colgroup>
                        <tbody>
                            <tr>
                                <td><span class="api-placeholder">boundary-string</span>
                                </td>
                                <td>(Required) A string of characters that is guaranteed to be unique within the body of the request, and that is used to delimit sections of the request body. This value
                                        must be declared as a header that has this format:
                                        <p><code>Content-type: multipart/mixed; boundary=boundary-string</code></p></td>
                            </tr>
                            <tr>
                                <td><span class="api-placeholder">name</span>
                                </td>
                                <td>The name to assign to the flow when it is saved on the server.</td>
                            </tr>
                            <tr>
                                <td><span class="api-placeholder">description</span>
                                </td>
                                <td>The description of the flow.</td>
                            </tr>
                            <tr>
                                <td><span class="api-placeholder">server-address</span>
                                </td>
                                <td>Specify the server address for an input connections.</td>
                            </tr>
                            <tr>
                                <td><span class="api-placeholder">port-number</span>
                                </td>
                                <td>Specify the port number for input connections.</td>
                            </tr>
                            <tr>
                                <td><span class="api-placeholder">connection-username</span>
                                </td>
                                <td>(Optional) If the flow input connections require credentials, the &lt;connectionCredentials&gt; elements are included and this attribute specifies the connection username. If the element is included but is not required, the server ignores the element and its attributes.<p>If your auth type allows secrets to be passed as generic username and password variables, use this attribute for the appropriate secret, such as client id. (Example auth types include 2-legged OAuth, like Service Principal OAuth with Databricks and Client Credentials OAuth with Snowflake.)</p></td>
                            </tr>
                            <tr>
                                <td><span class="api-placeholder">connection-password</span>
                                </td>
                                <td>(Optional) If the flow input connections require credentials, the &lt;connectionCredentials&gt; elements are included and this attribute specifies the connection password. If the element is included but is not required, the server ignores the element and its attributes.<p>If your auth type allows secrets to be passed as generic username and password variables, use this attribute for the appropriate secret, such as client secret. (Example auth types include 2-legged OAuth, like Service Principal OAuth with Databricks and Client Credentials OAuth with Snowflake.)</p></td>
                            </tr>
                            <tr>
                                <td><span class="api-placeholder">embed-flag</span>
                                </td>
                                <td>(Optional) If the flow input connection requires credentials, the &lt;connectionCredentials&gt; element is included. Setting this attribute to <span class="api-command-ref">true</span> instructs the server to save the credentials. </td>
                            </tr>
                            <tr>
                                <td><span class="api-placeholder">oauth-flag</span>
                                </td>
                                <td>
                                    <p>(Optional) If the flow input connection is configured to use OAuth, set this to <code>true</code> to specify that the value of the name attribute in the <span class="api-command-ref">connectionCredentials</span> element is an OAuth username. In that case, no password is required and the value of the <span class="api-command-ref">embed</span> attribute specifies whether to embed the OAuth credential with the data source.</p>
                                    <p>If your auth type allows secrets to be passed as generic username and password variables, set the <span class="api-command-ref">oAuth</span> attribute to <code>false</code>. (Example auth types include 2-legged OAuth, like Service Principal OAuth with Databricks and Client Credentials OAuth with Snowflake.)</p>
                                    <p>For more information on OAuth, see the OAuth Connections section of the <a href="https://help.tableau.com/current/online/en-us/protected_auth.htm" target="_blank">Tableau Cloud</a> or <a href="https://help.tableau.com/current/server/en-us/protected_auth.htm" target="_blank">Tableau Server</a> Product Help.

                                    </p>
                                </td>
                            </tr>
                            <tr>
                                <td><span class="api-placeholder">project-id</span>
                                </td>
                                <td>The ID of the project to assign the flow to.</td>
                            </tr>
                            <tr>
                                <td><span class="api-placeholder">content-of-flow-file</span>
                                </td>
                                <td>The file itself if you are including it in the request body.</td>
                            </tr>
                        </tbody>
                    </table>

#### Response Code

201

#### Response Body

```
<tsResponse>
      <flow id="770a1cf8-6abe-4bc3-b0b8-59c4b15ce959"
            name="ShortTermRentalNola222"
            description=""
            webpageUrl="http://localhost/#/flows/3"
            fileType="tflx" createdAt="2018-11-20T19:28:58Z"
            updatedAt="2018-11-20T19:28:58Z">
           <project id="9077e04c-ece4-11e8-aa58-df538c72f42f"
            name="Default" />
           <owner id="5a39de9c-4eb0-47a7-88f7-2e78ddd58c6b" />
      </flow>
</tsResponse>
```

#### Errors

<table class="api-error-table"><colgroup><col class="api-error-table-col-1"> <col class="api-error-table-col-2"> <col class="api-error-table-col-3"> <col></colgroup><tbody><tr><th>HTTP status</th><th><code>error</code> Code</th><th>Condition</th><th>Details</th></tr><tr><td>400</td><td>400000</td><td>Malformed request body</td><td>The XML content in the MIME multipart request is not empty.</td></tr><tr><td>400</td><td>400089</td><td>Missing flow name</td><td>Flow name is required and was not specified.</td></tr><tr><td>403</td><td>403007</td><td>Invalid permissions</td><td>The caller does not have the necessary permissions to publish the flow.&nbsp;</td></tr><tr><td>400</td><td>400090</td><td>Missing flow payload</td><td>The flow information (the structure containing the flow description, flow project) was not included in the request body.</td></tr><tr><td>400</td><td>400086</td><td>Invalid flow attachment</td><td>The name of the flow doesn't end in .tfl or .tflx.</td></tr><tr><td>400</td><td>400087</td><td>Generic flow publishing error</td><td>The flow could not be published for some other reason than those specified earlier.</td></tr><tr><td>409</td><td>409041</td><td>Flow already found in destination</td><td>The flow name should be unique, or the overwrite flag parameter should be set to <span class="api-command-ref">true</span>.</td></tr><tr><td>403</td><td>403008</td><td>Insufficient storage quota</td><td>The flow could not be published because there is not enough storage remaining on the server to accommodate its size.</td></tr><tr><td>404</td><td>404000</td><td>Site not found</td><td>The site ID in the URI doesn't correspond to an existing site.</td></tr><tr><td>404</td><td>404005</td><td>Project not found</td><td>The project ID in the request body doesn't correspond to an existing project on the site.</td></tr><tr><td>404</td><td>404027</td><td>Flow not found</td><td>The flow ID in the URI doesn't correspond to an existing flow.</td></tr><tr><td>405</td><td>405000</td><td>Invalid request method</td><td>Request type was not <span class="api-command-ref">POST</span>.</td></tr></tbody></table>

For more information, see [Handling Errors](https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_concepts_errors.htm).

## Publish Virtual Connection

Publishes a virtual connection on the specified site, either from a packaged virtual connection file (`.tvcx`) or from a downloaded JSON representation.

If the virtual connection does not exist, it is published as a new virtual connection. If it already exists and you choose to overwrite it, the virtual connection is published as a revision of the existing virtual connection.

You can publish in either of these ways:

- **`.tvcx` file**. Send a packaged virtual connection file, as returned by [Download Virtual Connection](https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref_virtual_connections.htm#download_virtual_connection). A `.tvcx` file can include extracts.
- **JSON representation**. Send the virtual connection schema, as returned by [Download Virtual Connection as JSON](https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref_virtual_connections.htm#download_virtual_connection_as_json), inline in the request body.

**Version**: Available in API 3.23 (Tableau Cloud June 2024 / Tableau Server 2024.2) and later. Support for publishing a `.tvcx` file added in API 3.30.

**License**: Requires [Tableau Data Management](https://help.tableau.com/current/online/en-us/dm_overview.htm).

**Permissions**: You must have the Overwrite permission for the virtual connection and your site role must be at least Creator, or you must be a Tableau administrator.

**Access Scope**: `tableau:virtual_connections:create`. Scope added in API 3.27 (Tableau Cloud December 2025 / Server 2025.3).

For more information, see [Versions](https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_concepts_versions.htm), [Permissions](https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_concepts_permissions.htm), [Access scopes for UATs](https://help.tableau.com/current/api/cloud-manager/en-us/docs/unified_access_tokens.html#scopes) (Cloud), and access scopes for [Cloud](https://help.tableau.com/current/online/en-us/connected_apps_scopes.htm), [Server-Windows,](https://help.tableau.com/current/server/en-us/connected_apps_scopes.htm) or [Server-Linux](https://help.tableau.com/current/server-linux/en-us/connected_apps_scopes.htm).

To publish a `.tvcx` file, you can call this method in two ways. You can publish a virtual connection in a single request. To do that, you include the content of the `.tvcx` file in the body of the request. The maximum size of a file that can be published in a single request is about 64 MB.

Alternatively, you can publish a `.tvcx` file in multiple parts. To do that, you initiate a file upload by calling [Initiate File Upload](#initiate_file_upload), send portions of the file to the server using [Append to File Upload](#append_to_file_upload), and then commit the upload by calling Publish Virtual Connection. In this case, Publish Virtual Connection doesn't contain the file to publish. We recommend this approach for files larger than about 64 MB, such as files that include large extracts.

**Virtual connections with extracts**  
A `.tvcx` file for a virtual connection that uses extracts contains the Hyper extract files, in addition to the virtual connection schema. A `.tvcx` file for a live virtual connection contains only the schema. This method accepts both kinds of file.

**Draft or active**  
When you publish a JSON representation, the virtual connection can be published as a draft or as an active virtual connection, as set by the `publishAsDraft` parameter. A virtual connection that you publish from a `.tvcx` file is always published as an active virtual connection, whether or not the file includes extracts. The `publishAsDraft` parameter does not apply to a `.tvcx` file.

For more information, see [Publishing Resources](https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_concepts_publish.htm).

#### URI

POST /api/api-version/sites/site-id/virtualconnections

POST /api/api-version/sites/site-id/virtualconnections?publishAsDraft=publish-as-draft-flag

POST /api/api-version/sites/site-id/virtualconnections?overwrite=overwrite-flag

POST /api/api-version/sites/site-id/virtualconnections?uploadSessionId=upload-session-id&overwrite=overwrite-flag

#### URI Parameter Values

<table class="api-parameters-table">
                        <colgroup>
                            <col class="api-parameters-table-col-1-wide">
                            <col>
                        </colgroup>
                        <tbody>
                            <tr>
                                <td><span class="api-placeholder">api-version</span>
                                </td>
                                <td>The version of the API to use, such as <code><span class="mc-variable Variables.REST-API-Version variable">3.29</span></code>. For more information, see <a href="https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_concepts_versions.htm" class="xref">REST API and Resource Versions</a>.</td>
                            </tr>
                            <tr>
                                <td><span class="api-placeholder">site-id</span>
                                </td>
                                <td>The LUID of the site to publish to.</td>
                            </tr>
                            <tr>
                                <td><span class="api-placeholder">publish-as-draft-flag</span>
                                </td>
                                <td>(Optional) <span class="api-command-ref">true</span> to publish the virtual connection as a draft, or <span class="api-command-ref">false</span> to publish it as an active virtual connection. The default is <span class="api-command-ref">true</span>. This parameter applies only when you publish a JSON representation. The parameter is case sensitive.
                        <p>If the virtual connection contains an extract, the <span class="api-command-ref">publishAsDraft</span> parameter value is ignored and the virtual connection is published as a draft.</p><p class="note"><b>Note:</b> If you are using the REST&nbsp;API to publish a virtual connection as a draft, note the virtual connection's LUID (<code>virtualconnection id</code>) in the response body. Use that LUID to build a URL to further edit, create extracts for, or publish the virtual connection using the virtual connection editor in the regular web interface. For more information, see "Draft in Progress"&nbsp;in the <a href="https://help.tableau.com/current/online/en-us/dm_vconn_publish_save.htm#draft-in-progress" target="_blank">Tableau Cloud Product Help</a> and <a href="https://help.tableau.com/current/server/en-us/dm_vconn_publish_save.htm#draft-in-progress" target="_blank">Tableau Server Product Help</a>.</p></td>
                            </tr>
                            <tr>
                                <td><span class="api-placeholder">overwrite-flag</span>
                                </td>
                                <td><span class="api-command-ref">true</span> to overwrite a virtual connection that has the same name in the target project, or <span class="api-command-ref">false</span>
                                        to fail if the specified virtual connection already exists. The default is <span class="api-command-ref">false</span>. If <span class="api-placeholder">overwrite-flag</span>
                                        is set to <span class="api-command-ref">true</span> but the virtual connection doesn't already exist, the operation succeeds.
                    </td>
                            </tr>
                            <tr>
                                <td><span class="api-placeholder">upload-session-id</span>
                                </td>
                                <td>(Optional, <code>.tvcx</code> files only) If you are calling this method to commit a file that was uploaded in parts, this value contains the upload session ID that was generated by a call to
                                        <a href="#initiate_file_upload"><span class="api-command-ref">Initiate File Upload</span></a>. If this value is not included, the server assumes
                                        that the body of the request contains the file to be published.
                    </td>
                            </tr>
                        </tbody>
                    </table>

#### Request Body

The request body depends on whether you publish a `.tvcx` file or a JSON representation.

**Publishing a .tvcx file**

The content type in the header of requests to publish a `.tvcx` file must use the mixed multipart content type with a boundary string definition, in the form of: `Content-Type: multipart/mixed; boundary=boundary-string`. The server uses this content type to tell a `.tvcx` request from a JSON request. A request with any other content type, such as `application/octet-stream` or `multipart/form-data`, is handled as a request to publish a JSON representation and fails.

**Publishing a file in the request body**

```
--boundary-string
Content-Disposition: name="request_payload"
Content-Type: text/xml

<tsRequest>
  <virtualConnection name="virtualconnection-name">
    <project id="project-id" />
    <owner id="owner-id" />
  </virtualConnection>
</tsRequest>
--boundary-string
Content-Disposition: name="tableau_virtual_connection"; filename="virtualconnection-name.tvcx"
Content-Type: application/octet-stream

content-of-virtualconnection-file
--boundary-string--
```

**Committing a file previously uploaded**

```
--boundary-string
Content-Disposition: name="request_payload"
Content-Type: text/xml

<tsRequest>
  <virtualConnection name="virtualconnection-name">
    <project id="project-id" />
    <owner id="owner-id" />
  </virtualConnection>
</tsRequest>
--boundary-string--
```

**Publishing a JSON representation**

```
<tsRequest>
  <virtualConnection name="virtualconnection-name">
    <project id="project-id" />
    <owner id="owner-id" />
    <content>virtualconnection-as-json</content>
  </virtualConnection>
</tsRequest>
```

```
{
  "virtualConnection": {
    "project": {
      "id": "project-id"
    },
    "owner": {
      "id": "owner-id"
    },
    "content": "virtualconnection-as-json",
    "name": "virtualconnection-name"
  }
}
```

#### Request Attributes

**For a .tvcx file**

<table class="api-parameters-table">
                        <colgroup>
                            <col class="api-parameters-table-col-1-extra-wide">
                            <col>
                        </colgroup>
                        <tbody>
                            <tr>
                                <td><span class="api-placeholder">boundary-string</span>
                                </td>
                                <td>(Required) A string of characters that is guaranteed to be unique within the body of the request, and that is used to delimit sections of the request body. This value
                                        must be declared as a header that has this format:
                                        <p><code>Content-type: multipart/mixed; boundary=boundary-string</code></p></td>
                            </tr>
                            <tr>
                                <td><span class="api-placeholder">virtualconnection-name</span>
                                </td>
                                <td>(Required) The name to assign to the virtual connection when it is saved on the server. This is typically derived from the file name.</td>
                            </tr>
                            <tr>
                                <td><span class="api-placeholder">project-id</span>
                                </td>
                                <td>(Optional) The LUID of the project to publish to. If you omit it, the virtual connection is published to the default project.</td>
                            </tr>
                            <tr>
                                <td><span class="api-placeholder">owner-id</span>
                                </td>
                                <td>(Optional) The LUID of the owner of the virtual connection. If you omit it, the authenticated user becomes the owner.</td>
                            </tr>
                            <tr>
                                <td><code>tableau_virtual_connection</code> file part
                    </td>
                                <td>The <code>.tvcx</code> file. Include it when you publish in a single request. Omit it when you commit a file that was uploaded in parts. If you include both a file part and the <code>uploadSessionId</code> parameter, or if you include neither, the request fails.</td>
                            </tr>
                        </tbody>
                    </table>

**For a JSON representation**

<table class="api-parameters-table">
                        <colgroup>
                            <col class="api-parameters-table-col-1-extra-wide">
                            <col>
                        </colgroup>
                        <tbody>
                            <tr>
                                <td><span class="api-placeholder">virtualconnection-name</span>
                                </td>
                                <td>The name of the virtual connection you are publishing. If publishing an existing virtual connection as a revision, the virtual connection name is ignored.</td>
                            </tr>
                            <tr>
                                <td><span class="api-placeholder">project-id</span>
                                </td>
                                <td>The LUID of the project you are publishing to.</td>
                            </tr>
                            <tr>
                                <td><span class="api-placeholder">owner-id</span>
                                </td>
                                <td>This attribute is required, but is ignored.</td>
                            </tr>
                            <tr>
                                <td><span class="api-placeholder">virtualconnection-as-json</span>
                                </td>
                                <td>
                                    <p>The virtual connection schema rendered as JSON, as obtained using the <a href="https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref_virtual_connections.htm#download_virtual_connection_as_json">Download Virtual Connection as JSON</a> or <a href="https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref_virtual_connections.htm#download_virtual_connection_revision_as_json">Download Virtual Connection Revision as JSON</a> method. The schema appears in the <span class="uicontrol">content</span> element (for XML output) or <span class="uicontrol">content</span> property (for JSON output).</p>
                                    <p><strong>Note:</strong> Changing the downloaded schema and then using it with this method isn't supported.</p>
                                    <p>When using the Publish Virtual Connection method, we recommend using the virtual connection schema format that matches the format you used for downloading it. This is important because the virtual connection schema returned by the download methods has escape characters in it if the output was JSON. If you download and publish using different formats, you will have to make changes to the JSON representation of the virtual connection.</p>
                                    <p>In other words:</p>
                                    <ul>
                                        <li>If the output of the <a href="https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref_virtual_connections.htm#download_virtual_connection_as_json">Download Virtual Connection as JSON</a> method was XML (except for the <code>content</code> element, which is always a form of JSON), use XML when using this Publish Virtual Connection method.</li>
                                        <li>If the output of the <a href="https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref_virtual_connections.htm#download_virtual_connection_as_json">Download Virtual Connection as JSON</a> method was JSON (in which case it will have escape characters in the <code>content</code> property), use JSON when using this Publish Virtual Connection method.</li>
                                        <li>Alternatively, you can escape or unescape the schema yourself if you are downloading and publishing using different formats.</li>
                                    </ul>
                                    <p>For more information on the difference between using XML and using JSON with the REST&nbsp;API, see <a href="https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_concepts_fundamentals.htm#Using" class="xref">Fundamentals of the Tableau Server REST API</a>.</p>
                                </td>
                            </tr>
                        </tbody>
                    </table>

#### cURL Example

**Publishing a .tvcx file**

`curl "http://MY_SERVER/api/3.29/sites/9a8b7c6d-5e4f-3a2b-1c0d-9e8f7a6b5c4d/virtualconnections?overwrite=false" -X POST -H "X-Tableau-Auth: HvZMqFFfQQmOM4L-AZNIQA|5fI6T54OPK1Gn1p4w0RtHv6EkojWRTwq|a946d998-2ead-4894-bb50-1054a91dcab3" -H "Content-Type: multipart/mixed; boundary=----TabBoundary" --data-binary @publish-vconn-request.txt`

The file `publish-vconn-request.txt` contains the multipart request body shown above in **Publishing a file in the request body**.

**Publishing a JSON representation**

`curl --location 'http://MY_SERVER/api/3.29/sites/9a8b7c6d-5e4f-3a2b-1c0d-9e8f7a6b5c4d/virtualconnections?overwrite=true&publishAsDraft=false' --header 'Content-Type: application/xml' --header 'X-Tableau-Auth: HvZMqFFfQQmOM4L-AZNIQA|5fI6T54OPK1Gn1p4w0RtHv6EkojWRTwq|a946d998-2ead-4894-bb50-1054a91dcab3' --data @data.xml`

**Content of data.xml**:

```
<tsRequest>
  <virtualConnection name="Batters">
    <project id="1f2f3e4e-5d6d-7c8c-9b0b-1a2a3f4f5e6e"/>
    <owner id="9f9e9d9c-8b8a-8f8e-7d7c-7b7a6f6d6e6d"/>
    <content>virtualconnection-as-json</content>
  </virtualConnection>
</tsRequest>
```

Replace virtualconnection-as-json in this example with the virtual connection schema you downloaded using the [Download Virtual Connection as JSON](https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref_virtual_connections.htm#download_virtual_connection_as_json) method.

#### Response Code

201

#### Response Body

The response is the same whether you publish a JSON representation or a `.tvcx` file.

```
<tsResponse>
  <virtualConnection id="virtualconnection-id" name="virtualconnection-name">
    <project id="project-id" />
  </virtualConnection>
</tsResponse>
```

```
{
  "virtualConnection": {
    "project": {
      "id": "project-id"
    },
    "id": "virtualconnection-id",
    "name": "virtualconnection-name"
  }
}
```

#### Errors

<table class="api-error-table">
                        <colgroup>
                            <col class="api-error-table-col-1">
                            <col class="api-error-table-col-2">
                            <col class="api-error-table-col-3">
                            <col>
                        </colgroup>
                        <tbody>
                            <tr>
                                <th>HTTP status</th>
                                <th><code>error</code> Code</th>
                                <th>Condition</th>
                                <th>Details</th>
                            </tr>
                            <tr>
                                <td>400</td>
                                <td>400000</td>
                                <td>Bad request</td>
                                <td>
                                    <p>When you publish a .tvcx file, the request is not valid for one of these reasons:</p>
                                    <ul>
                                        <li>The request does not include <code>request_payload</code> or the <code>virtualConnection</code> element.</li>
                                        <li>The <code>virtualConnection</code> element does not include a <code>name</code>.</li>
                                        <li>The request includes both the .tvcx file and <code>uploadSessionId</code>, or it includes neither. Include only one.</li>
                                        <li>The file for the <code>uploadSessionId</code> is no longer available.</li>
                                        <li>The .tvcx file is not valid.</li>
                                        <li>The virtual connection could not be published with the extract in the .tvcx file.</li>
                                    </ul>
                                </td>
                            </tr>
                            <tr>
                                <td>400</td>
                                <td>400201</td>
                                <td>Publish virtual connection error</td>
                                <td>The virtual connection could not be published. This includes content that is not valid virtual connection JSON, or a .tvcx file or its contents that
					could not be read.</td>
                            </tr>
                            <tr>
                                <td>403</td>
                                <td>403008</td>
                                <td>Insufficient site storage</td>
                                <td>The content would exceed the site's storage quota. Applies when publishing a .tvcx file.</td>
                            </tr>
                            <tr>
                                <td>403</td>
                                <td>403175</td>
                                <td>Publish virtual connection forbidden</td>
                                <td>The user does not have permission to publish the virtual connection.</td>
                            </tr>
                            <tr>
                                <td>404</td>
                                <td>404015</td>
                                <td>File upload not found</td>
                                <td>The <code>uploadSessionId</code> does not match an upload owned by the user. Applies when publishing a .tvcx file.</td>
                            </tr>
                            <tr>
                                <td>404</td>
                                <td>404049</td>
                                <td>Virtual connection not found</td>
                                <td>The virtual connection could not be found while publishing it with the extract in the .tvcx file.</td>
                            </tr>
                            <tr>
                                <td>405</td>
                                <td>405000</td>
                                <td>Invalid request method</td>
                                <td>Request type was not <span class="api-command-ref">POST</span>.</td>
                            </tr>
                            <tr>
                                <td>409</td>
                                <td>409123</td>
                                <td>Virtual connection exists</td>
                                <td>A virtual connection with the same name already exists in the project and <code>overwrite</code> is false. Applies when publishing a .tvcx file.</td>
                            </tr>
                        </tbody>
                    </table>

For more information, see [Handling Errors](https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_concepts_errors.htm).

## Publish Workbook

Publishes a workbook on the specified site.

To make changes to a published workbook, call [Update Workbook](https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref_workbooks_and_views.htm#update_workbook) or [Update Workbook Connection](https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref_workbooks_and_views.htm#update_workbook_connection).

**Version**: Available in API 2.0 and later.

**License**: No additional license required.

**Permissions**: Users who are not server administrators or site administrators can publish a workbook only if the workbook belongs to a project that they have permissions to publish to.

**Access Scope**: `tableau:workbooks:create`

For more information, see [Versions](https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_concepts_versions.htm), [Permissions](https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_concepts_permissions.htm), [Access scopes for UATs](https://help.tableau.com/current/api/cloud-manager/en-us/docs/unified_access_tokens.html#scopes) (Cloud), and access scopes for [Cloud](https://help.tableau.com/current/online/en-us/connected_apps_scopes.htm), [Server-Windows,](https://help.tableau.com/current/server/en-us/connected_apps_scopes.htm) or [Server-Linux](https://help.tableau.com/current/server-linux/en-us/connected_apps_scopes.htm).

This method is used in two ways. You can call it to publish a workbook in a single request. To do that, you include the content of the workbook file in the body of the request. The maximum size of a file that can be published in a single request is 64 MB. If you want to avoid having the publishing process time out, you can use the _asJob_ parameter to make workbook publication asynchronous.

Alternatively, you can publish a workbook in multiple parts. To do that, you initiate a file upload by calling [Initiate File Upload](#initiate_file_upload), send portions of the file to the server using [Append to File Upload](#append_to_file_upload), and then commit the upload by calling Publish Workbook. In this case, Publish Workbook doesn't contain the file to publish.

**Hiding views in a published workbook**  
To exclude certain sheets (also known as views) when you publish a workbook, configure them in the request as `hidden`. You cannot publish a workbook if all sheets are hidden.

**Extracts with multiple table options**  
If an extract was stored using the multiple tables option, you can't append data to it.

**Workbooks that rely on external local resources**  
When you publish a workbook from your local computer to the server, the publish process will fail if the workbook relies on resources (such as an Excel file or other data file) that are on your local computer but are not available on the server. (Unlike the publish process that is used in Tableau Desktop, the REST API publish process cannot automatically include extracts or other resources that the workbook uses.) If you are publishing a workbook that gets its data from a source on your computer, save the workbook as a packaged workbook (`.twbx` file) and publish the package so that workbook has all the resources it needs on the server.

For more information, see [Publishing Resources](https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_concepts_publish.htm).

#### URI

POST /api/api-version/sites/site-id/workbooks

POST /api/api-version/sites/site-id/workbooks?overwrite=overwrite-flag

POST /api/api-version/sites/site-id/workbooks?skipConnectionCheck=skip-connection-check-flag

POST /api/api-version/sites/site-id/workbooks?uploadSessionId=upload-session-id&workbookType=workbook-file-type&overwrite=bool&asJob=asJob-value

#### Parameter Values

<table class="api-parameters-table"><colgroup><col class="api-parameters-table-col-1-extra-wide"> <col></colgroup><tbody><tr><td><span class="api-placeholder">api-version</span></td><td>The version of the API to use, such as <code><span class="mc-variable Variables.REST-API-Version variable">3.29</span></code>. For more information, see <a href="https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_concepts_versions.htm" class="xref">REST API and Resource Versions</a>.</td></tr><tr><td><span class="api-placeholder">site-id</span></td><td>The ID of the site to publish to.</td></tr><tr><td><span class="api-placeholder">overwrite-flag</span></td><td>(Optional) <span class="api-command-ref">true</span> to overwrite a workbook that has the same name, or <span class="api-command-ref">false</span> to fail if the specified workbook already exists. The default is <span class="api-command-ref">false</span>. If <span class="api-placeholder">overwrite-flag</span> is set to <span class="api-command-ref">true</span> but the workbook doesn't already exist, the operation succeeds.</td></tr><tr><td><span class="api-placeholder">asJob-value</span></td><td>(Optional, boolean) If <code>false</code>, the workbook publishing process runs as a synchronous process. If a workbook is very large, the process might time out before it finishes. If you set this value to <i>true</i>, the process runs asynchronously, and a job will start to perform the publishing process and return the job ID. You can check the status of the import job by calling <a href="#query_job">Query Job</a>. Default value is <code>false</code>.</td></tr><tr><td><span class="api-placeholder">skip-connection-check-flag</span></td><td>(Optional, boolean) If <code>true</code>, then the Tableau server will not check if a non-published connection of a workbook is reachable. Publishing will succeed but unchecked connection issues may result in a non-functioning workbook. If you encounter this issue, follow <a href="https://help.tableau.com/current/online/en-us/to_keep_data_fresh.htm" rel="noopener" target="_blank">Keep Data Fresh guidelines</a>. Default value is <code>false</code>.</td></tr><tr><td><span class="api-placeholder">upload-session-id</span></td><td>If you are calling this method to commit a file that was uploaded in parts, this value contains the upload session ID that was generated by a call to <a href="#initiate_file_upload"><span class="api-command-ref">Initiate File Upload</span></a>. If this value is not included, the server assumes that the body of the request contains the file to be published.</td></tr><tr><td><span class="api-placeholder">workbook-file-type</span></td><td><span class="api-command-ref">twb</span> or <span class="api-command-ref">twbx</span> to indicate whether you have uploaded a workbook file (twb) or a packaged workbook file (twbx). This value is required if you are calling <span class="api-command-ref">Publish Workbook</span> in order to commit a file that was previously uploaded using <span class="api-command-ref">Append to File Upload</span>. The value is not used if you upload a file in the body of the request.</td></tr></tbody></table>

#### Request Body

The content type in the header of requests to publish a workbook must use the mixed multi-part content type with a boundary string definition, in the form of: `Content-Type: multipart/mixed; boundary=boundary-string`.

**Publishing a file in the request body**

```
--boundary-string
Content-Disposition: name="request_payload"
Content-Type: text/xml
<tsRequest>
  <workbook
    name="workbook-name"
    showTabs="show-tabs-flag"
    description="workbook-description"
    thumbnailsUserId="user-luid">
    <connections>
      <connection
        serverAddress="server-address"
        serverPort="port-number">
        <connectionCredentials
          name="connection-username"
          password="connection-password"
          embed="embed-flag"
          oAuth="oauth-flag" />
      </connection>
    </connections>
    <project id="project-id"/>
  </workbook>
</tsRequest>
--boundary-string
Content-Disposition: name="tableau_workbook"; filename="workbook-file-name"
Content-Type: application/octet-stream
content-of-workbook-file
--boundary-string--
```

**Committing a file previously uploaded**

```
--boundary-string
Content-Disposition: name="request_payload"
Content-Type: text/xml
<tsRequest>
  <workbook
    name="workbook-name"
    showTabs="show-tabs-flag"
    description="workbook-description"
    thumbnailsUserId="user-luid" >
    <connections>
      <connection
        serverAddress="server-address"
        serverPort="port-number">
        <connectionCredentials
          name="connection-username"
          password="connection-password"
          embed="embed-flag"
          oAuth="oauth-flag" />
      </connection>
    </connections>
    <project id="project-id"/>
  </workbook>
</tsRequest>
--boundary-string--
```

**Hiding a view when publishing a workbook**

```
--boundary-string
Content-Disposition: name="request_payload"
Content-Type: text/xml
<tsRequest>
  <workbook
    name="workbook-name"
    showTabs="show-tabs-flag"
    description="workbook-description"
    thumbnailsUserId="user-luid" >
    <connections>
      <connection
        serverAddress="server-address"
        serverPort="port-number">
        <connectionCredentials
          name="connection-username"
          password="connection-password"
          embed="embed-flag"
          oAuth="oauth-flag" />
	  </connection>
	</connections>
	<views>
      <view
        name="view-name"
        hidden="hide-view-flag" />
	</views>
	<project id="project-id"/>
  </workbook>
</tsRequest>
--boundary-string--
```

#### Attribute Values

<table class="api-parameters-table">
                        <colgroup>
                            <col class="api-parameters-table-col-1-wide">
                            <col>
                        </colgroup>
                        <tbody>
                            <tr>
                                <td><span class="api-placeholder">boundary-string</span>
                                </td>
                                <td>A string of characters that is guaranteed to be unique within the body of the request, and that is used to delimit sections of the request body. This value
                                        must be declared as a header that has this format:
                                        <p><code>Content-type: multipart/mixed; boundary=<span class="api-placeholder">boundary-string</span></code></p></td>
                            </tr>
                            <tr>
                                <td><span class="api-placeholder">workbook-name</span>
                                </td>
                                <td>The name to assign to the workbook when it is saved on the server.</td>
                            </tr>
                            <tr>
                                <td><span class="api-placeholder">workbook-description</span>
                                </td>
                                <td>(Optional) Starting in API&nbsp;3.20, the description for the workbook.</td>
                            </tr>
                            <tr>
                                <td><span class="api-placeholder">show-tabs-flag</span>
                                </td>
                                <td>(Optional) Specify <span class="api-command-ref">true</span> to have the published workbook show views in tabs; otherwise, <span class="api-command-ref">false</span>. The default is <span class="api-command-ref">false</span>.</td>
                            </tr>
                            <tr>
                                <td><span class="api-placeholder">user-luid</span>
                                </td>
                                <td>(Optional) The LUID of the user to generate thumbnails as. You can get the user LUID by calling <a href="#get_users_on_site">Get Users on Site</a>.</td>
                            </tr>
                            <tr>
                                <td><span class="api-placeholder">server-address</span>
                                </td>
                                <td>(Optional) Specify the server address for a data source connection if that data source does not use OAuth.</td>
                            </tr>
                            <tr>
                                <td><span class="api-placeholder">port-number</span>
                                </td>
                                <td>(Optional) Specify the port number for a data source connection if that data source does not use OAuth.</td>
                            </tr>
                            <tr>
                                <td><span class="api-placeholder">connection-username</span>
                                </td>
                                <td>(Optional) If the workbook's data source connections require credentials, the
								    <span class="api-command-ref">&lt;connectionCredentials&gt;</span> elements are included and this attribute specifies
									the connection username. If the element is included but is not required (for example, if the data source uses OAuth),
									the server ignores the element and its attributes.<p>If your auth type allows secrets to be passed as generic username and password variables, use this attribute for the appropriate secret, such as client id. (Example auth types include 2-legged OAuth, like Service Principal OAuth with Databricks and Client Credentials OAuth with Snowflake.)</p><p><b>Note:</b> Even if credentials are embedded in a workbook, you must still provide credentials when connecting to
									a data source that requires credentials, unless that data source uses OAuth.</p></td>
                            </tr>
                            <tr>
                                <td><span class="api-placeholder">connection-password</span>
                                </td>
                                <td>(Optional) If the workbook's data source connections require credentials, the
									<span class="api-command-ref">&lt;connectionCredentials&gt;</span> elements are included and this attribute specifies
									the connection password. If the element is included but is not required (for example, if the data source uses OAuth),
									the server ignores the element and its attributes.<p>If your auth type allows secrets to be passed as generic username and password variables, use this attribute for the appropriate secret, such as client secret. (Example auth types include 2-legged OAuth, like Service Principal OAuth with Databricks and Client Credentials OAuth with Snowflake.)</p><p><b>Note:</b> Even if credentials are embedded in a workbook, you must still provide credentials when connecting to
									a data source that requires credentials, unless that data source uses OAuth.</p></td>
                            </tr>
                            <tr>
                                <td><span class="api-placeholder">embed-flag</span>
                                </td>
                                <td>(Optional) If the workbook's data source connection requires credentials, the <span class="api-command-ref">&lt;connectionCredentials&gt;</span> element is included.
                                        Setting this attribute to <span class="api-command-ref">true</span> instructs the server to save the credentials for when the data source is used.
                                    </td>
                            </tr>
                            <tr>
                                <td><span class="api-placeholder">oauth-flag</span>
                                </td>
                                <td>(Optional) If the workbook's data source connection is configured to use OAuth, set this to <code>true</code> to specify that the value of the <span class="api-command-ref">name</span> attribute
                                    in the <span class="api-command-ref">&lt;connectionCredentials&gt;</span> element is an
                                        OAuth username. In that case, no password is required and the value of the <span class="api-command-ref">embed</span> attribute specifies
                                        whether to embed the OAuth credential with the workbook, and the server address and port number are not required.<p>If your auth type allows secrets to be passed as generic username and password variables, set the <span class="api-command-ref">oAuth</span> attribute to <code>false</code>. (Example auth types include 2-legged OAuth, like Service Principal OAuth with Databricks and Client Credentials OAuth with Snowflake.)</p><p>For more information on OAuth, see the OAuth Connections section of the <a href="https://help.tableau.com/current/online/en-us/protected_auth.htm" target="_blank">Tableau Cloud</a> or <a href="https://help.tableau.com/current/server/en-us/protected_auth.htm" target="_blank">Tableau Server</a> Product Help.

                                    </p></td>
                            </tr>
                            <tr>
                                <td><span class="api-placeholder">hide-view-flag</span>
                                </td>
                                <td>Setting this flag to <code>true</code> will cause the named view to be hidden in the published workbook. The default value is <code>false</code>.
							You can specify any number of views to hide. If all views in a workbook are hidden the server will not perform a publish.</td>
                            </tr>
                            <tr>
                                <td><span class="api-placeholder">project-id</span>
                                </td>
                                <td>The ID of the project to assign the workbook to. If the project is not specified, the workbook will be published to the default project.</td>
                            </tr>
                            <tr>
                                <td><span class="api-placeholder">workbook-file-name</span>
                                </td>
                                <td>The file name (including extension) of the workbook file to upload. This attribute is used in the request body only if the
                                        request also includes the content of the workbook file; it is not used if you are committing a file uploaded using
                                        previous requests.
                                    </td>
                            </tr>
                            <tr>
                                <td><span class="api-placeholder">content-of-workbook-file</span>
                                </td>
                                <td>The content of the workbook file, if the request includes the file. The maximum size of a file that can be uploaded in one call is 64&nbsp;MB.</td>
                            </tr>
                            <tr>
                                <td><span class="api-placeholder">encryptExtracts</span>
                                </td>
                                <td>(Optional) <b>true</b> to encrypt the extracts or <b>false</b> to not encrypt extracts. For more information, see <a href="https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref_extract_and_encryption.htm" class="xref">Extract and Encryption Methods</a>.</td>
                            </tr>
                        </tbody>
                    </table>

#### Response Code

201

#### Response Body

```
<tsResponse>
  <workbook
    id="workbook-id"
	  name="workbook-name"
	  contentUrl="site-content-url"
	  webpageUrl="server-address"
	  showTabs="show-tabs-flag"
	  size="num-size"
	  createdAt="workbook-publish-date-time"
	  updatedAt="workbook-update-date-time"
	  encryptExtracts="encryptExtracts" >
 	    <project id="project-id" name="project-name"/>
	    <owner id="workbook-owner-id"/>
	    <tags/>
	    <views>
	      <view
	        id="view-id"
	     	name="view-name"
	        contentUrl="view-content-url"
	        createdAt="view-publish-date-time"
	        updatedAt="view-update-date-time" >
	          <tags/>
	 	  </view>
	  <materializedViewsEnablementConfig materializedViewsEnabled="materialized-views-enabled-flag"/>
  </workbook>
</tsResponse>
```

The datetime-created and datetime-updated attribute values are returned in UTC format (YYYY-MM-DDTHH:MM:SSZ).

#### cURL Request Example

```
curl "http://MY_SERVER/api/3.4/sites/ff2a8360-3c2b-4b05-a793-7607c602e1fb/workbooks" -X POST -H "X-Tableau-Auth:7T_33sOfS8Ks_0cht4tYxw|8tsTYQyyOZXfOgxZEHWQ4jUTCQ08GhRr" -H "Content-Type: multipart/mixed;" -F "request_payload=@publish-workbook.xml" -F "tableau_workbook=@MY_WORKBOOK.twbx"
```

**Content of publish-workbook.xml** (publish the Test1 workbook, hide the Test Sheet 1 view):

```
<tsRequest>
	<workbook name="test1" showTabs="true" >
	<project id=""/>
	<views>
	<view name="Test Sheet 1" hidden="true" />
	</views>
	</workbook>
</tsRequest>
```

**Example response:**

```
<tsResponse>
	<workbook
		id="1e40f015-ac41-4377-8238-544f70d36150"
		name="test1" contentUrl="test1"
		webpageUrl="http://MY_SERVER/#/workbooks/3"
		showTabs="true"
		size="1"
		createdAt="2019-04-03T21:24:58Z"
		updatedAt="2019-04-03T21:25:02Z"
		encryptExtracts="false">
		  <project id="e6e94e18-349f-11e9-a794-13e5e0f21c22" name="Default"/>
		  <owner id="1473347e-b0c6-4f1f-bcac-7927ee1a690e"/>
	 	  <tags/>
		  <views>
			<view
			  id="0f0d33ac-027d-42a7-94bf-4f0b13e07652"
			  name="Sheet 1"
			  contentUrl="test1/sheets/Sheet1"
			  createdAt="2019-04-03T21:25:02Z"
		      updatedAt="2019-04-03T21:25:02Z">
			  <tags/>
			</view>
		 <materializedViewsEnablementConfig materializedViewsEnabled="false"/>
	</workbook>
</tsResponse>
```

#### Response Headers

Location: /api/3.29/sites/site-id/workbooks/workbook-id

#### Errors

<table class="api-error-table"><colgroup><col class="api-error-table-col-1"> <col class="api-error-table-col-2"> <col class="api-error-table-col-3"> <col></colgroup><tbody><tr><th>HTTP status</th><th><code>error</code> Code</th><th>Condition</th><th>Details</th></tr><tr><td>400</td><td>400000</td><td>Malformed request body</td><td>The XML content in the MIME multipart request is not empty.</td></tr><tr><td>400</td><td>400000</td><td>Missing workbook</td><td>There is no attachment in the request and no <span class="api-command-ref">uploadSessionID</span> parameter.</td></tr><tr><td>400</td><td>400000</td><td>Unexpected attachments</td><td>The message had both an <span class="api-command-ref">uploadSessionId</span> parameter and an attachment, or the request body contained more than one attachment.</td></tr><tr><td>400</td><td>400008</td><td>Invalid <span class="api-command-ref">embed</span> value</td><td>The request body contains a <span class="api-command-ref">&lt;connectionCredentials&gt;</span> element and it has an <span class="api-command-ref">embed</span>&nbsp;attribute whose value is not <span class="api-command-ref">true</span>&nbsp;or&nbsp;<span class="api-command-ref">false</span>.</td></tr><tr><td>400</td><td>400008</td><td>Invalid overwrite value</td><td>The overwrite parameter must be <span class="api-command-ref">true</span> or <span class="api-command-ref">false</span>.</td></tr><tr><td>400</td><td>400011</td><td>Publishing error</td><td>The workbook could not be published for some other reason than those specified earlier.</td></tr><tr><td>400</td><td>400020</td><td>Invalid workbook file name</td><td>The name of the workbook doesn't end in <code>.twb</code> or <code>.twbx</code>.</td></tr><tr><td>400</td><td>400035</td><td>Missing or invalid file type</td><td>The request included an <span class="api-command-ref">uploadSessionId</span> parameter but no file type, or the file type was something other than <code>.twb</code> or <code>.twbx</code>.</td></tr><tr><td>403</td><td>403007</td><td>Insufficient publishing permission</td><td>A non-administrator user attempted to publish a workbook, but the caller doesn't have sufficient project permissions.</td></tr><tr><td>403</td><td>403007</td><td>Unlicensed publishing forbidden</td><td>A non-administrator user attempted to publish a workbook. This is disallowed for all projects (including the default project).</td></tr><tr><td>403</td><td>403007</td><td>Overwrite forbidden</td><td>A workbook with the specified name already exists and the <span class="api-command-ref">overwrite</span> parameter was not set to <span class="api-command-ref">true</span>.</td></tr><tr><td>403</td><td>403007</td><td>Problem connecting to data source</td><td>There was a problem connecting to a data source used by the workbook.&nbsp;This can be due to missing or invalid connection credentials or because the referenced data source is not available on the server.</td></tr><tr><td>403</td><td>403008</td><td>Insufficient storage quota</td><td>The workbook could not be published because there is not enough storage remaining on the server to accommodate its size.</td></tr><tr><td>403</td><td>403130</td><td>Publishing overwrite</td><td>A workbook with the same name already exists.</td></tr><tr><td>403</td><td>403131</td><td>Concurrent update</td><td>The workbook is already being published in another process.</td></tr><tr><td>403</td><td>403132</td><td>Failed connection check</td><td>One or more data sources used by the workbook could not be reached.</td></tr><tr><td>404</td><td>404005</td><td>Project not found</td><td>The project ID in the request body doesn't correspond to an existing project on the site.</td></tr><tr><td>404</td><td>404006</td><td>Workbook not found</td><td>The user specified overwrite as <span class="api-command-ref">true</span> but no workbook with the specified name exists on the site.</td></tr><tr><td>404</td><td>404015</td><td>File upload not found</td><td>The file upload session ID in the <span class="api-command-ref">uploadSessionId</span> parameter doesn't correspond to an existing file upload on the site.</td></tr><tr><td>405</td><td>405000</td><td>Invalid request method</td><td>Request type was not <span class="api-command-ref">POST</span>.</td></tr></tbody></table>

For more information, see [Handling Errors](https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_concepts_errors.htm).