Optimized App API (2.0.1)

API for managing profiles, batches, and campaign scheduling in Optimized.App.

Introduction

To begin utilizing Optimized.App, it's essential to:

  1. Obtain an API Token Access to the API is granted only through a valid API Token. Note: API Tokens can only be created by an organization administrator. You can generate your token via the Organization Settings section, under Integration -> Api Tokens on the Optimized.App dashboard.

  2. Understand Rate and Usage Limits Optimized.App has specific rate and usage limitations. Familiarize yourself with these to ensure uninterrupted service.

  3. Secure Communication Protocol Optimized.App mandates the use of HTTPS-secured communications. Any requests sent via HTTP return an HTTP 301 redirect to the corresponding HTTPS resources.

  4. Response Format All responses from Optimized.App are provided in JSON format, ensuring a standardized and easy-to-parse structure for your applications.

  5. All datetime values in requests and responses are in UTC timezone. Responses are formatted according to ISO 8601 standard (YYYY-MM-DDThh:mm:ss.sssZ).

By following these guidelines, you'll be set to effectively integrate and work with Optimized.App's API.

Authentication

To begin utilizing Optimized.App, it's essential to:

  1. Obtain an API Token Access to the API is granted only through a valid API Token. Note: API Tokens can only be created by an organization administrator. You can generate your token via the Organization Settings section, under Integration -> Api Tokens on the Optimized.App dashboard.

You must include an API token in each request to the Optimized.App API with the Authorization request header.

Example: Authorization: Bearer [API-TOKEN]

If an API token is missing, malformed, or invalid, you will receive an HTTP 401 Unauthorized response code.

Rate and Usage Limits

The basic rate limit is 250 requests per minute per user basis. Also, depending on your plan, you may have different usage limits. If you exceed either limit, your request will return an HTTP 429 Too Many Requests status code.

The following set of headers are returned on the response to help you identify your use status:

HeaderDescription
X-Ratelimit-LimitThe maximum number of requests that the consumer is permitted to make per minute.
X-Ratelimit-RemainingThe number of requests remaining in the current rate limit window.
X-Ratelimit-ResetThe time at which the current rate limit window resets in UTC epoch seconds. This header is only present when maximum number of requests has been consumed for time period.

Endpoint Specific Rate Limits

EndpointDescription
Profile importing with schedulingThis is a group based rate limit for 10 requests per minute.

Errors

Optimized.App employs standard HTTP response codes to signify the outcome of an API request. Typically, codes within the 2xx range signify a successful operation. Codes within the 4xx range point to an error coming from the provided information (for example, missing a necessary parameter or having invalid data). Codes in the 5xx range are indicative of issues with Optimized.App servers, though these occurrences are uncommon.

HTTP status codeDescription
200Request was made successfully.
201Request was made successfully and a resource was created.
400The request was rejected, often due to missing a required parameter.
401API token is not valid.
403API token has no permission to perform the request.
404The requested resource does not exist.
422The request was rejected, often due to invalid client data.
429Too many requests hit the API too quickly. We advise implementing an exponential backoff strategy for your requests.
500Something went wrong on our end.
503An unexpected spike in API access traffic. The server is usually operational within a short period of time. If the outage persists or you receive any other form of an HTTP 5XX error, please contact support.

Validation Errors (422 Unprocessable Entity)

When a request fails validation, the API will respond with a 422 Unprocessable Entity status code and a JSON response containing detailed information about the validation errors.

Validation Error Format

When validation fails for a request, the API will return a JSON response that includes:

  1. A high-level error message that summarizes the validation issues
  2. An errors object containing detailed validation error messages organized by field
{
    "message": "The fail on missing attributes field must be true or false.",
    "errors": {
        "fail_on_missing_attributes": [
            "The fail on missing attributes field must be true or false."
        ]
    }
}

Understanding the Validation Error Response

  • message: A summary of validation errors that occurred. If there are multiple errors, the message will indicate how many additional errors exist beyond the first one mentioned.

  • errors: An object where:

    • Each key represents a field that failed validation
    • Each value is an array of error messages for that field
    • A field may have multiple error messages if it fails multiple validation rules

Handling Array Validation Errors

When validating array elements, the error keys will include the array indices:

{
    "message": "The profiles.1.person.email_address must be a valid email address. (and 1 more error)",
    "errors": {
        "profiles.1.person.email_address": [
            "The profiles.1.person.email_address must be a valid email address."
        ],
        "profiles.0.person.phone_number": [
            "The profiles.0.person.phone_number field contains an invalid number."
        ]
    }
}

