> For the complete documentation index, see [llms.txt](https://docs.enate.net/enate-help/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.enate.net/enate-help/enate-apis-and-webhooks/apis.md).

# APIs

## Intro to Enate APIs

Enate has APIs that allow other systems to start, track and interact with work in Enate. Enate's APIs communicate via HTTPS GET and POST calls using the JSON data format.

Enate publishes two sets of APIs. Each has its own address on your Enate platform and its own Swagger page.

<table><thead><tr><th width="136">API</th><th width="322">Address</th><th>What it's for</th></tr></thead><tbody><tr><td>Operational API</td><td><code>https://yourplatform/operational</code></td><td>The work your teams do in Work Manager: creating and updating Tickets and Cases, working with Actions, contacts, files, emails and searching.</td></tr><tr><td>Configuration API</td><td><code>https://yourplatform/configuration</code></td><td>The configuration you manage in Builder: Service Lines, Calendars, Companies, Email Routes, user groups, Webhook subscriptions and so on.</td></tr></tbody></table>

Enate also supports Webhooks, which you can subscribe to so your system is updated on Enate activity in real-time. Check out the Webhooks section for more information:

{% content-ref url="/pages/-MWitakdiScHygZobBO9" %}
[Webhooks](/enate-help/enate-apis-and-webhooks/webhooks.md)
{% endcontent-ref %}

## Using Application Credentials to access Enate

Enate allows you to create Application Credentials to support multiple concurrent integrations into Enate via APIs. This approach has replaced the need to use standard Enate user accounts for authorized access to the system, which only supported one concurrent access. The Application Credentials records created in User Management section of Builder can be used to generate 'Bearer Tokens' which can be appended in the header of each API to grant access to Enate. Different permission levels can be granted to each Application Credential by selecting from a number of available 'Roles' when creating the Application Credential.

For more information on this, check out the Application Credentials page in the Builder section:

{% content-ref url="/pages/Mb17Q8b06ZFCsOKaKgtN" %}
[Application Credentials](/enate-help/builder/builder/user-management/application-credentials.md)
{% endcontent-ref %}

For how a token behaves once you have it, including how long it lasts, what it's allowed to do and what Enate returns when it's refused, see the API Authentication page:

{% content-ref url="/pages/70HdLoQbouliiyFCvgaG" %}
[API Authentication](/enate-help/enate-apis-and-webhooks/apis/api-authentication.md)
{% endcontent-ref %}

## Swagger - Enate's Interactive API Documentation

If you've got access to an existing Enate environment, you can open interactive documentation for Enate's APIs using your Swagger link. The link is unique to your environment. For example:

**Operational API:** [**https://yourplatform/operational/swagger**](https://yourplatform/operational/swagger)

**Configuration API:** [**https://yourplatform/configuration/swagger**](https://yourplatform/configuration/swagger)

More general information on Swagger can be found [here](https://swagger.io/docs/specification/v3_0/about/).

Each Swagger page has one document for every API version your environment provides. You choose the version from the definition list at the top right of the page. Enate lists the latest stable version first and selects it by default, and a preview version carries a `-preview` suffix, such as `V4-PREVIEW`. Use the Authorize button to sign in with an Application Credential's Client ID and Secret Key and try requests from Swagger itself.

Swagger lists the endpoints Enate supports for integrations, apart from the authentication ones, and it's the definitive description of each one: its route, parameters, request and response structure and the status codes it can return. This documentation covers the behaviour that applies across all of them.

{% hint style="warning" %}
Only call endpoints that appear in Swagger. Enate's APIs also contain private APIs, which are the endpoints Work Manager and Builder use for their own screens. Private APIs aren't listed in Swagger and aren't supported for integrations, and they can change or be removed without notice, even within a version that's otherwise frozen.
{% endhint %}

## Making a Request

Every address has the same shape:

```
https://yourplatform/<api>/<Controller>/<Action>?api-version=4
```

| Part           | What it is                                                                           |
| -------------- | ------------------------------------------------------------------------------------ |
| `yourplatform` | Your Enate URL.                                                                      |
| `api`          | `operational` for the Operational API, or `configuration` for the Configuration API. |
| `Controller`   | The group of operations, such as `Ticket`, `Case`, `Calendar` or `Schedule`.         |
| `Action`       | What you want to do, such as `Create` or `Get`.                                      |
| `api-version`  | The version of the API you want to use. See Choosing an API Version below.           |

For example, `POST https://yourplatform/operational/Ticket/Create?api-version=4` creates a Ticket, and `GET https://yourplatform/configuration/Calendar/GetAll?api-version=4` lists the Calendars in your Enate environment.

* Enate uses two HTTP methods. **GET** reads data. **POST** creates, updates or deletes it. There are no PUT, PATCH or DELETE operations, so deleting something is a POST, such as `WebHookSubscription/Unsubscribe`.
* Send your Bearer Token in the `Authorization` header: `Authorization: Bearer <your token>`.
* Send request bodies as JSON, with the header `Content-Type: application/json`. Responses use PascalCase property names, such as `TicketAttributeVersionGUID`. Property names in a request aren't case sensitive, but sending them as Swagger shows them keeps your requests and responses consistent.
* Enate's responses use the same JSON format. Most create and update operations return the object and a list of validation messages in one response.

The API Request and Response Conventions page covers the rules for requests and responses in detail, and the API Errors and Status Codes page lists what Enate returns when something goes wrong:

{% content-ref url="/pages/7higrINDVhsCeIUgg08S" %}
[API Request and Response Conventions](/enate-help/enate-apis-and-webhooks/apis/api-request-and-response-conventions.md)
{% endcontent-ref %}

{% content-ref url="/pages/JlIMonf1Oe8RGGRS5erd" %}
[API Errors and Status Codes](/enate-help/enate-apis-and-webhooks/apis/api-errors-and-status-codes.md)
{% endcontent-ref %}

To see all of this working together, the quick start takes you from an Application Credential to a Ticket created through the Operational API:

{% content-ref url="/pages/edVe3tJZq0OPjjlIAj5s" %}
[API Quick Start: Create a Ticket](/enate-help/enate-apis-and-webhooks/apis/api-quick-start-create-a-ticket.md)
{% endcontent-ref %}

## Choosing an API Version

Enate's APIs are versioned. You choose the version you want with the `api-version` query string parameter on every request:

```
POST https://yourplatform/operational/Ticket/Create?api-version=3
```

The latest stable version of the Operational and Configuration APIs depends on the feature wave your environment is running, and so do the other versions available alongside it:

| Feature Wave | Latest stable version | Other versions available | Preview version                         |
| ------------ | --------------------- | ------------------------ | --------------------------------------- |
| July 2026    | 3                     | 1 and 2                  | 4, requested as `api-version=4-preview` |
| October 2026 | 4                     | 2 and 3                  | None                                    |

Earlier versions stay available so that an existing integration keeps working when Enate releases a new one, but they don't stay available forever. Version 1 is not available in the October 2026 feature wave, and Enate rejects a request that asks for it. If you have an integration pinned to version 1, move it to a later version before your environment moves to the October 2026 feature wave. The [Upgrading API versions](/enate-help/enate-apis-and-webhooks/apis/upgrading-api-versions.md) pages tell you what to change for each move. Swagger shows you which versions your own environment provides, in the definition list at the top right of each Swagger page.

You choose the version with the query string parameter only. Enate doesn't read the version from a request header, so a version sent in a header is ignored and the request is treated as though it had no version at all.

If you leave the `api-version` parameter off a request, Enate doesn't reject it. It applies the latest stable version instead, and as the table shows that's a moving target: an environment that moves from the July 2026 wave to the October 2026 wave starts resolving unversioned requests to version 4 rather than version 3.

{% hint style="warning" %}
**Send `api-version` explicitly on every request.** Leaving it off means Enate decides when your integration moves to a new request and response format, rather than you deciding. Pin the version you've built and tested against, and change it when you're ready.
{% endhint %}

A preview version lets you see what's coming in the next version of the API. It's marked as a preview in Swagger, and it can still change before it's released, so don't build a production integration against it.

{% hint style="info" %}
Enate doesn't return the available versions in a response header. Swagger is the place to see which versions your environment provides.
{% endhint %}

A value that a newer version returns can be one that an older version has no member for. See the API Enums page for what happens when you ask an older version for data it can't express:

{% content-ref url="/pages/-McjNI1qFp\_MXXsb03k\_" %}
[API Enums](/enate-help/enate-apis-and-webhooks/apis/api-enums.md)
{% endcontent-ref %}

The API Changes page lists what changed between versions, including the changes that can break an integration when you move to a newer version:

{% content-ref url="/pages/1DH9uE1vBH3GiHRi4vrK" %}
[API Changes](/enate-help/enate-apis-and-webhooks/apis/api-changes.md)
{% endcontent-ref %}

When you're ready to move an integration to a newer version, start from Upgrading API versions. It has a page for each journey, such as version 3 to version 4, with the changes to make and how to test them:

{% content-ref url="/pages/7bYJxQEI6RUCite7VtrV" %}
[Upgrading API versions](/enate-help/enate-apis-and-webhooks/apis/upgrading-api-versions.md)
{% endcontent-ref %}

## Limit on Custom Data

A Ticket, Case or Action can hold up to 2,000 pieces of custom data. The calls that save a work item's custom data refuse a request that adds rows to a custom data table and would leave the work item over that limit. Enate counts one piece for each custom data field that isn't in a table and one piece for each cell of a custom data table, so a table of 200 rows and 10 columns is 2,000 pieces. The full counting rules are on the Maximum Limits in Enate page, linked at the end of this section.

| Behaviour                        | Detail                                                                                                                                                                              |
| -------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Calls that check the limit       | The Update call for Tickets, Cases and Actions, and the Ticket and Case calls that accept the same request body, for example SetWaiting, SetInProgress, SetToDo, Resolve and Reject |
| What is refused                  | A request that adds rows to a custom data table and leaves the work item with more than 2,000 pieces. Nothing in the request is saved                                               |
| What is not refused              | A request that adds no table rows, or removes at least as much custom data as it adds. Creating a work item, including with the Create calls, isn't checked                         |
| Work item already over the limit | Still accepts requests that assign it, progress it, edit it, or reduce its custom data                                                                                              |
| Is the request safe to retry     | No. The same request will be refused again until you send fewer rows                                                                                                                |

### What you get back

On version 4, a refused request returns 400 Bad Request with `Result` set to null and one validation message:

| Field                | Type                         | Required | Description                                                        |
| -------------------- | ---------------------------- | -------- | ------------------------------------------------------------------ |
| `Result`             | Object                       | Optional | Null where the request was refused and nothing was saved           |
| `Messages`           | Array of validation messages | Optional | The validation messages raised by the request                      |
| `MessageID`          | Integer                      | Required | 828023, the enumeration value for `PacketCustomData_LimitExceeded` |
| `MessageDescription` | String                       | Required | "This Packet has more custom data than the limit allows."          |
| `Parameters`         | Array                        | Required | Empty for this message, because the text has no placeholders       |
| `IsError`            | Boolean                      | Required | True, because the request was refused and nothing was saved        |

Earlier versions are frozen and have no member for 828023. A request to version 3 or earlier that breaches the limit is refused with the 400 text response described on the [API Enums](/enate-help/enate-apis-and-webhooks/apis/api-enums.md#when-a-value-cant-be-expressed-in-your-api-version) page, instead of a validation message. That response names `PacketCustomData_LimitExceeded` and `PacketValidatorMessage`, which is how you can recognise it.

### Worked example: adding a row to the Approvers table

A Case holds 1,998 pieces of custom data. One of its custom data tables is Approvers, which has three columns (ApproverName, ApproverEmail and ApprovalLevel, using the Safe Names from Builder) and two rows stored. The integration sends the whole table back with a third row added. To keep the example short, the request below shows only `GUID` and `DataFields`. A real `Case/Update` sends every property the operation accepts, copied from `Case/Get`, because a property you leave out is reset to its default. See [API Request and Response Conventions](/enate-help/enate-apis-and-webhooks/apis/api-request-and-response-conventions.md).

```
POST https://yourplatform/operational/Case/Update?api-version=4
```

```json
{
  "GUID": "5d0c7f3e-2b6a-4e1f-9a84-3c7b1e9d6a52",
  "DataFields": {
    "Approvers": [
      {
        "ApproverName": "Priya Nair",
        "ApproverEmail": "priya.nair@globex.example.com",
        "ApprovalLevel": 1
      },
      {
        "ApproverName": "Tom Becker",
        "ApproverEmail": "tom.becker@globex.example.com",
        "ApprovalLevel": 2
      },
      {
        "ApproverName": "Elena Rossi",
        "ApproverEmail": "elena.rossi@globex.example.com",
        "ApprovalLevel": 3
      }
    ]
  }
}
```

The third row is new and adds three pieces, so the Case would hold 2,001. Enate refuses the request:

```http
HTTP/1.1 400 Bad Request
```

```json
{
  "Result": null,
  "Messages": [
    {
      "MessageID": 828023,
      "IsError": true,
      "MessageDescription": "This Packet has more custom data than the limit allows.",
      "Parameters": []
    }
  ]
}
```

Nothing in the request was saved, including any other changes it carried. Sending the same request again returns the same response. To carry on, send fewer rows, for example the original two, or remove rows from one of the Case's tables in the same request so that the total stays at 2,000 or below.

Send the request to version 3 instead (`api-version=3`) and the same breach returns the plain text response for an unsupported value:

```http
HTTP/1.1 400 Bad Request
Content-Type: text/plain; charset=utf-8

'PacketCustomData_LimitExceeded' is not a value that this version of the API can return for PacketValidatorMessage. Use the latest version of the API to read this data.
```

For the table of every limit in the platform, see Maximum Limits in Enate:

{% content-ref url="/pages/oPSb2TTA4ot02bdzLFLq" %}
[Maximum Limits in Enate](/enate-help/builder/builder/maximum-limits-in-enate.md)
{% endcontent-ref %}

## Rate Limiting

Enate's APIs are rate limited, so that one busy integration can't slow the platform down for everyone else using the same Enate environment. The limit is applied to your Enate environment and to each caller within it, and it's counted on a sliding window, so Enate looks at the requests received during the preceding minute rather than resetting a counter on the minute boundary.

Enate counts requests in two groups, each with its own allowance:

| Requests                                                                                                                                                | Default requests per minute |
| ------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------- |
| Requests with a Bearer Token: calls to the Operational and Configuration APIs, whether they come from your integration or from Work Manager and Builder | 1,000                       |
| Sign-in and token requests, and calls to the legacy API                                                                                                 | 10,000                      |

The second group is every request that doesn't present a Bearer Token from the Authentication API. These requests still authenticate, but in other ways:

* A user signing in to Work Manager or Builder, whether with a user name and password or through single sign-on.
* An integration getting a token, by sending its Client ID and Secret Key to the token address.
* Every call to the legacy API. These count in this group even though they carry a token, so an integration that still uses the legacy API draws on the 10,000 rather than the 1,000.

Everything else counts towards the 1,000, including the requests Work Manager and Builder make on behalf of your users. If your integration runs against the same Enate environment that your operational teams are working in, you're sharing the allowance with them.

### What happens when you exceed the limit

Enate rejects the request with HTTP **429 Too Many Requests**. Nothing is processed, so a rejected request has no effect on your data and is safe to send again.

Two things to design around:

* **Enate doesn't tell you how long to wait.** There's no `Retry-After` header and no response body describing the limit, your current usage or when the window clears. Use this pattern instead:
  1. After a 429, wait a random interval of between 1 and 6 seconds, then send the same request again.
  2. If that's rejected too, pause for 60 seconds before you send anything else. The limit is counted over the preceding minute, so a full minute's pause lets the window clear.
  3. Then carry on at a lower rate than before.
* **Enate doesn't distinguish between callers, or between test and live.** A request made against a process version in Testing state is counted exactly like a live one, and a burst from one Application Credential can use up the allowance that another integration is relying on. If you're load testing an integration, do it against a non production Enate environment.

Work Manager and Builder handle a 429 themselves. They retry the request once after a random delay of between one and six seconds, and if that retry is also rejected the user sees the message "You have sent too many requests to a server within a given timeframe." A rate limited user is never signed out.

### Staying inside the limit

* Retry with a random backoff rather than immediately. Retrying the instant you're rejected sends the second request while the sliding window is still full, and several clients retrying on the same fixed interval will keep colliding with each other.
* Send bulk work sequentially, or at low parallelism, rather than firing every request at once. A loop that creates 2,000 Tickets as fast as it can will be rate limited part way through; the same loop paced across a few minutes won't be.
* Avoid polling wherever you can. [Subscribe to a Webhook](/enate-help/enate-apis-and-webhooks/webhooks.md) and let Enate tell you when something has changed, rather than asking repeatedly and spending the allowance on responses that haven't changed. Where you genuinely have to poll, poll on a schedule that reflects how often the data actually changes, not as often as the limit allows.
* Cache values that rarely change, such as Service and Process configuration, for the life of your integration run instead of re-reading them for every work item.

### Worked example: creating Tickets in bulk

An integration creating 2,000 Tickets from an overnight file, using one Application Credential, would:

1. Request a Bearer Token once and reuse it, rather than authenticating per Ticket.
2. Read the Service and Process configuration it needs once, and hold it for the run.
3. `POST /Ticket/Create?api-version=4` for each row, in sequence.
4. On a 429, wait a random interval of between 1 and 6 seconds, then send the same request again. The Ticket wasn't created, so the retry can't produce a duplicate.
5. On a second consecutive 429 for the same row, pause the run for 60 seconds before continuing, rather than continuing to retry.

At the default of 1,000 requests a minute, the create calls alone take a minimum of two minutes for a file of that size, so build the schedule around the whole run taking several minutes rather than expecting it to finish instantly. Handle the 429 rather than tuning your sender to the exact number, because the number is a default and your environment may not be on it.

Limits that apply across the rest of the platform, including Webhook delivery, are listed on the Maximum Limits in Enate page:

{% content-ref url="/pages/oPSb2TTA4ot02bdzLFLq" %}
[Maximum Limits in Enate](/enate-help/builder/builder/maximum-limits-in-enate.md)
{% endcontent-ref %}

## Sample Integration Patterns Using Enate's API's

{% content-ref url="/pages/-MfY7fKX1YUUX8c7NMnz" %}
[Create a Webform that turns requests into Tickets with Enate's APIs](/enate-help/integrations/enate-integrations/api-sample-webform-front-end-to-post-tickets.md)
{% endcontent-ref %}


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.enate.net/enate-help/enate-apis-and-webhooks/apis.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
