Introduction

This API can be used to programmatically pull data out of ExhibitDay or push data into ExhibitDay -- allowing for automation between ExhibitDay and your internal systems (or other third-party software). To use the API, you'll need working knowledge of consuming REST APIs.

Prerequisite

An API Key is required in order to make API calls. You can obtain your API Key from your ExhibitDay account (under Workspace Settings > API & Integrations > API Access).

Methods and Parameters

There are 3 ways you can pass in the parameter(s) for a method when making an API call:
  1. Parameters In the Request Body (recommended)
    Example: Update an Event's Name (change the name of the event with eventid 12345 to be "Foo Bar")
    curl -X PATCH https://api.exhibitday.com/v1/events -H "Content-Type: application/json" -d "{\"api_key\":\"YOUR_API_KEY\", \"id\":\"12345\", \"name\":\"Foo Bar\"}"
  2. Parameters In the Request Header
    Example (delete an event that has an eventid of 12345):
    curl -X DELETE https://api.exhibitday.com/v1/events -H "api_key: YOUR_API_KEY" -H "id: 12345"
  3. Parameters In the Request URL (only recommended for simple API calls, such as retrieving a task or a list of events)
    Example (get a list of events):
    curl -X GET "https://api.exhibitday.com/v1/events?api_key=YOUR_API_KEY"
Pro tip: you can mix-and-match where the parameters are placed in the request. For example, the api_key parameter (which is a required parameter of every API method) can be placed in the request Header and all other parameters can be placed in the request Body.
Parameter values are text, numbers, true/false or null. A JSON array or object is refused with 400 (error_code invalid_request), with two exceptions: event_tags also accepts an array of tag names, and amount_cost_center_breakdown is the JSON array shown in its description. A request body can be at most 10 MB.

Updating and Clearing Values

