<!-- llms.txt: https://workos.com/llms.txt -->

# Connected account

A connected account represents a user's authorized connection to a third-party [provider](https://workos.com/docs/reference/pipes/provider) through Pipes. Connected accounts store the OAuth credentials and scopes granted during the authorization flow.

When listing providers for a user, each provider includes a nested `connected_account` showing the user's connection status.

## Create a connected account

Imports a [connected account](https://workos.com/docs/reference/pipes/connected-account) for a user by directly providing OAuth tokens. This is useful for migrating existing connections from another system.

The `state` field is derived from the token combination when not explicitly set. If no tokens are provided, the state defaults to `needs_reauthorization`.

:::code-group

```bash language="curl" title="Request" tab="1"
curl --request POST \
  --url "https://api.workos.com/user_management/users/user_01EHZNVPK3SFK441A1RGBFSHRT/connected_accounts/github" \
  --header "Authorization: Bearer sk_example_123456789" \
```

```rb language="ruby" title="Request" tab="1"
require "workos"

WorkOS.configure do |config|
  config.api_key = "sk_example_123456789"
end

WorkOS.client.pipes.create_user_connected_account(
  user_id: "user_01EHZNVPK3SFK441A1RGBFSHRT",
  slug: "github"
)
```

```py language="python" title="Request" tab="1"
from workos import WorkOSClient

client = WorkOSClient(api_key="sk_example_123456789", client_id="client_123456789")

client.pipes.create_user_connected_account(
    user_id="user_01EHZNVPK3SFK441A1RGBFSHRT", slug="github"
)
```

```go language="go" title="Request" tab="1"
package main

import (
	"context"

	"github.com/workos/workos-go/v10"
)

func main() {
	client := workos.NewClient("sk_example_123456789")

	_, err := client.Pipes().CreateUserConnectedAccount(context.Background(), "user_01EHZNVPK3SFK441A1RGBFSHRT", "github")
	if err != nil {
		panic(err)
	}
}
```

```php language="php" title="Request" tab="1"
<?php

use WorkOS\WorkOS;

$workos = new WorkOS(
    apiKey: "sk_example_123456789",
    clientId: "client_123456789",
);

$workos
    ->pipes()
    ->createUserConnectedAccount(
        userId: "user_01EHZNVPK3SFK441A1RGBFSHRT",
        slug: "github",
    );
```

```java language="java" title="Request" tab="1"
import com.workos.WorkOS;

WorkOS workos = new WorkOS("sk_example_123456789");

workos.pipes.createUserConnectedAccount("user_01EHZNVPK3SFK441A1RGBFSHRT", "github");
```

```cs language="dotnet" title="Request" tab="1"
using WorkOS;

var client = new WorkOSClient(new WorkOSOptions {
    ApiKey = "sk_example_123456789",
    ClientId = "client_123456789",
});

await client.Pipes.CreateUserConnectedAccountAsync("user_01EHZNVPK3SFK441A1RGBFSHRT", "github");
```

```rust language="rust" title="Request" tab="1"
use workos::Client;

#[tokio::main]
async fn main() -> Result<(), workos::Error> {
    let client = Client::builder()
        .api_key("sk_example_123456789")
        .client_id("client_123456789")
        .build();

    let _result = client
        .pipes()
        .create_user_connected_account(
            "user_01EHZNVPK3SFK441A1RGBFSHRT",
            "github"
        )
        .await?;

    Ok(())
}
```

```json language="json" title="Response" tab="2"
{
  "object": "connected_account",
  "id": "data_installation_01EHZNVPK3SFK441A1RGBFSHRT",
  "user_id": "user_01EHZNVPK3SFK441A1RGBFSHRT",
  "organization_id": null,
  "scopes": [
    "repo",
    "user:email"
  ],
  "auth_method": "oauth",
  "api_key_last_4": null,
  "client_id": "3MVG9dZJodJWxft2VoStSCVwPFsx0eDcpVc",
  "client_secret_last_4": "cdef",
  "config": {
    "instance_url": "https://example.my.salesforce.com"
  },
  "state": "connected",
  "created_at": "2024-01-16T14:20:00.000Z",
  "updated_at": "2024-01-16T14:20:00.000Z"
}
```

:::

> **Note:** Token combinations are validated on create. Invalid combinations — such as providing only `expires_at` without an `access_token` — will return a `422` error. See the token validation rules below.

### Token validation

When creating a connected account, the following token combination rules apply:

- No tokens provided → `state` is set to `needs_reauthorization`.
- `access_token` with `expires_at` and `refresh_token` → valid, `state` is `connected`.
- `access_token` only (no `expires_at`) → valid, `state` is `connected`.
- `access_token` with `expires_at` but no `refresh_token` → rejected (`422`).
- `refresh_token` only (no `access_token`) → valid, `expires_at` is set to now.
- `expires_at` only (no `access_token`) → rejected (`422`).

### Error responses

- **409 Conflict**: A connected account already exists for this user, integration, and organization.
- **422**: Invalid token combination or the data integration is not in a valid state.

## Delete a connected account

Disconnects WorkOS's account for the user, including removing any stored access and refresh tokens. The user will need to reauthorize if they want to reconnect.

This does not revoke access on the provider side. The user may need to disconnect the application directly from the provider's settings.

Returns a `204 No Content` response on success.

:::code-group

```bash language="curl" title="Request" tab="1"
curl --request DELETE \
  --url "https://api.workos.com/user_management/users/user_01EHZNVPK3SFK441A1RGBFSHRT/connected_accounts/github" \
  --header "Authorization: Bearer sk_example_123456789"
```

```js language="js" title="Request" tab="1"
import { WorkOS } from '@workos-inc/node';

const workos = new WorkOS('sk_example_123456789');

await workos.pipes.deleteUserConnectedAccount({
  userId: 'user_01EHZNVPK3SFK441A1RGBFSHRT',
  slug: 'github',
});
```

```rb language="ruby" title="Request" tab="1"
require "workos"

WorkOS.configure do |config|
  config.api_key = "sk_example_123456789"
end

WorkOS.client.pipes.delete_user_connected_account(
  user_id: "user_01EHZNVPK3SFK441A1RGBFSHRT",
  slug: "github"
)
```

```py language="python" title="Request" tab="1"
from workos import WorkOSClient

client = WorkOSClient(api_key="sk_example_123456789", client_id="client_123456789")

client.pipes.delete_user_connected_account(
    user_id="user_01EHZNVPK3SFK441A1RGBFSHRT", slug="github"
)
```

```go language="go" title="Request" tab="1"
package main

import (
	"context"

	"github.com/workos/workos-go/v10"
)

func main() {
	client := workos.NewClient("sk_example_123456789")

	_, err := client.Pipes().DeleteUserConnectedAccount(context.Background(), "user_01EHZNVPK3SFK441A1RGBFSHRT", "github")
	if err != nil {
		panic(err)
	}
}
```

```php language="php" title="Request" tab="1"
<?php

use WorkOS\WorkOS;

$workos = new WorkOS(
    apiKey: "sk_example_123456789",
    clientId: "client_123456789",
);

$workos
    ->pipes()
    ->deleteUserConnectedAccount(
        userId: "user_01EHZNVPK3SFK441A1RGBFSHRT",
        slug: "github",
    );
```

```java language="java" title="Request" tab="1"
import com.workos.WorkOS;

WorkOS workos = new WorkOS("sk_example_123456789");

workos.pipes.deleteUserConnectedAccount("user_01EHZNVPK3SFK441A1RGBFSHRT", "github");
```

```cs language="dotnet" title="Request" tab="1"
using WorkOS;

var client = new WorkOSClient(new WorkOSOptions {
    ApiKey = "sk_example_123456789",
    ClientId = "client_123456789",
});

await client.Pipes.DeleteUserConnectedAccountAsync("user_01EHZNVPK3SFK441A1RGBFSHRT", "github");
```

```rust language="rust" title="Request" tab="1"
use workos::Client;

#[tokio::main]
async fn main() -> Result<(), workos::Error> {
    let client = Client::builder()
        .api_key("sk_example_123456789")
        .client_id("client_123456789")
        .build();

    let _result = client
        .pipes()
        .delete_user_connected_account(
            "user_01EHZNVPK3SFK441A1RGBFSHRT",
            "github"
        )
        .await?;

    Ok(())
}
```

:::

## Get authorization URL

Generates an OAuth authorization URL to initiate the connection flow for a user. Redirect the user to the returned URL to begin the OAuth flow with the third-party provider.

:::code-group

```bash language="curl" title="Request" tab="1"
curl --request POST \
  --url "https://api.workos.com/data-integrations/github/authorize" \
  --header "Authorization: Bearer sk_example_123456789" \
  --header "Content-Type: application/json" \
  -d @- <<'BODY'
    {
        "user_id": "user_01EHZNVPK3SFK441A1RGBFSHRT"
    }
BODY
```

```js language="js" title="Request" tab="1"
import { WorkOS } from '@workos-inc/node';

const workos = new WorkOS('sk_example_123456789');

const { url } = await workos.pipes.authorizeDataIntegration({
  slug: 'github',
  userId: 'user_01EHZNVPK3SFK441A1RGBFSHRT',
});
```

```rb language="ruby" title="Request" tab="1"
require "workos"

WorkOS.configure do |config|
  config.api_key = "sk_example_123456789"
end

WorkOS.client.pipes.authorize_data_integration(
  slug: "github",
  user_id: "user_01EHZNVPK3SFK441A1RGBFSHRT"
)
```

```py language="python" title="Request" tab="1"
from workos import WorkOSClient

client = WorkOSClient(api_key="sk_example_123456789", client_id="client_123456789")

client.pipes.authorize_data_integration(
    slug="github", user_id="user_01EHZNVPK3SFK441A1RGBFSHRT"
)
```

```go language="go" title="Request" tab="1"
package main

import (
	"context"

	"github.com/workos/workos-go/v10"
)

func main() {
	client := workos.NewClient("sk_example_123456789")

	_, err := client.Pipes().AuthorizeDataIntegration(context.Background(), "github", &workos.PipesAuthorizeDataIntegrationParams{
		UserID: "user_01EHZNVPK3SFK441A1RGBFSHRT",
	})
	if err != nil {
		panic(err)
	}
}
```

```php language="php" title="Request" tab="1"
<?php

use WorkOS\WorkOS;

$workos = new WorkOS(
    apiKey: "sk_example_123456789",
    clientId: "client_123456789",
);

$workos
    ->pipes()
    ->authorizeDataIntegration(
        slug: "github",
        userId: "user_01EHZNVPK3SFK441A1RGBFSHRT",
    );
```

```java language="java" title="Request" tab="1"
import com.workos.WorkOS;
import com.workos.pipes.PipesApi.AuthorizeDataIntegrationOptions;

WorkOS workos = new WorkOS("sk_example_123456789");

AuthorizeDataIntegrationOptions options = AuthorizeDataIntegrationOptions.builder()
                                              .userId("user_01EHZNVPK3SFK441A1RGBFSHRT")
                                              .build();

workos.pipes.authorizeDataIntegration("github", options);
```

```cs language="dotnet" title="Request" tab="1"
using WorkOS;

var client = new WorkOSClient(new WorkOSOptions {
    ApiKey = "sk_example_123456789",
    ClientId = "client_123456789",
});

await client.Pipes.AuthorizeDataIntegrationAsync("github", new PipesAuthorizeDataIntegrationOptions {
    UserId = "user_01EHZNVPK3SFK441A1RGBFSHRT",
});
```

```rust language="rust" title="Request" tab="1"
use workos::Client;
use workos::pipes::AuthorizeDataIntegrationParams;

#[tokio::main]
async fn main() -> Result<(), workos::Error> {
    let client = Client::builder()
        .api_key("sk_example_123456789")
        .client_id("client_123456789")
        .build();

    let _result = client
        .pipes()
        .authorize_data_integration(
            "github",
            AuthorizeDataIntegrationParams {
                user_id: "user_01EHZNVPK3SFK441A1RGBFSHRT".into(),
                ..Default::default()
            }
        )
        .await?;

    Ok(())
}
```

```json language="json" title="Response" tab="2"
{
  "url": "https://api.workos.com/data-integrations/q2czJKmVAraSBg8xFpT7M9uR/authorize-redirect"
}
```

:::

## Get a connected account

Retrieves a user's [connected account](https://workos.com/docs/reference/pipes/connected-account) for a specific provider.

:::code-group

```bash language="curl" title="Request" tab="1"
curl "https://api.workos.com/user_management/users/user_01EHZNVPK3SFK441A1RGBFSHRT/connected_accounts/github" \
  --header "Authorization: Bearer sk_example_123456789"
```

```js language="js" title="Request" tab="1"
import { WorkOS } from '@workos-inc/node';

const workos = new WorkOS('sk_example_123456789');

const connectedAccount = await workos.pipes.getUserConnectedAccount({
  userId: 'user_01EHZNVPK3SFK441A1RGBFSHRT',
  slug: 'github',
});
```

```rb language="ruby" title="Request" tab="1"
require "workos"

WorkOS.configure do |config|
  config.api_key = "sk_example_123456789"
end

WorkOS.client.pipes.get_user_connected_account(
  user_id: "user_01EHZNVPK3SFK441A1RGBFSHRT",
  slug: "github"
)
```

```py language="python" title="Request" tab="1"
from workos import WorkOSClient

client = WorkOSClient(api_key="sk_example_123456789", client_id="client_123456789")

client.pipes.get_user_connected_account(
    user_id="user_01EHZNVPK3SFK441A1RGBFSHRT", slug="github"
)
```

```go language="go" title="Request" tab="1"
package main

import (
	"context"

	"github.com/workos/workos-go/v10"
)

func main() {
	client := workos.NewClient("sk_example_123456789")

	_, err := client.Pipes().GetUserConnectedAccount(context.Background(), "user_01EHZNVPK3SFK441A1RGBFSHRT", "github")
	if err != nil {
		panic(err)
	}
}
```

```php language="php" title="Request" tab="1"
<?php

use WorkOS\WorkOS;

$workos = new WorkOS(
    apiKey: "sk_example_123456789",
    clientId: "client_123456789",
);

$workos
    ->pipes()
    ->getUserConnectedAccount(
        userId: "user_01EHZNVPK3SFK441A1RGBFSHRT",
        slug: "github",
    );
```

```java language="java" title="Request" tab="1"
import com.workos.WorkOS;

WorkOS workos = new WorkOS("sk_example_123456789");

workos.pipes.getUserConnectedAccount("user_01EHZNVPK3SFK441A1RGBFSHRT", "github");
```

```cs language="dotnet" title="Request" tab="1"
using WorkOS;

var client = new WorkOSClient(new WorkOSOptions {
    ApiKey = "sk_example_123456789",
    ClientId = "client_123456789",
});

await client.Pipes.GetUserConnectedAccountAsync("user_01EHZNVPK3SFK441A1RGBFSHRT", "github");
```

```rust language="rust" title="Request" tab="1"
use workos::Client;

#[tokio::main]
async fn main() -> Result<(), workos::Error> {
    let client = Client::builder()
        .api_key("sk_example_123456789")
        .client_id("client_123456789")
        .build();

    let _result = client
        .pipes()
        .get_user_connected_account(
            "user_01EHZNVPK3SFK441A1RGBFSHRT",
            "github"
        )
        .await?;

    Ok(())
}
```

```json language="json" title="Response" tab="2"
{
  "object": "connected_account",
  "id": "data_installation_01EHZNVPK3SFK441A1RGBFSHRT",
  "user_id": "user_01EHZNVPK3SFK441A1RGBFSHRT",
  "organization_id": null,
  "scopes": [
    "repo",
    "user:email"
  ],
  "auth_method": "oauth",
  "api_key_last_4": null,
  "client_id": "3MVG9dZJodJWxft2VoStSCVwPFsx0eDcpVc",
  "client_secret_last_4": "cdef",
  "config": {
    "instance_url": "https://example.my.salesforce.com"
  },
  "state": "connected",
  "created_at": "2024-01-16T14:20:00.000Z",
  "updated_at": "2024-01-16T14:20:00.000Z"
}
```

:::

## Update a connected account

Updates a user's [connected account](https://workos.com/docs/reference/pipes/connected-account) tokens, scopes, or state for a specific provider.

:::code-group

```bash language="curl" title="Request" tab="1"
curl --request PUT \
  --url "https://api.workos.com/user_management/users/user_01EHZNVPK3SFK441A1RGBFSHRT/connected_accounts/github" \
  --header "Authorization: Bearer sk_example_123456789" \
  --header "Content-Type: application/json" \
  -d @- <<'BODY'
    {
        "access_token": "gho_16C7e42F292c6912E7710c838347Ae178B4a",
        "refresh_token": "ghr_xxxxxxxxxxxxxxxxxxxx",
        "expires_at": "2025-12-31T23:59:59.000Z",
        "scopes": [
            "repo",
            "user:email"
        ],
        "state": "connected"
    }
BODY
```

```rb language="ruby" title="Request" tab="1"
require "workos"

WorkOS.configure do |config|
  config.api_key = "sk_example_123456789"
end

WorkOS.client.pipes.update_user_connected_account(
  user_id: "user_01EHZNVPK3SFK441A1RGBFSHRT",
  slug: "github"
)
```

```py language="python" title="Request" tab="1"
from workos import WorkOSClient

client = WorkOSClient(api_key="sk_example_123456789", client_id="client_123456789")

client.pipes.update_user_connected_account(
    user_id="user_01EHZNVPK3SFK441A1RGBFSHRT", slug="github"
)
```

```go language="go" title="Request" tab="1"
package main

import (
	"context"

	"github.com/workos/workos-go/v10"
)

func main() {
	client := workos.NewClient("sk_example_123456789")

	_, err := client.Pipes().UpdateUserConnectedAccount(context.Background(), "user_01EHZNVPK3SFK441A1RGBFSHRT", "github")
	if err != nil {
		panic(err)
	}
}
```

```php language="php" title="Request" tab="1"
<?php

use WorkOS\WorkOS;

$workos = new WorkOS(
    apiKey: "sk_example_123456789",
    clientId: "client_123456789",
);

$workos
    ->pipes()
    ->updateUserConnectedAccount(
        userId: "user_01EHZNVPK3SFK441A1RGBFSHRT",
        slug: "github",
    );
```

```java language="java" title="Request" tab="1"
import com.workos.WorkOS;

WorkOS workos = new WorkOS("sk_example_123456789");

workos.pipes.updateUserConnectedAccount("user_01EHZNVPK3SFK441A1RGBFSHRT", "github");
```

```cs language="dotnet" title="Request" tab="1"
using WorkOS;

var client = new WorkOSClient(new WorkOSOptions {
    ApiKey = "sk_example_123456789",
    ClientId = "client_123456789",
});

await client.Pipes.UpdateUserConnectedAccountAsync("user_01EHZNVPK3SFK441A1RGBFSHRT", "github");
```

```rust language="rust" title="Request" tab="1"
use workos::Client;

#[tokio::main]
async fn main() -> Result<(), workos::Error> {
    let client = Client::builder()
        .api_key("sk_example_123456789")
        .client_id("client_123456789")
        .build();

    let _result = client
        .pipes()
        .update_user_connected_account(
            "user_01EHZNVPK3SFK441A1RGBFSHRT",
            "github"
        )
        .await?;

    Ok(())
}
```

```json language="json" title="Response" tab="2"
{
  "object": "connected_account",
  "id": "data_installation_01EHZNVPK3SFK441A1RGBFSHRT",
  "user_id": "user_01EHZNVPK3SFK441A1RGBFSHRT",
  "organization_id": null,
  "scopes": [
    "repo",
    "user:email"
  ],
  "auth_method": "oauth",
  "api_key_last_4": null,
  "client_id": "3MVG9dZJodJWxft2VoStSCVwPFsx0eDcpVc",
  "client_secret_last_4": "cdef",
  "config": {
    "instance_url": "https://example.my.salesforce.com"
  },
  "state": "connected",
  "created_at": "2024-01-16T14:20:00.000Z",
  "updated_at": "2024-01-16T14:20:00.000Z"
}
```

:::

> **Note:** Unlike the create endpoint, update does **not** validate token combinations. The provided values are applied directly, so callers are responsible for maintaining valid token and state combinations. For example, setting `state` to `connected` without providing valid tokens will leave the connected account in an inconsistent state.

### Error responses

- **404 Not Found**: No connected account exists for the given user and slug.

## Upsert an API key for a connected account

Creates or updates an API-key-based installation for the specified integration and user. If an installation already exists, the stored API key is rotated to the new value.

:::code-group

```bash language="curl" title="Request" tab="1"
curl --request PUT \
  --url "https://api.workos.com/data-integrations/github/api-key" \
  --header "Authorization: Bearer sk_example_123456789" \
  --header "Content-Type: application/json" \
  -d @- <<'BODY'
    {
        "user_id": "user_01EHZNVPK3SFK441A1RGBFSHRT",
        "secret": "sk-1234567890abcdef"
    }
BODY
```

```js language="js" title="Request" tab="1"
import { WorkOS } from '@workos-inc/node';

const workos = new WorkOS('sk_example_123456789');

await workos.pipes.updateDataIntegrationApiKey({
  slug: 'github',
  userId: 'user_01EHZNVPK3SFK441A1RGBFSHRT',
  secret: 'sk-1234567890abcdef',
});
```

```rb language="ruby" title="Request" tab="1"
require "workos"

WorkOS.configure do |config|
  config.api_key = "sk_example_123456789"
end

WorkOS.client.pipes.update_data_integration_api_key(
  slug: "github",
  user_id: "user_01EHZNVPK3SFK441A1RGBFSHRT",
  secret: "sk-1234567890abcdef"
)
```

```py language="python" title="Request" tab="1"
from workos import WorkOSClient

client = WorkOSClient(api_key="sk_example_123456789", client_id="client_123456789")

client.pipes.update_data_integration_api_key(
    slug="github",
    user_id="user_01EHZNVPK3SFK441A1RGBFSHRT",
    secret="sk-1234567890abcdef",
)
```

```go language="go" title="Request" tab="1"
package main

import (
	"context"

	"github.com/workos/workos-go/v10"
)

func main() {
	client := workos.NewClient("sk_example_123456789")

	_, err := client.Pipes().UpdateDataIntegrationAPIKey(context.Background(), "github", &workos.PipesUpdateDataIntegrationAPIKeyParams{
		UserID: "user_01EHZNVPK3SFK441A1RGBFSHRT",
		Secret: "sk-1234567890abcdef",
	})
	if err != nil {
		panic(err)
	}
}
```

```php language="php" title="Request" tab="1"
<?php

use WorkOS\WorkOS;

$workos = new WorkOS(
    apiKey: "sk_example_123456789",
    clientId: "client_123456789",
);

$workos
    ->pipes()
    ->updateDataIntegrationApiKey(
        slug: "github",
        userId: "user_01EHZNVPK3SFK441A1RGBFSHRT",
        secret: "sk-1234567890abcdef",
    );
```

```java language="java" title="Request" tab="1"
import com.workos.WorkOS;
import com.workos.pipes.PipesApi.UpdateDataIntegrationApiKeyOptions;

WorkOS workos = new WorkOS("sk_example_123456789");

UpdateDataIntegrationApiKeyOptions options =
    UpdateDataIntegrationApiKeyOptions.builder()
        .userId("user_01EHZNVPK3SFK441A1RGBFSHRT")
        .secret("sk-1234567890abcdef")
        .build();

workos.pipes.updateDataIntegrationApiKey("github", options);
```

```cs language="dotnet" title="Request" tab="1"
using WorkOS;

var client = new WorkOSClient(new WorkOSOptions {
    ApiKey = "sk_example_123456789",
    ClientId = "client_123456789",
});

await client.Pipes.UpdateDataIntegrationApiKeyAsync("github", new PipesUpdateDataIntegrationApiKeyOptions {
    UserId = "user_01EHZNVPK3SFK441A1RGBFSHRT",
    Secret = "sk-1234567890abcdef",
});
```

```rust language="rust" title="Request" tab="1"
use workos::Client;
use workos::pipes::UpdateDataIntegrationApiKeyParams;

#[tokio::main]
async fn main() -> Result<(), workos::Error> {
    let client = Client::builder()
        .api_key("sk_example_123456789")
        .client_id("client_123456789")
        .build();

    let _result = client
        .pipes()
        .update_data_integration_api_key(
            "github",
            UpdateDataIntegrationApiKeyParams {
                user_id: "user_01EHZNVPK3SFK441A1RGBFSHRT".into(),
                secret: "sk-1234567890abcdef".into(),
                ..Default::default()
            }
        )
        .await?;

    Ok(())
}
```

```json language="json" title="Response" tab="2"
{
  "object": "connected_account",
  "id": "data_installation_01EHZNVPK3SFK441A1RGBFSHRT",
  "user_id": "user_01EHZNVPK3SFK441A1RGBFSHRT",
  "organization_id": "org_01EHZNVPK3SFK441A1RGBFSHRT",
  "scopes": [],
  "auth_method": "api_key",
  "api_key_last_4": "cdef",
  "state": "connected",
  "created_at": "2024-01-16T14:20:00.000Z",
  "updated_at": "2024-01-16T14:20:00.000Z"
}
```

:::

## Upsert client credentials for a connected account

Creates or updates a client-credentials-based installation for the specified integration and user. If an installation already exists, the stored client credentials are rotated to the new values.

:::code-group

```bash language="curl" title="Request" tab="1"
curl --request PUT \
  --url "https://api.workos.com/data-integrations/salesforce/client-credentials" \
  --header "Authorization: Bearer sk_example_123456789" \
  --header "Content-Type: application/json" \
  -d @- <<'BODY'
    {
        "user_id": "user_01EHZNVPK3SFK441A1RGBFSHRT",
        "client_id": "3MVG9...",
        "client_secret": "shhh-secret"
    }
BODY
```

```rb language="ruby" title="Request" tab="1"
require "workos"

WorkOS.configure do |config|
  config.api_key = "sk_example_123456789"
end

WorkOS.client.pipes.update_data_integration_client_credentials(
  slug: "salesforce",
  user_id: "user_01EHZNVPK3SFK441A1RGBFSHRT",
  client_id: "3MVG9...",
  client_secret: "shhh-secret"
)
```

```py language="python" title="Request" tab="1"
from workos import WorkOSClient

client = WorkOSClient(api_key="sk_example_123456789", client_id="client_123456789")

client.pipes.update_data_integration_client_credentials(
    slug="salesforce",
    user_id="user_01EHZNVPK3SFK441A1RGBFSHRT",
    client_id="3MVG9...",
    client_secret="shhh-secret",
)
```

```go language="go" title="Request" tab="1"
package main

import (
	"context"

	"github.com/workos/workos-go/v10"
)

func main() {
	client := workos.NewClient("sk_example_123456789")

	_, err := client.Pipes().UpdateDataIntegrationClientCredentials(context.Background(), "salesforce", &workos.PipesUpdateDataIntegrationClientCredentialsParams{
		UserID:       "user_01EHZNVPK3SFK441A1RGBFSHRT",
		ClientID:     "3MVG9...",
		ClientSecret: "shhh-secret",
	})
	if err != nil {
		panic(err)
	}
}
```

```php language="php" title="Request" tab="1"
<?php

use WorkOS\WorkOS;

$workos = new WorkOS(
    apiKey: "sk_example_123456789",
    clientId: "client_123456789",
);

$workos
    ->pipes()
    ->updateDataIntegrationClientCredentials(
        slug: "salesforce",
        userId: "user_01EHZNVPK3SFK441A1RGBFSHRT",
        clientId: "3MVG9...",
        clientSecret: "shhh-secret",
    );
```

```java language="java" title="Request" tab="1"
import com.workos.WorkOS;
import com.workos.pipes.PipesApi.UpdateDataIntegrationClientCredentialsOptions;

WorkOS workos = new WorkOS("sk_example_123456789");

UpdateDataIntegrationClientCredentialsOptions options =
    UpdateDataIntegrationClientCredentialsOptions.builder()
        .userId("user_01EHZNVPK3SFK441A1RGBFSHRT")
        .clientId("3MVG9...")
        .clientSecret("shhh-secret")
        .build();

workos.pipes.updateDataIntegrationClientCredentials("salesforce", options);
```

```cs language="dotnet" title="Request" tab="1"
using WorkOS;

var client = new WorkOSClient(new WorkOSOptions {
    ApiKey = "sk_example_123456789",
    ClientId = "client_123456789",
});

await client.Pipes.UpdateDataIntegrationClientCredentialsAsync("salesforce",
                                                               new PipesUpdateDataIntegrationClientCredentialsOptions {
                                                                   UserId = "user_01EHZNVPK3SFK441A1RGBFSHRT",
                                                                   ClientId = "3MVG9...",
                                                                   ClientSecret = "shhh-secret",
                                                               });
```

```rust language="rust" title="Request" tab="1"
use workos::Client;
use workos::pipes::UpdateDataIntegrationClientCredentialsParams;

#[tokio::main]
async fn main() -> Result<(), workos::Error> {
    let client = Client::builder()
        .api_key("sk_example_123456789")
        .client_id("client_123456789")
        .build();

    let _result = client
        .pipes()
        .update_data_integration_client_credentials(
            "salesforce",
            UpdateDataIntegrationClientCredentialsParams {
                user_id: "user_01EHZNVPK3SFK441A1RGBFSHRT".into(),
                client_id: "3MVG9...".into(),
                client_secret: "shhh-secret".into(),
                ..Default::default()
            }
        )
        .await?;

    Ok(())
}
```

```json language="json" title="Response" tab="2"
{
  "object": "connected_account",
  "id": "data_installation_01EHZNVPK3SFK441A1RGBFSHRT",
  "user_id": "user_01EHZNVPK3SFK441A1RGBFSHRT",
  "organization_id": "org_01EHZNVPK3SFK441A1RGBFSHRT",
  "scopes": [],
  "auth_method": "client_credentials",
  "state": "connected",
  "created_at": "2024-01-16T14:20:00.000Z",
  "updated_at": "2024-01-16T14:20:00.000Z"
}
```

:::

### data_integration

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `object` | "data_integration" | Yes | Distinguishes the Data Integration object. |
| `id` | string | Yes | Unique identifier of the Data Integration. |
| `slug` | string | Yes | The provider slug for this Data Integration. |
| `integration_type` | string | Yes | The integration type derived from the provider. |
| `description` | string | No | An optional description of the Data Integration. |
| `enabled` | boolean | Yes | Whether the Data Integration is enabled. |
| `state` | "valid" \| "invalid" \| "requested" | Yes | The state of the Data Integration. |
| `scopes` | string[] | No | The OAuth scopes configured for the Data Integration. `null` when the provider's configured scopes are used. |
| `redirect_uri` | string | Yes | The OAuth redirect URI to register with the provider when configuring the custom application. Empty for `api_key` and `client_credentials` integrations, which run no authorization redirect. |
| `auth_methods` | ("oauth" \| "api_key" \| "client_credentials")[] | Yes | How accounts authenticate with the provider for this Data Integration. |
| `credentials` | object | No | The integration-level OAuth app credentials. `null` for `api_key` and `client_credentials` integrations, which hold no integration-level credentials (secrets are installed per-tenant). |
| `installation` | object | No | The tenant installation created when an API key was supplied at creation time; `null` otherwise. Not populated on list/get responses. |
| `config` | object | Yes | Provider-specific config values set on the Data Integration (e.g. a Snowflake `account`), keyed by config field. Only fields the provider declares are accepted. |
| `custom_provider` | object | No | The OAuth definition when this is a custom provider; `null` for built-in providers. |
| `created_at` | string | Yes | An ISO 8601 timestamp. |
| `updated_at` | string | Yes | An ISO 8601 timestamp. |

### POST /user_management/users/{user_id}/connected_accounts/{slug}

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `access_token` | string | No | The OAuth access token for the connected account. |
| `refresh_token` | string | No | The OAuth refresh token for the connected account. |
| `expires_at` | string | No | The ISO-8601 timestamp when the access token expires. Required when providing both `access_token` and `refresh_token` for tokens that expire. Providing `expires_at` with `access_token` but without `refresh_token` returns a `422` error. |
| `scopes` | string[] | No | The OAuth scopes granted for this connection. |
| `state` | "connected" \| "needs_reauthorization" | No | Explicitly set the state of the connected account. When omitted, the state is derived from the token combination provided. |

#### Parameters

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| `user_id` | string | Yes | A [User](/reference/authkit/user) identifier. |
| `slug` | string | Yes | The slug identifier of the provider (e.g., `github`, `slack`, `notion`). |
| `organization_id` | string | No | An [Organization](/reference/organization) identifier. Optional parameter to scope the connection to a specific organization. |

#### Returns

| Field | Type | Description |
| --- | --- | --- |
| `connected_account` | object | Distinguishes the connected account object. |

### DELETE /user_management/users/{user_id}/connected_accounts/{slug}

#### Parameters

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| `user_id` | string | Yes | A [User](/reference/authkit/user) identifier. |
| `slug` | string | Yes | The slug identifier of the provider (e.g., `github`, `slack`, `notion`). |
| `organization_id` | string | No | An [Organization](/reference/organization) identifier. Optional parameter if the connection is scoped to an organization. |

#### Returns

| Field | Type | Description |
| --- | --- | --- |
| `empty` | empty | Returns an empty response on success. |

### POST /data-integrations/{slug}/authorize

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `user_id` | string | Yes | A [User](/reference/authkit/user) identifier. This is the user who will authorize the connection. |
| `organization_id` | string | No | An [Organization](/reference/organization) identifier. Optional parameter to scope the connection to a specific organization. |
| `return_to` | string | No | The URL to redirect the user to after authorization. |
| `config` | object | No | Connect-time config values for the provider-declared `installation`-scope fields (e.g. a Zendesk `subdomain`), keyed by the config field. Only fields the provider declares may be supplied, and required fields must be provided unless already pinned on the integration. |

#### Parameters

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| `slug` | string | Yes | The slug identifier of the provider (e.g., `github`, `slack`, `notion`). |

#### Returns

| Field | Type | Description |
| --- | --- | --- |
| `url` | string | The OAuth authorization URL to redirect the user to. |

### GET /user_management/users/{user_id}/connected_accounts/{slug}

#### Parameters

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| `user_id` | string | Yes | A [User](/reference/authkit/user) identifier. |
| `slug` | string | Yes | The slug identifier of the provider (e.g., `github`, `slack`, `notion`). |
| `organization_id` | string | No | An [Organization](/reference/organization) identifier. Optional parameter if the connection is scoped to an organization. |

#### Returns

| Field | Type | Description |
| --- | --- | --- |
| `connected_account` | object | Distinguishes the connected account object. |

### PUT /user_management/users/{user_id}/connected_accounts/{slug}

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `access_token` | string | No | The OAuth access token for the connected account. |
| `refresh_token` | string | No | The OAuth refresh token for the connected account. |
| `expires_at` | string | No | The ISO-8601 timestamp when the access token expires. |
| `scopes` | string[] | No | The OAuth scopes granted for this connection. |
| `state` | "connected" \| "needs_reauthorization" | No | Explicitly set the state of the connected account. When omitted, the existing state is preserved. |

#### Parameters

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| `user_id` | string | Yes | A [User](/reference/authkit/user) identifier. |
| `slug` | string | Yes | The slug identifier of the provider (e.g., `github`, `slack`, `notion`). |
| `organization_id` | string | No | An [Organization](/reference/organization) identifier. Required if the connected account is scoped to an organization. |

#### Returns

| Field | Type | Description |
| --- | --- | --- |
| `connected_account` | object | Distinguishes the connected account object. |

### PUT /data-integrations/{slug}/api-key

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `user_id` | string | Yes | A [User](/reference/authkit/user) identifier. |
| `organization_id` | string | No | An [Organization](/reference/organization) identifier. Optional parameter to scope the connection to a specific organization. |
| `secret` | string | Yes | The API key secret to store for this integration. |

#### Parameters

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| `slug` | string | Yes | The identifier of the integration. |

#### Returns

| Field | Type | Description |
| --- | --- | --- |
| `connected_account` | object | Distinguishes the connected account object. |

### PUT /data-integrations/{slug}/client-credentials

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `user_id` | string | Yes | A [User](/reference/authkit/user) identifier. |
| `organization_id` | string | No | An [Organization](/reference/organization) identifier. Optional parameter to scope the connection to a specific organization. |
| `client_id` | string | Yes | The OAuth client ID to store for this integration. |
| `client_secret` | string | Yes | The OAuth client secret to store for this integration. |
| `config` | object | No | Provider-specific configuration values collected for this installation, keyed by the provider's config field descriptors. |

#### Parameters

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| `slug` | string | Yes | The identifier of the integration. |

#### Returns

| Field | Type | Description |
| --- | --- | --- |
| `connected_account` | object | Distinguishes the connected account object. |