> 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.

# Amendment Lifecycle

> Create, update, validate, confirm, cancel, accept, sign, and retrieve amendments

## Create a draft amendment

Create a new draft amendment by specifying the `contract_id`. You can include all, some, or none data points you plan to amend. This allows you to start with a basic amendment and add more details later.

```shell
curl --location -g --request POST '{{host}}/rest/eor/contracts/{{contract_id}}/amendments' \
--header 'Authorization: Bearer {{token}}' \
--header 'Content-Type: application/json' \
--data-raw '{
    "data": {
    }
}'
```

OR

```shell
curl --location -g --request POST '{{host}}/rest/eor/contracts/{{contract_id}}/amendments' \
--header 'Authorization: Bearer {{token}}' \
--header 'Content-Type: application/json' \
--data-raw '{
    "data": {
        "time_off_type": "SPECIFIC",
        "holidays": 12,
        "employment_type": "PART_TIME"
    }
}'
```

## Update existing draft amendment

Update an existing draft amendment by including the `amendment_id` returned when the amendment was created. You can add additional data points, modify existing ones, or set the effective date. This endpoint allows you to build your amendment incrementally.

> **Warning**
>
> Updating an amendment replaces its full set of data points. Each update request must contain all the data points you want to keep, not just the one you’re changing.
> If you only send the newly updated data point, any previously saved data points that are not included will be removed from the amendment.

```shell
curl --location -g --request PATCH '{{host}}/rest/eor/contracts/{{contract_id}}/amendments/{{amendment_id}}' \
--header 'Authorization: Bearer {{token}}' \
--header 'Content-Type: application/json' \
--data-raw '{
    "data": {
        "time_off_type": "SPECIFIC",
        "holidays": 12,
        "employment_type": "PART_TIME",
        "effective_date": "2025-08-01",
    }
}'
```

## Amendment validation approaches

The amendment submission endpoint always validates the request, so pre-validation is optional. You'd add it when you want to give the user inline feedback before they submit, or when a field is gated by AI or country-specific rules that can't be reproduced in the browser.

Where you validate a field depends on its `external_validation` flag in the [amendment settings endpoint](/api/reference/endpoints/eor-amendments/get-contract-amendments-validation-settings) response. When `external_validation: false`, the field is a simple enum or numeric bound that the settings endpoint already describes, so you can validate it client-side for immediate feedback. When `external_validation: true`, the field goes through AI job-scope checks, job categorization, or country-specific rules that only the [validate amendment endpoint](/api/reference/endpoints/eor-amendments/validate-eor-amendments) can evaluate, so it requires a server-side call.

### Hybrid approach (recommended)

For production integrations, combine the two: validate `external_validation: false` fields client-side using the rules from the amendment settings endpoint, and validate `external_validation: true` fields server-side by calling the validate amendment endpoint. This gives you immediate feedback for cheap validations while still running the checks that only the server can do; the server response also returns the AI job scope check and job categorization results when applicable.

### Validate amendment data points

Use the [validate amendment](/api/reference/endpoints/eor-amendments/validate-eor-amendments) endpoint to validate amendment data points before submission.

```shell
curl --location --request POST '{{host}}/rest/eor/contracts/{{contract_id}}/amendments/validate' \
--header 'Authorization: Bearer {{token}}' \
--header 'Content-Type: application/json' \
--data-raw '{
    "data": {
        "job_title": "Senior Software Engineer",
        "scope": "Lead development of web applications"
    }
}'
```

#### Response format

The response includes validation results with field-specific error mapping:

```json
{
  "data": {
    "is_valid": true,
    "validation_error": [],
    "disabled_amendments": [],
    "ai_job_scope_and_title_check": {
      "is_valid": true,
      "ai_scope_check_public_id": "9f9e086f-2195-4ced-a641-c62d5cd388fc"
    },
    "job_categorization": {
      "is_valid": true,
      "job_categorization_log_id": "366681cd-fe16-4be7-9e45-692a4bbc91c0",
      "job_category": "Software Engineer",
      "job_code": "214129"
    }
  }
}
```

#### Error response with field mapping

When validation fails, errors include a `field` parameter for easy frontend integration:

```json
{
  "data": {
    "is_valid": false,
    "validation_error": [
      {
        "code": "AMENDMENT_ITEM_VALIDATION_FAILED",
        "message": "Scope exceeds maximum length of 20,000 characters",
        "field": "scope",
        "details": {
          "newValue": "Very long scope description...",
          "previousValue": "Short scope"
        }
      }
    ],
    "disabled_amendments": [],
    "ai_job_scope_and_title_check": null,
    "job_categorization": null
  }
}
```