When you update an object (e.g., an event or a task), only pass in the parameters that you want to change. Any parameter you don't pass in is left unchanged.
  • To change a value, pass in the new value.
  • To clear a value, pass in null (a JSON null, or the text "null"). Text values are emptied, dates are removed, and numbers are reset to 0. Values that are required (e.g., an event's name or start date) and yes/no values (e.g., is_completed) cannot be cleared; the request is rejected with an error.
  • An empty value doesn't change anything. If you pass in an empty value (e.g., ""), the current value is kept and the response includes a warnings property naming that parameter. This way, a form or an integration tool that sends every field (including the ones that were left blank) never erases your data by accident. The one exception is a task comment's text: a comment cannot be blank, so an empty comment is rejected with an error. Optionally, you can pass in $ignore_params_with_empty_values=true with an update: then every parameter with an empty value or a JSON null is left out of the update (and gets no warning), so with this option the only way to clear a value is the text "null".
Example (remove the due date of the task that has a taskid of 12345; the empty details value leaves the task's details unchanged):
curl -X PATCH https://api.exhibitday.com/v1/tasks -H "Content-Type: application/json" -d "{\"api_key\":\"YOUR_API_KEY\", \"id\":\"12345\", \"due_date\":null, \"details\":\"\"}"
Response:
{"status_code":200,"status":"OK","message":"Task Update Successful. Task properties that were changed: due_date","errors":[],"warnings":["details was empty, so it was left unchanged. To clear it, send null."]}
Note: when you add an object (e.g., with a POST call), passing in null is the same as leaving the parameter out.

Empty Values in Responses

When a value is not set, the API returns it as follows:
  • Text is an empty string (""). For example, an event's venue_name and event_notes, a task's details, and the integration_metadata_field_1 to integration_metadata_field_5 fields.
  • Dates are null. For example, a task's due_date and task_completed_timestamp, and a miscellaneous expense/credit's payment_due_date and next_partial_payment_due_date.
  • Related objects and their ids are null. For example, a task's assignee and event_task_section_id, the event of a general task, and the cost_center_id of an unassigned charge.
  • Numbers are 0. For example, an event's budget and ROI values, and a miscellaneous expense/credit's amount.
  • Lists are empty lists ([]). For example, an event's tags.
A few fields don't follow these rules (they stay as they are, so existing integrations keep working):
  • An event's booth_date_reserved and booth_reserve_by_date are "" when not set.
  • In the records returned by /v1/financials/event_costs, payment_due_date, next_partial_payment_due_date and payment_notes are "" when not set, and cost_subtype is null when the cost has no subtype.
  • A miscellaneous expense/credit's payment_notes is null when empty (its notes is "").
  • In the shorter tasks returned with $return_task_lites, assignee_user_id and task_completed_by_user_id are "" when not set.
Tip: when you check whether a value is empty, treat null and "" the same way.

Response Status Codes

Code Status Description
200 OK Indicates that the request was successfully processed.
304 Not Modified Only for a GET that sends an If-None-Match header with the ETag of an earlier response from the same URL: the data has not changed since, so the response has no body and you can keep using your saved copy. A request without If-None-Match never gets 304 (see Retrying Safely and Conditional Requests below).
400 Bad Request Indicates an issue with the request (i.e., missing required parameter(s) or invalid parameter values), or a change that is not allowed for that event in ExhibitDay (e.g., its tasks or its deletion are locked, or its Misc. Expenses & Credits tab is hidden).
401 Unauthorized The api_key is missing or not valid, or API access is not enabled for your workspace (error_code missing_api_key, invalid_api_key or api_access_disabled).
404 Not Found The requested object was not found (e.g., an incorrect event id was passed in when retrieving an event).
409 Conflict A request with the same Idempotency-Key is still being processed (error_code idempotency_key_in_use: retry after a moment with the same key), or an earlier request with that key did not finish (idempotency_key_indeterminate: check whether it succeeded, then retry with a new key). See Retrying Safely and Conditional Requests below.
429 Too Many Requests The API rate limit is a maximum of 50 calls per second. Each response to a call made with a valid API key includes the X-RateLimit-Limit (calls allowed per second), X-RateLimit-Remaining (calls left in the current second) and X-RateLimit-Reset (seconds until the count resets) headers. A 429 response also includes a Retry-After header with the number of seconds to wait before trying again.
500 Unexpected Internal Error Indicates that an unexpected error has occurred.

Error Codes

Every error response also has an error_code (a stable code your integration can check instead of reading the message), error_params (the parameters the errors refer to; [] when the API cannot tell) and a request_id. Every response carries the request id in the X-Request-Id header as well: quote it when you contact support. New codes may be added, so handle a code you don't know by its HTTP status.
{"status_code": 400, "status": "Bad Request", "message": "Error retrieving event(s)", "errors": ["Invalid value for the event_id parameter: abc. The event_id parameter must be the numeric id of an event."], "error_code": "invalid_request", "error_params": ["event_id"], "request_id": "3f2c9a7e4b1d4c8e9f0a1b2c3d4e5f60"}
error_codeStatusMeaning
invalid_request400A parameter is missing or has an invalid value (error_params names it when the API can tell).
malformed_json400The request body is not valid JSON.
not_allowed400The change is not allowed for that record in ExhibitDay (e.g., the event's tasks or its deletion are locked, or its Misc. Expenses & Credits tab is hidden).
idempotency_key_reused400The Idempotency-Key was already used with a different request. Use a new key for a new request.
missing_api_key401No api_key was sent.
invalid_api_key401The api_key is not valid.
api_access_disabled401API access is not enabled for the workspace.
not_found404No record with that id exists in your workspace.
unknown_endpoint404The URL or HTTP method is not part of the API.
idempotency_key_in_use409A request with the same Idempotency-Key is still being processed. Retry after a moment.
idempotency_key_indeterminate409A previous request with this Idempotency-Key did not finish and its outcome is unknown, so this retry was not run (to avoid creating a duplicate). Check whether the earlier request succeeded; to try again, use a new Idempotency-Key.
rate_limited429Too many requests. Wait the number of seconds in the Retry-After header, then retry.
internal_error500An unexpected error occurred. Quote the request_id when you contact support.

Paging and Changed Records

A list returns every matching record unless you ask for a page. On Retrieve Events, Retrieve Tasks, task comments, miscellaneous expenses/credits, event costs and annual expense costs, pass $limit (the most records to return) and $offset (how many to skip). In the response, records_found is the number of records in it, total_records counts every match and has_more is true while more pages follow; the X-Total-Count header carries the total too. In a URL, write $ as %24.
curl "https://api.exhibitday.com/v1/events?%24limit=100&%24offset=0" -H "api_key: YOUR_API_KEY"
To get only what changed, pass filter_by_last_update_timestamp_greater_than_or_equal_to with the latest last-update timestamp you received (on events, tasks, task comments and miscellaneous expenses/credits). Sync Events and Tasks to Another System shows the whole loop.

Retrying Safely and Conditional Requests

Send an Idempotency-Key header (for example a UUID) with a create (POST). If the call times out and you retry with the same key within 24 hours, you get the first response again (with the header Idempotent-Replayed: true) instead of a second record. Reusing a key for a different request is refused with error_code idempotency_key_reused, and a retry while the first request is still running gets 409 (idempotency_key_in_use). If an earlier request stopped before it finished and its outcome is unknown, a retry gets 409 (idempotency_key_indeterminate) instead of risking a duplicate — check whether that request succeeded, then retry with a new Idempotency-Key.
curl -X POST https://api.exhibitday.com/v1/tasks -H "api_key: YOUR_API_KEY" -H "Idempotency-Key: 5f0c2a8e-7d1b-4c3a-9e6f-2b8d4a1c7e90" -H "Content-Type: application/json" -d "{\"name\":\"Order booth carpet\",\"event_id\":12345}"
Every successful GET response has an ETag header. Send it back in an If-None-Match header: while the data is unchanged, the API answers 304 Not Modified without a body.

Guides