For nested fields using "dot" notation, error keys in the response will maintain this notation for easy identification:

Best Practices for Handling Validation Errors

When developing an integration with the Optimized.App API, consider these best practices for handling validation errors:

  1. Always check for the HTTP status code first - a status code of 422 indicates validation errors.

  2. Extract field-specific errors from the errors object to display targeted feedback to your users.

  3. Display all validation errors to users at once rather than one at a time to improve user experience.

  4. For form submissions, map the error field names in the API response to your form field names for proper error display.

  5. Implement client-side validation that mirrors the API's validation rules to provide faster feedback to users before submitting requests to the API.

By properly handling validation errors, you can create a smoother integration experience with the Optimized.App API and provide clear guidance to users when their inputs need correction.

Pagination

Optimized.App API uses pagination for endpoints that return collections of resources to improve performance and reduce response sizes. Pagination information is included in the JSON response body and follows a consistent format across all paginated endpoints.

Pagination Response Format

Paginated responses include the following standard fields:

FieldDescription
current_pageThe current page number
dataArray containing the actual resource items for the current page
first_page_urlURL for the first page of results
fromPosition of the first item on the current page
next_page_urlURL for the next page (null if there is no next page)
pathBase URL path without query parameters
per_pageNumber of items displayed per page
prev_page_urlURL for the previous page (null if there is no previous page)
toPosition of the last item on the current page

Example Pagination Response

{
    "current_page": 1,
    "data": [
        {
            "uuid": "9e072d6f-11af-4a13-a373-924a516d3795",
            "metadata": [],
            "name": "My Group",
            "created_at": "2025-01-22T09:04:02.000000Z",
            "updated_at": "2025-01-22T09:04:02.000000Z",
            "deleted_at": null
        },
        {
            "uuid": "9e072d6f-0ed2-486a-baca-58f889f55cd4",
            "metadata": [],
            "name": "My second group",
            "created_at": "2025-01-22T09:04:02.000000Z",
            "updated_at": "2025-01-22T09:04:02.000000Z",
            "deleted_at": null
        }
    ],
    "first_page_url": "https://api.optimized.app/v1/my-groups&page=1",
    "from": 1,
    "next_page_url": null,
    "path": "https://api.optimized.app/v1/my-groups",
    "per_page": 25,
    "prev_page_url": null,
    "to": 2
}

Navigating Paginated Pages

By default, paginated endpoints return 25 items per page.

To navigate through pages, you can:

  1. Use the page parameter to request a specific page
  2. Follow the URLs provided in the pagination fields:
  • first_page_url: Navigate to the first page
  • next_page_url: Navigate to the next page
  • prev_page_url: Navigate to the previous page

Sorting Paginated Results

You can sort paginated results using the sort parameter:

GET /v1/my-groups?sort=created_at

For descending order, prefix the field name with a minus sign:

GET /v1/my-groups?sort=-created_at

Best Practices for Pagination

  1. Always check for null values in next_page_url and prev_page_url to determine if there are more pages available.

  2. Use the provided URLs instead of constructing your own to ensure proper formatting and compatibility with API changes.

  3. Implement cache invalidation strategies when working with paginated data that may change frequently.

  4. Be mindful of rate limits when making multiple requests to retrieve all pages of a resource. Implement appropriate backoff strategies if necessary.

Download OpenAPI description
Languages
Servers
Mock server

https://docs.optimized.app/_mock/api/

Production server

https://api.optimized.app/

Create a new batch of profiles with scheduling

Request

Creates a new batch of profiles with scheduling information.

This endpoint has a special rate limit of 10 requests per minute per group.

Errors

This endpoint may fail with a validation error (HTTP 422). See the Errors section for details on error response format.

Common validation errors include: Duplicate or non-unique external_id, invalid phone number / email address format

Path
GROUP_IDstringrequired

The unique identifier of the group

Bodyapplication/jsonrequired
profile_tagobject or object

Optional. Profile tag information for the batch. If missing, a new one will be created automatically.

One of:

Optional. Profile tag information for the batch. If missing, a new one will be created automatically.

profilesArray of objects<= 50 itemsrequired

Array of profile objects to be created in this batch. Limit: You can include up to 50 profiles in a single request.

profiles[].​external_idstring or null<= 255 characters

External identifier for the profile. Must be unique within your organization.

profiles[].​personobjectrequired
profiles[].​person.​first_namestring or null<= 255 characters

First name of the person.

profiles[].​person.​last_namestring or null<= 255 characters