### Seniority ID

To amend `seniority_id`:

#### Retrieve seniority levels

Use the [Get Seniority List](/api/reference/endpoints/lookups/get-seniority-levels) endpoint to get available levels.

#### Include in the amendment request

Add the selected `seniority_id` to your amendment request body.

### Effective date limitations

#### Create an amendment

Use the [Create Amendment](/api/reference/endpoints/eor-amendments/create-contract-amendment) endpoint.

#### Fetch effective date limits

Call the [Get Effective Date Limitations](/api/reference/endpoints/eor-amendments/get-contract-amendment-effective-date-limitations) endpoint.

#### Set the date in your UI

Use the returned rules to configure the date picker or apply the default.

#### Submit with effective date (optional)

Include the effective date in the amendment request if required.

### AI job scope check and job categorization

#### AI review check

When you create or update a job title or scope amendment, Deel automatically runs an AI review check to confirm the new title and scope are consistent with the existing job description and responsibilities. To avoid surprises at submission time, call the [validate amendment](/api/reference/endpoints/eor-amendments/validate-eor-amendments) endpoint first so you can inspect the AI check status before proceeding.

A successful validation returns an `ai_scope_check_public_id`. Include this ID in the amendment request body so the AI check result carries over and the amendment skips manual review. You can still submit without pre-validating, but if the AI check then fails, the amendment is flagged for manual review by Deel's internal team before it can proceed.

### Validate job title and scope

Use the [validate amendment](/api/reference/endpoints/eor-amendments/validate-eor-amendments) endpoint:

```json
{
  "url": "https://api.letsdeel.com/rest/eor/contracts/{{contract_id}}/amendments/validate",
  "method": "POST",
  "headers": {
    "accept": "application/json",
    "Content-Type": "application/json",
    "Authorization": "Bearer {API_TOKEN}"
  },
  "body": {
    "data": {
      "job_title": "Senior Software Manager"
    }
  }
}
```

Response:

```json
{
  "data": {
    "is_valid": true,
    "validation_error": [],
    "disabled_amendments": [],
    "ai_job_scope_and_title_check": {
      "is_valid": true,
      "ai_scope_check_public_id": "9f9e086f-2195-4ced-a641-c62d5cd388fc"
    },
    "job_categorization": null
  }
}
```

### Submit with the AI scope check ID

Include `ai_scope_check_public_id` from the validation response:

```json
{
  "url": "https://api.letsdeel.com/rest/eor/contracts/{{contract_id}}/amendments/{{amendment_id}}",
  "method": "PATCH",
  "headers": {
    "accept": "application/json",
    "Content-Type": "application/json",
    "Authorization": "Bearer {API_TOKEN}"
  },
  "body": {
    "job_title": "Senior Software Manager",
    "additional_info": {
      "ai_scope_check_public_id": "9f9e086f-2195-4ced-a641-c62d5cd388fc"
    }
  }
}
```

#### Job categorization with AI recommendations

Job categorization is only available for specific countries. The following table lists where it is supported and what the AI generates per country:

| Country  | AI Generates          |
| -------- | --------------------- |
| Bulgaria | Job code and category |
| Latvia   | Job code and category |
| Romania  | Job code and category |
| Ukraine  | Job category          |

* Every time a job title is amended, an AI job categorization is triggered to classify the new job title into a predefined job category and code.
* You can trigger the [validate amendment](/api/reference/endpoints/eor-amendments/validate-eor-amendments) endpoint for the AI job categorization to be performed before creating or updating the job title amendment.
* You can submit the amendment regardless of the AI job categorization outcome, but if the AI job categorization fails, the amendment will be flagged for manual review by Deel's internal team.
* You will get `job_categorization_log_id` when using [validate amendment](/api/reference/endpoints/eor-amendments/validate-eor-amendments) endpoint if the AI job categorization succeeds, which can be used to track the review status.
* You will also get `job_code` and `job_category` along with `job_categorization_log_id` in the response if the AI job categorization succeeds.
* You need to send this `job_categorization_log_id` and `job_code` and `job_category` in create or update amendment request so it won't require any manual review.

### Validate job title

Use the [validate amendment](/api/reference/endpoints/eor-amendments/validate-eor-amendments) endpoint:

