> This page is for Unified.

> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.merge.dev/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.merge.dev/_mcp/server.

# /link-token

POST https://api.merge.dev/api/filestorage/v1/link-token
Content-Type: application/json

Creates a link token to be used when linking a new end user. The link token expires after single use.

Reference: https://docs.merge.dev/merge-unified/filestorage/linked-account/link-token/create

## Authentication

- `Authorization` header (bearer token, required) — Token-based authentication with required prefix "Bearer"

## Servers

- `https://api.merge.dev/api` (Production, default)
- `https://api-eu.merge.dev/api` (ProductionEU)
- `https://api-ap.merge.dev/api` (ProductionAPSE1)

## Request

### Body (application/json)

This endpoint expects an EndUserDetailsRequest.

- `end_user_email_address` (string, required) — Your end user's email address. This is purely for identification purposes - setting this value will not cause any emails to be sent.
- `end_user_organization_name` (string, required) — Your end user's organization.
- `end_user_origin_id` (string, required) — This unique identifier typically represents the ID for your end user in your product's database. This value must be distinct from other Linked Accounts' unique identifiers.
- `categories` (list of enum, required) — The integration categories to show in Merge Link.
  - Allowed values: `hris`, `ats`, `accounting`, `ticketing`, `crm`, `mktg`, `filestorage`, `knowledgebase`
- `integration` (string, optional, nullable) — The slug of a specific pre-selected integration for this linking flow token. For examples of slugs, see https://docs.merge.dev/guides/merge-link/single-integration/.
- `link_expiry_mins` (integer, optional, default: 30) — An integer number of minutes between [30, 720 or 10080 if for a Magic Link URL] for how long this token is valid. Defaults to 30.
- `should_create_magic_link_url` (boolean, optional, nullable, default: false) — Whether to generate a Magic Link URL. Defaults to false. For more information on Magic Link, see https://merge.dev/blog/integrations-fast-say-hello-to-magic-link.
- `hide_admin_magic_link` (boolean, optional, nullable, default: false) — Whether to generate a Magic Link URL on the Admin Needed screen during the linking flow. Defaults to false. For more information on Magic Link, see https://merge.dev/blog/integrations-fast-say-hello-to-magic-link.
- `common_models` (list of CommonModelScopesBodyRequest, optional, nullable) — An array of objects to specify the models and fields that will be disabled for a given Linked Account. Each object uses model_id, enabled_actions, and disabled_fields to specify the model, method, and fields that are scoped for a given Linked Account.
- `category_common_model_scopes` (map from string to list of IndividualCommonModelScopeDeserializerRequest, optional, nullable) — When creating a Link Token, you can set permissions for Common Models that will apply to the account that is going to be linked. Any model or field not specified in link token payload will default to existing settings.
- `language` (enum, optional, nullable) — The following subset of IETF language tags can be used to configure localization.
  - Allowed values: `en`, `de`
- `are_syncs_disabled` (boolean, optional, nullable, default: false) — The boolean that indicates whether initial, periodic, and force syncs will be disabled.
- `integration_specific_config` (map from string to any, optional, nullable) — A JSON object containing integration-specific configuration options.
- `completed_account_initial_screen` (enum, optional, nullable) — When creating a Link token, you can specifiy the initial screen of Linking Flow for a completed Linked Account.
  - Allowed values: `SELECTIVE_SYNC`
- `linked_destination_id` (string, optional, nullable) — The UUID of the linked destination that you want this Linked Account to be tied to.
- `credential_id` (string, optional, nullable) — The id of the credential that you want this Linked Account to be tied to.
- `ekm_enabled` (boolean, optional, default: false) — Whether to enable EKM (External Key Management) for this Linked Account.

## Response

### 200

- `link_token` (string, required)
- `integration_name` (string, optional)
- `magic_link_url` (string, optional)

## Types

### CommonModelScopesBodyRequest

- `model_id` (string, required)
- `enabled_actions` (list of enum, required)
  - Allowed values: `READ`, `WRITE`
- `disabled_fields` (list of string, required)

### IndividualCommonModelScopeDeserializerRequest

- `model_name` (string, required)
- `model_permissions` (map from string to ModelPermissionDeserializerRequest, optional)
- `field_permissions` (FieldPermissionDeserializerRequest, optional)

### ModelPermissionDeserializerRequest

- `is_enabled` (boolean, optional)

### FieldPermissionDeserializerRequest

- `enabled_fields` (list of any, optional)
- `disabled_fields` (list of any, optional)

## Examples

**Request**