Last name of the person.

profiles[].​person.​email_addressstring or null(email)<= 255 characters

Email address of the person.

profiles[].​person.​phone_numberstring or null<= 255 characters

Phone number of the person in international format (e.g., +35840123456).

profiles[].​attributesArray of objects<= 50 items

Optional. Array of custom attributes for the profile.

By default, any attribute that does not already exist will be created automatically.

If fail_on_missing_attributes is set to true, then all attributes listed here must already exist in the system (created via the UI or API); otherwise, the request will fail with a validation error.

scheduleobject

Optional. Scheduling information for the batch. If omitted, the batch will be imported without scheduling.

fail_on_missing_attributesboolean

If true, all attributes must already exist in the system. If any attribute does not exist (i.e., has not been created from the UI or via the API), the request will fail with a validation errors.

If false or omitted, all missing attributes will be created automatically.

Default false
curl -i -X POST \
  'https://docs.optimized.app/_mock/api/v1/groups/{GROUP_ID}/batches' \
  -H 'Authorization: Bearer <YOUR_API Token_HERE>' \
  -H 'Content-Type: application/json' \
  -d '{
    "profile_tag": {
      "name": "string"
    },
    "profiles": [
      {
        "external_id": "string",
        "person": {
          "first_name": "string",
          "last_name": "string",
          "email_address": "user@example.com",
          "phone_number": "string"
        },
        "attributes": [
          {
            "name": "string",
            "value": "string"
          }
        ]
      }
    ],
    "schedule": {
      "start_at": "2019-08-24T14:15:22Z",
      "campaign": {
        "uuid": "095be615-a8ad-4c33-8e9c-c7612fbf6c9f"
      }
    },
    "fail_on_missing_attributes": false
  }'

Responses

Batch created successfully

Bodyapplication/json
metadataArray of objects

Metadata associated with the batch

Example: []
profilesArray of objects

List of profiles created in this batch

Example: [{"external_id":"0000012","uuid":"9ed84352-3e00-4fa0-9705-27f566205d5f"}]
uuidstring(uuid)

UUID of the created batch

Example: "9ed84352-4652-4892-9fdc-cd0e1738d432"
updated_atstring(date-time)

Timestamp when the batch was last updated

Example: "2025-05-06T07:33:15.000000Z"
created_atstring(date-time)

Timestamp when the batch was created

Example: "2025-05-06T07:33:15.000000Z"
groupobject(Group)

Information about the group this batch belongs to.

campaignobject or null(Campaign)

Information about a campaign.

profile_tagobject(ProfileTag)

Information about the profile tag for this batch. In the Optimized.App UI, a profile tag is referred to as a "Contact list". If this field is not provided, a new Contact list will be created automatically and a name will be generated by the system. Use this object to associate the batch with an existing Contact list or to create a new one with a custom name.

scheduleobject or null(Schedule)

Information about the schedule if included (null if no schedule was set).

Response
application/json
{ "metadata": [], "profiles": [ {} ], "uuid": "9ed84352-4652-4892-9fdc-cd0e1738d432", "updated_at": "2025-05-06T07:33:15.000000Z", "created_at": "2025-05-06T07:33:15.000000Z", "group": { "uuid": "9e072d6f-0ed2-486a-baca-58f889f55cd4", "metadata": [], "name": "My group", "created_at": "2025-01-22T09:04:02.000000Z", "updated_at": "2025-01-22T09:04:02.000000Z", "deleted_at": null, "type": {} }, "campaign": { "uuid": "9e679c93-ff33-4b1e-bfad-1ac77afe1aef", "status": "untested", "name": "Voice with question", "description": "My complicated voice with question campaign", "metadata": [], "created_at": "2025-03-11T07:34:17.000000Z", "updated_at": "2025-04-08T06:28:10.000000Z", "deleted_at": null, "hidden_at": null, "view": "broadcast", "revision": 2 }, "profile_tag": { "name": "Voice with question - 202505060733 - e39f2636", "type": "basic", "is_anonymized": false, "uuid": "9ed84352-3b85-4018-a097-e4e15ff3b127", "updated_at": "2025-05-06T07:33:15.000000Z", "created_at": "2025-05-06T07:33:15.000000Z" }, "schedule": { "metadata": [], "status": "scheduled", "start_at": "2025-05-06T07:33:15.000000Z", "uuid": "9ed84352-453d-4a9d-82ad-a71062f44596", "updated_at": "2025-05-06T07:33:15.000000Z", "created_at": "2025-05-06T07:33:15.000000Z" } }