```json
{
  "url": "https://api.letsdeel.com/rest/eor/contracts/{{contract_id}}/amendments/validate",
  "method": "POST",
  "headers": {
    "accept": "application/json",
    "Content-Type": "application/json",
    "Authorization": "Bearer {API_TOKEN}"
  },
  "body": {
    "data": {
      "job_title": "Senior Software Manager"
    }
  }
}
```

Response:

```json
{
  "data": {
    "is_valid": true,
    "validation_error": [],
    "disabled_amendments": [],
    "ai_job_scope_and_title_check": {
      "is_valid": false,
      "message": "Job scope is too short"
    },
    "job_categorization": {
      "is_valid": true,
      "job_categorization_log_id": "366681cd-fe16-4be7-9e45-692a4bbc91c0",
      "job_category": "Manager, Software Development",
      "job_code": "13306011"
    }
  }
}
```

### Submit with the job categorization ID

Include `job_categorization_log_id`, `job_code`, and `job_category` from the validation response:

```json
{
  "url": "https://api.letsdeel.com/rest/eor/contracts/{{contract_id}}/amendments/{{amendment_id}}",
  "method": "PATCH",
  "headers": {
    "accept": "application/json",
    "Content-Type": "application/json",
    "Authorization": "Bearer {API_TOKEN}"
  },
  "body": {
    "job_title": "Senior Software Manager",
    "additional_info": {
      "job_categorization_log_id": "366681cd-fe16-4be7-9e45-692a4bbc91c0"
    },
    "job_category": "Manager, Software Development",
    "job_code": "13306011"
  }
}
```

When you trigger the [validate amendment](/api/reference/endpoints/eor-amendments/validate-eor-amendments) endpoint for job title amendments:

* In countries where job categorization is supported:
  * Both AI check and job categorization run.
  * You must send `ai_scope_check_public_id` and `job_categorization_log_id` together with `job_code` and `job_category` in the update amendment request to avoid manual review.
* In countries where job categorization is not supported:
  * Only AI check runs.

#### Update amendment with both `ai_scope_check_public_id` and `job_categorization_log_id`

Use this request to update an amendment with both the AI check and job categorization identifiers:

```json
{
  "url": "https://api.letsdeel.com/rest/eor/contracts/{{contract_id}}/amendments/{{amendment_id}}",
  "method": "PATCH",
  "headers": {
    "accept": "application/json",
    "Content-Type": "application/json",
    "Authorization": "Bearer {API_TOKEN}"
  },
  "body": {
    "job_title": "Senior Software Manager",
    "additional_info": {
      "ai_scope_check_public_id": "9f9e086f-2195-4ced-a641-c62d5cd388fc",
      "job_categorization_log_id": "366681cd-fe16-4be7-9e45-692a4bbc91c0"
    },
    "job_category": "Manager, Software Development",
    "job_code": "13306011"
  }
}
```

## Validation errors and disabled amendments

Amendment requests can fail if validation rules are not met. In these cases, the API returns an error response that includes details about validation errors and disabled data points.

### Standard error format

Error responses follow a consistent format that is easy to interpret and integrate. Every error includes a `code` and a `message`. The optional `field` attribute identifies which input caused the error when applicable, and an optional `details` object carries additional context.

Mandatory fields:

| Field              | Type   | Description                  | Example                                |
| ------------------ | ------ | ---------------------------- | -------------------------------------- |
| `errors`           | array  | Array of error objects       | `[{...}]`                              |
| `errors[].code`    | string | Error code identifier        | `"VALIDATION_ERROR"`                   |
| `errors[].message` | string | Human-readable error message | `"Internal validation error occurred"` |

Optional fields

| Field              | Type   | Description                                            | Example                                          |
| ------------------ | ------ | ------------------------------------------------------ | ------------------------------------------------ |
| `errors[].field`   | string | Field name that caused the error                       | `"effective_date"`                               |
| `errors[].details` | object | Additional error context in free-form object structure | `{"previousValue": "96000", "newValue": "3000"}` |

### Common amendment error codes

| Error Code                                                                                                            | Description               | HTTP Status |
| --------------------------------------------------------------------------------------------------------------------- | ------------------------- | ----------- |
| `VALIDATION_ERROR`, `AMENDMENT_ERROR`                                                                                 | Request validation failed | 400         |
| `NOT_FOUND`, `CONTRACT_NOT_FOUND`, `AMENDMENT_NOT_FOUND`                                                              | Resource not found        | 404         |
| `AMENDMENT_CREATION_FAILED`, `AMENDMENT_UPDATE_FAILED`, `AMENDMENT_ITEM_DISABLED`, `AMENDMENT_ITEM_VALIDATION_FAILED` | Field validation failed   | 422         |
| `FORBIDDEN`                                                                                                           | Insufficient permissions  | 403         |
| `CHANGE_REQUEST_CONFIRMED`, `RESOURCE_CONFLICT`                                                                       | Resource conflict         | 409         |
| `INTERNAL_ERROR`                                                                                                      | Server error              | 500         |

