> This page is for API, version 2026-01-01 (Stable) (default).
> For other versions, use one of these documentation indexes:
> - 2026-01-01 (Stable) (default): https://developer.deel.com/api/stable/llms.txt

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

# Add payroll migration files to a legal entity

POST https://api.letsdeel.com/rest/gp/legal-entities/{legal_entity_id}/payroll-migration-imports
Content-Type: application/json

Attach year-to-date payroll files to a legal entity's payroll migration import, created on the first call. Upload each file to the Deel file service first and pass the id and secret it returns. The import stays IN_PROGRESS until submitted; attaching files to a submitted one reopens it. Atomic: one rejected file stores nothing.

 **Token scopes**: `global-payroll:write`

Reference: https://developer.deel.com/api/reference/endpoints/global-payroll/import-payroll-migration-files-v-2026-09-14

## Authentication

- `Authorization` header (bearer token, required) — ## Authentication The Deel API uses bearer tokens to authenticate requests. All API calls must be made over HTTPS — calls over plain HTTP or without authentication will fail. ```curl curl -X GET 'https://api.letsdeel.com/rest/v2/contracts' \ -H 'Authorization: Bearer YOUR-TOKEN-HERE' ``` [Learn more about authentication](/api/authentication)
- `Authorization` header (bearer token, required) — Standard OAuth2 security scheme based on https://swagger.io/docs/specification/authentication/

## Servers

- `https://api.letsdeel.com/rest` (Production, default)
- `https://api-staging.letsdeel.com/rest` (Demo)

## Request

### Path parameters

- `legal_entity_id` (string, required) — The unique identifier of the legal entity the payroll migration files belong to.

### Body (application/json)

This endpoint expects an object.

- `data` (GpLegalEntitiesLegalEntityIdPayrollMigrationImportsPostRequestBodyContentApplicationJsonSchemaData, required) — The payroll migration files to attach to the import.

## Response

### 201

OK

- `data` (GpLegalEntitiesLegalEntityIdPayrollMigrationImportsPostResponsesContentApplicationJsonSchemaData, required) — The payroll migration import.

## Errors

### 400 Bad Request Error

400

- `code` (string, required)
- `status` (double, required)
- `defined` (boolean, required)
- `message` (string, required, default: One or more files could not be claimed - check that each upload finished its security scan.)
- `data` (GpLegalEntitiesLegalEntityIdPayrollMigrationImportsPostResponsesContentApplicationJsonSchemaData, optional)

### 401 Unauthorized Error

401

- `code` (string, required)
- `status` (double, required)
- `defined` (boolean, required)
- `message` (string, required, default: The request carries no caller identity the gateway could resolve.)
- `data` (any, optional)

### 403 Forbidden Error

403

- `code` (string, required)
- `status` (double, required)
- `defined` (boolean, required)
- `message` (string, required, default: The caller is not authorized to act on this legal entity.)
- `data` (any, optional)

### 404 Not Found Error

404

- `code` (string, required)
- `status` (double, required)
- `defined` (boolean, required)
- `message` (string, required, default: Legal entity not found.)
- `data` (any, optional)

### 409 Conflict Error

409

- `code` (string, required)
- `status` (double, required)
- `defined` (boolean, required)
- `message` (string, required, default: One or more files are already attached to this payroll migration import.)
- `data` (GpLegalEntitiesLegalEntityIdPayrollMigrationImportsPostResponsesContentApplicationJsonSchemaData, optional)

### 500 Internal Server Error

500

- `code` (string, required)
- `status` (double, required)
- `defined` (boolean, required)
- `message` (string, required, default: Internal server error.)
- `data` (any, optional)

## Types

### GpLegalEntitiesLegalEntityIdPayrollMigrationImportsPostRequestBodyContentApplicationJsonSchemaData

The payroll migration files to attach to the import.

- `files` (list of GpLegalEntitiesLegalEntityIdPayrollMigrationImportsPostRequestBodyContentApplicationJsonSchemaDataFilesItems, required) — The files to attach to the import, between 1 and 50 per request.

### GpLegalEntitiesLegalEntityIdPayrollMigrationImportsPostResponsesContentApplicationJsonSchemaData

- `file_ids` (list of string, required) — The ids of the files the request was rejected over.

### GpLegalEntitiesLegalEntityIdPayrollMigrationImportsPostRequestBodyContentApplicationJsonSchemaDataFilesItems

- `file_id` (string, required) — The identifier the Deel file service returned for the uploaded file.
- `one_time_secret` (string, required) — The single-use secret the Deel file service returned alongside the file id.

## Examples

**Request**

```json
{
  "data": {
    "files": [
      {
        "file_id": "V1StGXR8_Z5jdHi6B-myT",
        "one_time_secret": "b7c2e91-A_z.9"
      }
    ]
  }
}
```

**Response**

