Skip to main content

Limitations

This page lists the constraints that apply to the current version of the developer API. Each entry describes the behaviour to expect and the approach an integration should take.

Read it alongside Getting Started and Authentication before designing an integration. Several of these constraints affect how requests are sequenced, which is easier to allow for up front than to retrofit.

Error Messages​

An error response carries an HTTP status code and a message. The status code is the dependable part: it is documented in the reference and is stable for a given operation and outcome. The message is diagnostic. It does not always name the field that caused a validation failure, and its wording can change between releases.

An integration should branch on the status code and never on the text of a message. It should also log the full response body together with the request that produced it, which is the quickest way to work out why a call was rejected.

Where an operation returns a status code that does not match the outcome, it is noted under that resource below.

Response Schemas​

Each operation in the reference documents its parameters, its request body, and the status codes it can return. Response bodies are not currently described, so a response's schema and example panels can be empty or show a generic object.

Confirm the shape of a response by calling the operation in a non-production environment, and ignore response fields the integration does not recognise, as described in Versioning.

Authentication​

Every Authentication Failure Returns 403​

A missing, malformed, expired, or revoked token, a token without the required scope, and a token used against another organisation's path all return 403. The API does not return 401, so the status code alone cannot tell an expired token from a missing scope.

Request a new token once and retry the call once. If it fails again, check the key's permissions and the {organisationId} in the path rather than retrying further. See Cache and refresh the token.

The Token Response Is Not Standard OAuth​

The token endpoint uses the OAuth 2.0 client credentials grant, but its response is the standard response envelope with the token at data.accessToken. It has no access_token, expires_in, or token_type field, so generic OAuth client libraries cannot parse it without customisation. Read the expiry from the token's exp claim.

Editing a Key Signs Out Its Integrations​

Any change to a key in the Admin app, even renaming it, invalidates every access token already issued from it. Integrations recover by requesting a new token, but calls in flight at the moment of the change return 403.

Agentic​

Agent Config Is Only Available Once the Agent Is Live​

The get agent config operation returns the configuration of the agent's live version. An agent that has never gone live returns 409. Take the agent live in the Admin app first, and treat a 409 as a configuration problem rather than a transient failure.

Sessions Cannot Be Deleted or Edited​

There is no delete operation for sessions, and turns, tool calls, and events cannot be edited or removed once appended. Send only what the transcript should keep, and keep personal data out of content, input, and output unless the integration is allowed to store it.

A Reused Session ID Overwrites the Session​

The create session operation does not check whether sessionId is already in use. A request that reuses an ID replaces that session's record. Omit sessionId to have one generated, or generate a fresh UUID for each session.

Session Lists Are Not Paginated​

The list sessions and reports operations return every matching session in one response. Narrow reports with the from and to query parameters, which are Unix seconds and default to the last 24 hours.

Timestamps Are in Seconds​

Every timestamp, endedAt, from, and to value is a Unix time in seconds. Values sent in milliseconds are stored as sent and are not converted, so they sort and display incorrectly.

SCIM Configuration​

Profile IDs Are Not Verified in Amazon Connect​

routingProfileId and securityProfileIds, in both userMapping and defaultUserMapping, are checked for format only: each value must be a well-formed UUID. An ID that is well formed but does not correspond to a profile in the Amazon Connect instance is accepted and saved, and the mismatch only becomes apparent when SCIM next provisions a user.

Copy these IDs from Amazon Connect and confirm them before sending the configuration.

The Security Token Is Managed in the Admin App​

The SCIM security token cannot be read or set through the API. Every other part of the configuration can be, but the token itself is generated in the NeonNow Admin app and copied into the identity provider from there. See External Provisioning.

Custom Schedules​

Dates Are Added After the Schedule Is Created​

The create operation accepts name, timezone, and description. Dates and status are set by the update operation, so a schedule that contact flows can act on takes two calls: create it, then update it with its scheduledDates and status.

An Updated Field Is Replaced in Full​

The update operation works on whole fields. A field that is omitted is left unchanged, and a field that is supplied replaces its stored value completely.

This is most visible with scheduledDates: the array sent becomes the schedule's entire set of dates, so a single date cannot be added, edited, or removed on its own. Read the schedule, apply the change to the array it returns, and send that array back in full. The last write wins, so updates to one schedule should be sequenced rather than issued in parallel.

An Unknown Schedule Name Returns 500​

An update that names a schedule which does not exist returns 500 rather than 404. This is worth allowing for in retry logic: a 500 from this operation is not necessarily transient, and retrying it will not help if the name is wrong.

Confirm the schedule exists with the get or list operation before updating it.

Operational Parameters​

Table Columns Are Not Described in the Reference​

Every TABLE parameter defines its own columns in its tableSchema, so the reference describes a table row generically, as an object with arbitrary keys. Rows are still validated when they are sent, and a row that does not match the parameter's columns is rejected, but the reference cannot show what those columns are.

Read the parameter first and build rows from the tableSchema it returns.

Table Rows Are Replaced as a Complete Set​

The replace table rows operation saves exactly the array it is sent, and any row not included is removed. Individual rows cannot be appended, edited, or deleted.

Read the current rows, apply the change locally, then send the complete set. As with schedule dates, the last write wins, so writes to one parameter should be sequenced.

Custom Type Values Are Not Enforced in Table Rows​

Where a table column uses a custom type, row values are not checked against the values that type permits. A row can be saved with a value outside the list, and a contact flow reading that row will not resolve it as expected.

Validate row values against the list custom types operation before writing them.

An Update Must Send Both type and value​

The update operation leaves omitted fields unchanged, with one exception: type and value are validated as a pair. A request that changes value must send type as well, even when the type is not changing.

Read the parameter first and send its current type alongside the new value.

Custom Types Use Separate Operations​

The create and update operations for an operational parameter accept the built-in types only: BOOLEAN, TEXT, NUMBER, PHONE_NUMBER, QUEUE, and TABLE. A parameter typed with a custom type uses its own pair of operations:

POST /rest/v1/{organisationId}/{contactCenterId}/operational-parameter/custom
PATCH /rest/v1/{organisationId}/{contactCenterId}/operational-parameter/custom/{name}

They take the same fields as their built-in counterparts, so the only difference to account for is choosing the right path for the type being sent.

These operations do not check the value against the values the custom type permits, so validate it against the list custom types operation first.