### Error response examples

The following examples show the different types of validation and amendment errors you may encounter.

#### Request validation errors

Returned when the request payload fails general validation checks.

```json
{
  "errors": [
    {
      "code": "VALIDATION_ERROR",
      "message": "Internal validation error occurred"
    }
  ]
}
```

#### General amendment errors

Returned when the amendment request cannot proceed due to one or more issues.

```json
{
    "errors": [
        {
            "message": "Amendment already in progress with ID: 5ea6c745-3f40-4fc8-864e-026ccae666e1",
            "code": "AMENDMENT_ERROR"
        }
    ]
}
```

#### Amendment field validation errors and disabled amendments

Returned when specific fields are invalid or disabled for the requested amendment.

```json
{
    "errors": [
        {
            "message": "Job title is not enabled for white label API",
            "code": "AMENDMENT_ITEM_DISABLED",
            "field": "jobTitle"
        },
        {
            "message": "Minimum salary for United Kingdom is $30,312.07",
            "code": "AMENDMENT_ITEM_VALIDATION_FAILED",
            "field": "salary",
            "details": {
                "previousValue": "96000.0000",
                "newValue": "3000"
            }
        }
    ]
}
```

#### Amendment processing failed errors

Returned when an amendment cannot be updated or confirmed.

```json
{
  "errors": [
    {
      "code": "AMENDMENT_UPDATE_FAILED",
      "message": "Failed to update amendment",
      "field": "amendment"
    }
  ]
}
```

```json
{
  "errors": [
    {
      "code": "CHANGE_REQUEST_CONFIRMED",
      "message": "Change request is already confirmed",
      "field": "changeRequestId"
    }
  ]
}
```

## Confirm an amendment

To confirm a draft amendment, use the `contract_id` and `amendment_id`. Only draft amendment can be confirmed.

After confirmation, the flow depends on the amendment type. If the type is instant, the amendment becomes active immediately. If it requires signatures, Deel or the employee must approve it first.

```shell
curl --location -g --request POST '{{host}}/rest/eor/contracts/{{contract_id}}/amendments/{{amendment_id}}/confirm' \
--header 'Authorization: Bearer {{token}}'
```

## Cancel an amendment

To cancel an amendment, use the `contract_id` and `amendment_id`. You can cancel an amendment any time before the employee signs it. After cancellation, you can delete it if needed.

```shell
curl --location -g --request DELETE '{{host}}/rest/eor/contracts/{{contract_id}}/amendments/{{amendment_id}}' \
--header 'Authorization: Bearer {{token}}'
```

## Download an amendment PDF

Retrieve the download URL for the Statement of Work (Employee Agreement, EA) of a confirmed amendment. The URL is available only after the amendment is confirmed and the contract is in progress.

> **Note**
>
> The download URL expires after 15 minutes.

```shell
curl --location -g --request GET '{{host}}/rest/eor/contracts/{{contract_id}}/amendments/{{amendment_id}}/pdf' \
--header 'Authorization: Bearer {{token}}'
```

## Accept an amendment

Use this endpoint to accept an amendment submitted by a Deel admin.

After acceptance, the amendment either becomes active immediately or moves to the signature step, depending on its type.

```shell
curl --location -g --request POST '{{host}}/rest/eor/contracts/{{contract_id}}/amendments/{{amendment_id}}/accept' \
--header 'Authorization: Bearer {{token}}'
```

## Sign an approved amendment

An employee can sign an amendment approved by both the client and admin. After signing, the amendment becomes active.

```shell
curl --location -g --request POST '{{host}}/rest/eor/contracts/{{contract_id}}/amendments/{{amendment_id}}/sign' \
--header 'Authorization: Bearer {{token}}'
```

## Retrieve the list of amendments

Retrieve all amendments for a specific contract.

```shell
curl --location -g --request GET '{{host}}/rest/eor/contracts/{{contract_id}}/amendments' \
--header 'Authorization: Bearer {{token}}'
```

## Retrieve a specific amendment

Retrieve details of a specific amendment

```shell
curl --location -g --request GET '{{host}}/rest/eor/contracts/{{contract_id}}/amendments/{{amendment_id}}' \
--header 'Authorization: Bearer {{token}}'
```