```json
{
  "end_user_email_address": "example@gmail.com",
  "end_user_organization_name": "Test Organization",
  "end_user_origin_id": "12345",
  "categories": [
    "hris",
    "ats"
  ]
}
```

**Response**

```json
{
  "link_token": "necdP7FtdASl1fQwm62be2_dM4wBG8_GactqoUV0",
  "integration_name": "Lever",
  "magic_link_url": "https://link.merge.dev/asdfjkl12345jsndfgi2i83n"
}
```

**SDK Code**

```python
import requests

url = "https://api.merge.dev/api/filestorage/v1/link-token"

payload = {
    "end_user_email_address": "example@gmail.com",
    "end_user_organization_name": "Test Organization",
    "end_user_origin_id": "12345",
    "categories": ["hris", "ats"]
}
headers = {
    "Authorization": "Bearer <token>",
    "Content-Type": "application/json"
}

response = requests.post(url, json=payload, headers=headers)

print(response.json())
```

```javascript
const url = 'https://api.merge.dev/api/filestorage/v1/link-token';
const options = {
  method: 'POST',
  headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
  body: '{"end_user_email_address":"example@gmail.com","end_user_organization_name":"Test Organization","end_user_origin_id":"12345","categories":["hris","ats"]}'
};

try {
  const response = await fetch(url, options);
  const data = await response.json();
  console.log(data);
} catch (error) {
  console.error(error);
}
```

```go
package main

import (
	"fmt"
	"strings"
	"net/http"
	"io"
)

func main() {

	url := "https://api.merge.dev/api/filestorage/v1/link-token"

	payload := strings.NewReader("{\n  \"end_user_email_address\": \"example@gmail.com\",\n  \"end_user_organization_name\": \"Test Organization\",\n  \"end_user_origin_id\": \"12345\",\n  \"categories\": [\n    \"hris\",\n    \"ats\"\n  ]\n}")

	req, _ := http.NewRequest("POST", url, payload)

	req.Header.Add("Authorization", "Bearer <token>")
	req.Header.Add("Content-Type", "application/json")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := io.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}
```

```ruby
require 'uri'
require 'net/http'

url = URI("https://api.merge.dev/api/filestorage/v1/link-token")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n  \"end_user_email_address\": \"example@gmail.com\",\n  \"end_user_organization_name\": \"Test Organization\",\n  \"end_user_origin_id\": \"12345\",\n  \"categories\": [\n    \"hris\",\n    \"ats\"\n  ]\n}"

response = http.request(request)
puts response.read_body
```

```java
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;

HttpResponse<String> response = Unirest.post("https://api.merge.dev/api/filestorage/v1/link-token")
  .header("Authorization", "Bearer <token>")
  .header("Content-Type", "application/json")
  .body("{\n  \"end_user_email_address\": \"example@gmail.com\",\n  \"end_user_organization_name\": \"Test Organization\",\n  \"end_user_origin_id\": \"12345\",\n  \"categories\": [\n    \"hris\",\n    \"ats\"\n  ]\n}")
  .asString();
```

```php
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('POST', 'https://api.merge.dev/api/filestorage/v1/link-token', [
  'body' => '{
  "end_user_email_address": "example@gmail.com",
  "end_user_organization_name": "Test Organization",
  "end_user_origin_id": "12345",
  "categories": [
    "hris",
    "ats"
  ]
}',
  'headers' => [
    'Authorization' => 'Bearer <token>',
    'Content-Type' => 'application/json',
  ],
]);

echo $response->getBody();
```

```csharp
using RestSharp;

var client = new RestClient("https://api.merge.dev/api/filestorage/v1/link-token");
var request = new RestRequest(Method.POST);
request.AddHeader("Authorization", "Bearer <token>");
request.AddHeader("Content-Type", "application/json");
request.AddParameter("application/json", "{\n  \"end_user_email_address\": \"example@gmail.com\",\n  \"end_user_organization_name\": \"Test Organization\",\n  \"end_user_origin_id\": \"12345\",\n  \"categories\": [\n    \"hris\",\n    \"ats\"\n  ]\n}", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
```

```swift
import Foundation

let headers = [
  "Authorization": "Bearer <token>",
  "Content-Type": "application/json"
]
let parameters = [
  "end_user_email_address": "example@gmail.com",
  "end_user_organization_name": "Test Organization",
  "end_user_origin_id": "12345",
  "categories": ["hris", "ats"]
] as [String : Any]

let postData = JSONSerialization.data(withJSONObject: parameters, options: [])

let request = NSMutableURLRequest(url: NSURL(string: "https://api.merge.dev/api/filestorage/v1/link-token")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers
request.httpBody = postData as Data

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error as Any)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
```