```json
{
  "data": {
    "created_at": "2026-01-15T09:30:00.000Z",
    "files": [
      {
        "file_id": "V1StGXR8_Z5jdHi6B-myT",
        "file_name": "Revolut IE (YTD) 2026.csv",
        "file_size": 524288,
        "mime_type": "text/csv",
        "source": "EXTERNAL",
        "uploaded_at": "2026-01-15T09:30:00.000Z"
      }
    ],
    "import_id": "2f8c9a41-6b3e-4d0a-9f21-77c1e0a5b3d8",
    "legal_entity_id": "9a1f0e77-3c22-4b8d-8e64-2b0f5d9c1a44",
    "status": "SUBMITTED",
    "submitted_at": "2026-01-15T09:30:00.000Z",
    "type": "YTD_HISTORICAL_INGESTION",
    "updated_at": "2026-01-15T09:30:00.000Z"
  }
}
```

**SDK Code**

```python
import requests

url = "https://api.letsdeel.com/rest/gp/legal-entities/9a1f0e77-3c22-4b8d-8e64-2b0f5d9c1a44/payroll-migration-imports"

payload = { "data": { "files": [
            {
                "file_id": "V1StGXR8_Z5jdHi6B-myT",
                "one_time_secret": "b7c2e91-A_z.9"
            }
        ] } }
headers = {
    "Authorization": "Bearer <token>",
    "Content-Type": "application/json"
}

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

print(response.json())
```

```javascript
const url = 'https://api.letsdeel.com/rest/gp/legal-entities/9a1f0e77-3c22-4b8d-8e64-2b0f5d9c1a44/payroll-migration-imports';
const options = {
  method: 'POST',
  headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
  body: '{"data":{"files":[{"file_id":"V1StGXR8_Z5jdHi6B-myT","one_time_secret":"b7c2e91-A_z.9"}]}}'
};

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.letsdeel.com/rest/gp/legal-entities/9a1f0e77-3c22-4b8d-8e64-2b0f5d9c1a44/payroll-migration-imports"

	payload := strings.NewReader("{\n  \"data\": {\n    \"files\": [\n      {\n        \"file_id\": \"V1StGXR8_Z5jdHi6B-myT\",\n        \"one_time_secret\": \"b7c2e91-A_z.9\"\n      }\n    ]\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.letsdeel.com/rest/gp/legal-entities/9a1f0e77-3c22-4b8d-8e64-2b0f5d9c1a44/payroll-migration-imports")

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  \"data\": {\n    \"files\": [\n      {\n        \"file_id\": \"V1StGXR8_Z5jdHi6B-myT\",\n        \"one_time_secret\": \"b7c2e91-A_z.9\"\n      }\n    ]\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.letsdeel.com/rest/gp/legal-entities/9a1f0e77-3c22-4b8d-8e64-2b0f5d9c1a44/payroll-migration-imports")
  .header("Authorization", "Bearer <token>")
  .header("Content-Type", "application/json")
  .body("{\n  \"data\": {\n    \"files\": [\n      {\n        \"file_id\": \"V1StGXR8_Z5jdHi6B-myT\",\n        \"one_time_secret\": \"b7c2e91-A_z.9\"\n      }\n    ]\n  }\n}")
  .asString();
```

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

$client = new \GuzzleHttp\Client();

$response = $client->request('POST', 'https://api.letsdeel.com/rest/gp/legal-entities/9a1f0e77-3c22-4b8d-8e64-2b0f5d9c1a44/payroll-migration-imports', [
  'body' => '{
  "data": {
    "files": [
      {
        "file_id": "V1StGXR8_Z5jdHi6B-myT",
        "one_time_secret": "b7c2e91-A_z.9"
      }
    ]
  }
}',
  'headers' => [
    'Authorization' => 'Bearer <token>',
    'Content-Type' => 'application/json',
  ],
]);

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

```csharp
using RestSharp;

var client = new RestClient("https://api.letsdeel.com/rest/gp/legal-entities/9a1f0e77-3c22-4b8d-8e64-2b0f5d9c1a44/payroll-migration-imports");
var request = new RestRequest(Method.POST);
request.AddHeader("Authorization", "Bearer <token>");
request.AddHeader("Content-Type", "application/json");
request.AddParameter("application/json", "{\n  \"data\": {\n    \"files\": [\n      {\n        \"file_id\": \"V1StGXR8_Z5jdHi6B-myT\",\n        \"one_time_secret\": \"b7c2e91-A_z.9\"\n      }\n    ]\n  }\n}", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
```

```swift
import Foundation

let headers = [
  "Authorization": "Bearer <token>",
  "Content-Type": "application/json"
]
let parameters = ["data": ["files": [
      [
        "file_id": "V1StGXR8_Z5jdHi6B-myT",
        "one_time_secret": "b7c2e91-A_z.9"
      ]
    ]]] as [String : Any]

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

let request = NSMutableURLRequest(url: NSURL(string: "https://api.letsdeel.com/rest/gp/legal-entities/9a1f0e77-3c22-4b8d-8e64-2b0f5d9c1a44/payroll-migration-imports")! 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()
```