Import Data for Analysis
Overview
Medallia Experience Cloud is the fabric over which customer and employee experiences can be captured, organized, analyzed, and actioned. Bringing data into Experience is essential for making that fabric work for you. Experience offers two APIs — Data Import and Custom Import — to bring that data in.
The Data Import APIs are enabled after installing Medallia Apps. You can browse a list of available Medallia’s Apps on the Medallia Xchange.
The Custom Import APIs are bespoke for each client instance and fit specific and unique needs.
All are backed by Medallia’s powerful ETL layer and accessed via the /inbound/{version}/{importer-name} and the /inbound/v2/async/{importer-name} endpoints, where {importer-name} identifies the specific Import API being targeted.
We refer to the Data Import and Custom Import APIs in this document as "Import API” for simplicity. Where there are differences, we will use the specific name.
The Feed File APIs work in a similar fashion to an import job. The API creates a feed file from the import request and the response returns a feed file ID. Use this ID to retrieve the status of the feed file and generate a detailed processing report.
The Introspection Import APIs enable external technologies to introspect Import API endpoints to understand import data structures programmatically.
Example Use Cases
- After a hotel guest has checked out, schedule a survey to be sent.
- Add transaction data to an existing survey record to enable segmentation analysis.
- Ingest chat transcripts from your contact center operations to understand what topics and themes your customers are asking about.
API Used
Authentication
All API endpoints use OAuth 2.0 for authentication. For all the examples below, we use ${TOKEN}
to refer to the OAuth 2.0 access token granted. See Authentication to learn how to obtain your token.
Request
When publishing to the Import API, the data shape should match the expectations of the API being targeted. Data Import APIs specify their shape, while Custom Import APIs conform to your specifications.
Calls are made using an HTTP POST. Below is an example request to a Data Import API named active_cc_agent_notes_import from the Agent Notes Analyzer Package:
POST /inbound/v1/active_cc_agent_notes_import HTTP/1.1
Host: example.apis.medallia.com
Authorization: Bearer ${TOKEN}
Content-Type: application/json
Accept: application/json
[
{
"CASE_ID": "2210902978",
"CASE_OPENED_DATETIME": "2020-06-11 12:00:00",
"CASE_CLOSED_DATETIME": "2020-06-17 12:00:00",
"CASE_CREATED_BY_ID": "JB0057820",
"CASE_OWNER_NAME": "Jane Brown",
"CASE_OWNER_ID": "JD0057820",
"CASE_STATUS": "Closed",
"CASE_SUBJECT": "Login Issues",
"CASE_NOTES": "Customer called for help with ...",
"CUSTOMER_ID": "22901189",
"FIRST_NAME": "Scott",
"LAST_NAME": "Smith",
"EMAIL_ADDRESS": "[email protected]",
"PHONE_NUMBER": "555-555-5555"
}
]
POST /inbound/v2/async/active_cc_agent_notes_import HTTP/1.1
Host: example.apis.medallia.com
Authorization: Bearer ${TOKEN}
Content-Type: application/json
Accept: application/json
[
{
"CASE_ID": "2210902978",
"CASE_OPENED_DATETIME": "2020-06-11 12:00:00",
"CASE_CLOSED_DATETIME": "2020-06-17 12:00:00",
"CASE_CREATED_BY_ID": "JB0057820",
"CASE_OWNER_NAME": "Jane Brown",
"CASE_OWNER_ID": "JD0057820",
"CASE_STATUS": "Closed",
"CASE_SUBJECT": "Login Issues",
"CASE_NOTES": "Customer called for help with ...",
"CUSTOMER_ID": "22901189",
"FIRST_NAME": "Scott",
"LAST_NAME": "Smith",
"EMAIL_ADDRESS": "[email protected]",
"PHONE_NUMBER": "555-555-5555"
}
]
POST /inbound/v1/active_cc_agent_notes_import HTTP/1.1
Host: example.apis.medallia.com
Authorization: Bearer ${TOKEN}
Content-Type: application/json
Accept: application/json
[
{
"CASE_ID": "2210902978",
"CASE_OPENED_DATETIME": "2020-06-11 12:00:00",
"CASE_CLOSED_DATETIME": "2020-06-17 12:00:00",
"CASE_CREATED_BY_ID": "JB0057820",
"CASE_OWNER_NAME": "Jane Brown",
"CASE_OWNER_ID": "JD0057820",
"CASE_STATUS": "Closed",
"CASE_SUBJECT": "Login Issues",
"CASE_NOTES": "Customer called for help with ..."
"CUSTOMER_ID": "22901189",
"FIRST_NAME": "Scott",
"LAST_NAME": "Smith",
"EMAIL_ADDRESS": "[email protected]",
"PHONE_NUMBER": "555-555-5555"
},
{
"CASE_ID": "982374987",
"CASE_OPENED_DATETIME": "2020-06-15 14:50:00",
"CASE_CLOSED_DATETIME": "2020-06-16 11:13:00",
"CASE_CREATED_BY_ID": "JB0057827",
"CASE_OWNER_NAME": "Violet Smith",
"CASE_OWNER_ID": "VS0059450",
"CASE_STATUS": "Closed",
"CASE_SUBJECT": "Site Issues",
"CASE_NOTES": "Customer noticed a broken link ...",
"CUSTOMER_ID": "32971891",
"FIRST_NAME": "James",
"LAST_NAME": "Henry",
"EMAIL_ADDRESS": "[email protected]",
"PHONE_NUMBER": "555-555-5555"
},
{
"CASE_ID": "3718294733",
"CASE_OPENED_DATETIME": "2020-06-18 08:30:00",
"CASE_CLOSED_DATETIME": "2020-06-18 08:45:00",
"CASE_CREATED_BY_ID": "AS0452087",
"CASE_OWNER_NAME": "Amarilla Sanchez",
"CASE_OWNER_ID": "AS0452087",
"CASE_STATUS": "Closed",
"CASE_SUBJECT": "Luxury Upgrade",
"CASE_NOTES": "Customer requested a suite ...",
"CUSTOMER_ID": "15601883",
"FIRST_NAME": "Sunny",
"LAST_NAME": "Moran",
"EMAIL_ADDRESS": "[email protected]",
"PHONE_NUMBER": "555-555-5555"
}
]
POST /inbound/v2/async/active_cc_agent_notes_import HTTP/1.1
Host: example.apis.medallia.com
Authorization: Bearer ${TOKEN}
Content-Type: application/json
Accept: application/json
[
{
"CASE_ID": "2210902978",
"CASE_OPENED_DATETIME": "2020-06-11 12:00:00",
"CASE_CLOSED_DATETIME": "2020-06-17 12:00:00",
"CASE_CREATED_BY_ID": "JB0057820",
"CASE_OWNER_NAME": "Jane Brown",
"CASE_OWNER_ID": "JD0057820",
"CASE_STATUS": "Closed",
"CASE_SUBJECT": "Login Issues",
"CASE_NOTES": "Customer called for help with ..."
"CUSTOMER_ID": "22901189",
"FIRST_NAME": "Scott",
"LAST_NAME": "Smith",
"EMAIL_ADDRESS": "[email protected]",
"PHONE_NUMBER": "555-555-5555"
},
{
"CASE_ID": "982374987",
"CASE_OPENED_DATETIME": "2020-06-15 14:50:00",
"CASE_CLOSED_DATETIME": "2020-06-16 11:13:00",
"CASE_CREATED_BY_ID": "JB0057827",
"CASE_OWNER_NAME": "Violet Smith",
"CASE_OWNER_ID": "VS0059450",
"CASE_STATUS": "Closed",
"CASE_SUBJECT": "Site Issues",
"CASE_NOTES": "Customer noticed a broken link ...",
"CUSTOMER_ID": "32971891",
"FIRST_NAME": "James",
"LAST_NAME": "Henry",
"EMAIL_ADDRESS": "[email protected]",
"PHONE_NUMBER": "555-555-5555"
},
{
"CASE_ID": "3718294733",
"CASE_OPENED_DATETIME": "2020-06-18 08:30:00",
"CASE_CLOSED_DATETIME": "2020-06-18 08:45:00",
"CASE_CREATED_BY_ID": "AS0452087",
"CASE_OWNER_NAME": "Amarilla Sanchez",
"CASE_OWNER_ID": "AS0452087",
"CASE_STATUS": "Closed",
"CASE_SUBJECT": "Luxury Upgrade",
"CASE_NOTES": "Customer requested a suite ...",
"CUSTOMER_ID": "15601883",
"FIRST_NAME": "Sunny",
"LAST_NAME": "Moran",
"EMAIL_ADDRESS": "[email protected]",
"PHONE_NUMBER": "555-555-5555"
}
]
Batch imports for large-scale integrations
Import APIs are built to handle multiple records/objects in a single call. Using batch import mode can greatly reduce the number of APIs calls needed.
Medallia recommends a per-batch limit of no more than 500 records.
The Import API accepts data in JSON, XML, CSV, and plaintext format. Set the Content-Type header to the appropriate MIME type.
Response
The Import API responds with a standard HTTP status code and a payload that indicates the status of the processing.
Import APIs are either synchronous (processes the data immediately) or asynchronous (queues the data for processing). The Import API will specify which it is through the response. For example, below is a synchronous response:
HTTP/1.1 200 Ok
Content-Type: application/json
{
"records": 1,
"duplicates": 0,
"rejects": 0
}
Import API v2 processing is asynchronous: the API response returns a feed file ID (feed_file_id).
HTTP/1.1 202 Accepted
Content-Type: application/json
{
"feed_file_id": "82a2ea83-9d7a-4b4f-8769-dd5b8c13a045",
"_allowed": [POST]
}
You can use the returned ID to retrieve the status of the feed file. Medallia recommends storing this value for troubleshooting and auditing purposes.
Retrieving Import Results
Detailed import results
Only supported when using the Import API v2 is on non-concurrent mode.
Using the Feed Files API, you can query the status of the feed file.
GET /inbound/v2/feedfiles/82a2ea83-9d7a-4b4f-8769-dd5b8c13a045 HTTP/1.1
Host: example.apis.medallia.com
Authorization: Bearer ${TOKEN}
Content-Type: application/json
Accept: application/json
HTTP/1.1 200 Ok
Content-Type: application/json
{
"id": "82a2ea83-9d7a-4b4f-8769-dd5b8c13a045",
"status": "COMPLETED_RESULTS_READY",
"stats": {
"records": {
"input_count": 2,
"success_count": 0,
"discarded_count": 2,
"duplicated_count": 2
},
"creation_date": "2023-05-09T23:46:52.874Z",
"processing_start_date": "2023-05-09T23:46:53.521Z",
"processing_end_date": "2023-05-09T23:47:11.11Z",
"processing_mode": "ACTIVE",
"processing_error_description": null
},
"_links": {
"self": {
"href": "https://example.medallia.com/inbound/v2/feedfiles/82a2ea83-9d7a-4b4f-8769-dd5b8c13a045",
"rel": "self"
},
"details": {
"href": "https://example.medallia.com/inbound/v2/feedfiles/82a2ea83-9d7a-4b4f-8769-dd5b8c13a045/detailed-results",
"rel": "collection"
},
"canonical": {
"href": "https://example.medallia.com/inbound/v2/feedfiles/82a2ea83-9d7a-4b4f-8769-dd5b8c13a045",
"rel": "canonical"
}
},
"_allowed": [GET]
}
Refer to the Feed File API specifications for a full list of possible status values.
Once the status of the feed file is COMPLETED_RESULTS_READY from the above query, you can fetch detailed results for analysis. Use an HTTP GET request to see detailed information about successfully ingested records and discarded records.
GET /inbound/v2/feedfiles/82a2ea83-9d7a-4b4f-8769-dd5b8c13a045/detailed-results HTTP/1.1
Host: example.apis.medallia.com
Authorization: Bearer ${TOKEN}
Content-Type: application/json
Accept: application/json
The shape of the response varies depending on the setup of the Importer in Experience Cloud that processes the import requests. In all cases, the response will differentiate input records that were successfully ingested from records that were discarded as shown in the below example.
HTTP/1.1 200 Ok
Content-Type: application/json
{
"processing_results": [
{
"entity_name": "record",
"successful_results": [
{
"input_position": 1,
"result": "Selected for sampling",
"has_duplicate_record_info": false,
"field_values": {
"e_bp_b2b_survey_date": {
"modified_content": null,
"current_content": "2023-05-01",
"value_modified": false,
"dup_checking": false,
"_allowed": []
},
"e_bp_uniquerecordid_txt": {
"modified_content": null,
"current_content": "[email protected]_rel",
"value_modified": false,
"dup_checking": true,
"_allowed": []
},
"e_bp_b2b_contact_role_alt": {
"modified_content": null,
"current_content": "",
"value_modified": false,
"dup_checking": false,
"_allowed": []
},
"e_bp_development_cycle_alt": {
"modified_content": null,
"current_content": "Development (1)",
"value_modified": false,
"dup_checking": false,
"_allowed": []
},
"e_bp_b2b_product_line_auto": {
"modified_content": null,
"current_content": "[]",
"value_modified": false,
"dup_checking": false,
"_allowed": []
},
"e_bp_historical_data_flag_yn": {
"modified_content": null,
"current_content": "No (2)",
"value_modified": false,
"dup_checking": false,
"_allowed": []
},
"e_firstname": {
"modified_content": null,
"current_content": "Scott",
"value_modified": false,
"dup_checking": false,
"_allowed": []
},
"e_lastname": {
"modified_content": null,
"current_content": "Smith",
"value_modified": false,
"dup_checking": false,
"_allowed": []
},
"e_email": {
"modified_content": null,
"current_content": "[email protected]",
"value_modified": false,
"dup_checking": false,
"_allowed": []
},
"e_bp_b2b_contact_id_txt": {
"modified_content": null,
"current_content": "id-1000",
"value_modified": false,
"dup_checking": false,
"_allowed": []
},
"e_bp_record_type_b2b_relationship_yn": {
"modified_content": null,
"current_content": "Yes (1)",
"value_modified": false,
"dup_checking": false,
"_allowed": []
},
"e_phone": {
"modified_content": null,
"current_content": "",
"value_modified": false,
"dup_checking": false,
"_allowed": []
},
"e_bp_b2b_account_unit": {
"modified_content": null,
"current_content": "b2b_account_87 ('3M')",
"value_modified": false,
"dup_checking": false,
"_allowed": []
},
"e_bp_record_type_b2b_all_yn": {
"modified_content": null,
"current_content": "Yes (1)",
"value_modified": false,
"dup_checking": false,
"_allowed": []
},
"e_country": {
"modified_content": null,
"current_content": "",
"value_modified": false,
"dup_checking": false,
"_allowed": []
},
"e_bp_language_alt": {
"modified_content": null,
"current_content": "English (1)",
"value_modified": false,
"dup_checking": false,
"_allowed": []
},
"e_bp_record_processing_time": {
"modified_content": null,
"current_content": "2023-06-01 13:05:38.066 -0700",
"value_modified": false,
"dup_checking": false,
"_allowed": []
}
},
"_allowed": []
}
],
"discarded_results": [
{
"input_position": 2,
"input_values": {
"LANGUAGE": null,
"DEVELOPMENT_CYCLE": null,
"PRODUCT_LINE": null,
"EMAIL_ADDRESS": null,
"COUNTRY": null,
"ACCOUNT_ID": "87",
"DATE_TO_SURVEY": "2023-01-02:00:00:00",
"CONTACT_ROLE": null,
"CONTACT_ID": "id-1001",
"LAST_NAME": "Smith",
"PHONE_NUMBER": null,
"FIRST_NAME": "Scott"
},
"issues": [
{
"consequence": "Record discarded",
"explanation": "missing required value",
"detail": "Email (e_email)",
"cause": "Issues associated with e_email ('Email')",
"_allowed": []
},
{
"consequence": "Record discarded",
"explanation": "failure to parse (possibly transformed) value",
"detail": "'2023-01-02:00:00:00' for DATE",
"cause": "Issues associated with e_bp_b2b_survey_date ('Date to Survey')",
"_allowed": []
}
],
"_allowed": []
}
],
"_allowed": []
}
],
"input_to_field_mappings": {
"LANGUAGE": [
"e_bp_language_alt"
],
"DEVELOPMENT_CYCLE": [
"e_bp_development_cycle_alt"
],
"PRODUCT_LINE": [
"e_bp_b2b_product_line_auto"
],
"EMAIL_ADDRESS": [
"e_email"
],
"COUNTRY": [
"e_country"
],
"ACCOUNT_ID": [
"e_bp_b2b_account_unit"
],
"DATE_TO_SURVEY": [
"e_bp_b2b_survey_date",
"e_bp_uniquerecordid_txt"
],
"CONTACT_ROLE": [
"e_bp_b2b_contact_role_alt"
],
"CONTACT_ID": [
"e_bp_b2b_contact_id_txt"
],
"LAST_NAME": [
"e_lastname"
],
"PHONE_NUMBER": [
"e_phone"
],
"FIRST_NAME": [
"e_firstname"
]
},
"processing_error_description": null,
"_links": null,
"_allowed": []
}
Successful results display which field entities in Medallia Experience Cloud are mapped and/or updated. Discarded results reveal the reasons for import rejection. Use this information to automate your IT processes, for example by storing all discarded records to be used for an automatic retry process, or flagging data hygiene issues in a data warehouse.
Import Properties
The data shape will be defined by the Import API being accessed. Data Import APIs from Medallia Apps will have out-of-the-box shapes that you transform your data to meet; Custom Import APIs will be designed around your data’s existing shape. Detailed results from the Feed File API take the shape of the Importer used to ingest the data.
Synchronous processing is used for high-volume data feeds, such as from a point-of-sale system. The HTTP client connection is kept open while the processing occurs. The number of records per request should be kept to 100 or less.
Asynchronous processing is used for large payloads or low-volume data feeds, such as a nightly CRM export process. The HTTP client connection is only kept open for as long as it takes to queue the asynchronous job in Medallia’s ETL layer. Asynchronous processing is also used for feed file tracking and record ingestion result discovery.
Introspection
Leverage the Introspection API to discover the shape of our out-of-the-box import connectors. Use this metadata REST API to automatically introspect import endpoints without having to rely on manual processes or data dictionaries.
Request
All calls are made using an HTTP GET.
The below is an example introspect all import endpoints from a Medallia instance:
GET /inbound/v2 HTTP/1.1
Host: example.apis.medallia.com
Authorization: Bearer ${TOKEN}
Content-Type: application/json
Accept: application/json
Response
The response contains all the import API paths configured as active or pretend in an instance.
Successful results display a summary and a description of each import connector.
HTTP/1.1 200 Ok
Content-Type: application/json
{
"openapi": "3.0.1",
"info": {
"title": "Import API",
"version": "1.0.0"
},
"servers": [
{
"url": "example.apis.medallia.com"
}
],
"paths": {
"/inbound/v2/async/active_b2b_onboarding_invitation": {
"post": {
"summary": "active_b2b_onboarding_invitation",
"description": "This web feed is for the client to send Medallia invitation data for the B2B Onboarding program ON ACTIVE."
}
},
"/inbound/v2/async/active_b2b_org": {
"post": {
"summary": "active_b2b_org",
"description": "This web feed is for the client to send Medallia org hierarchy data for the B2B program WITH ACTIVE PROCESSING."
}
},
"/inbound/v2/async/active_b2b_relationship_invitation": {
"post": {
"summary": "active_b2b_relationship_invitation",
"description": "This web feed is for the client to send Medallia invitation data for the B2B Relationship program ON ACTIVE."
}
}
}
}
The example below is a request to introspect a Data Import API named portal_b2b_onboarding_survey:
GET /inbound/v2/portal_b2b_onboarding_survey HTTP/1.1
Host: example.apis.medallia.com
Authorization: Bearer ${TOKEN}
Content-Type: application/json
Accept: application/json
Response
Successful results display a summary and a description of the import connector. Additionally, they show the API Gateway URL for that instance, and objects describing the shape of the request body of the Data Import API, available responses, and authentications schemas.
Primarily, input-object
displays a list of all input columns, their type, description, and enumerated values if applicable, and specifies which are the required input columns.
The shape of the response conforms to OpenAPI specification version 3.0 standards.
HTTP/1.1 200 Ok
Content-Type: application/json
{
"openapi": "3.0.1",
"info": {
"title": "Import API",
"version": "1.0.0"
},
"servers": [
{
"url": "example.apis.medallia.com"
}
],
"paths": {
"/inbound/v2/async/portal_b2b_onboarding_survey": {
"post": {
"summary": "portal_b2b_onboarding_survey",
"description": "Web Feed to trigger B2B Onboarding survey email from Portal's feedless survey tool.",
"requestBody": {
"description": "The data to be imported",
"content": {
"application/json": {
"schema": {
"oneOf": [
{
"$ref": "#/components/schemas/input-object"
},
{
"type": "array",
"items": {
"$ref": "#/components/schemas/input-object"
}
}
]
}
},
"text/xml": {
"schema": {
"oneOf": [
{
"$ref": "#/components/schemas/input-object"
},
{
"type": "array",
"items": {
"$ref": "#/components/schemas/input-object"
}
}
]
}
},
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": {
"schema": {
"type": "string",
"format": "binary"
}
},
"text/csv": {
"schema": {
"type": "string"
}
}
},
"required": true
},
"responses": {
"202": {
"description": "The response to a data import that is processed asynchronously. Refer to Medallia's Developer Portal for latest rate limit information returned in the headers.",
"content": {
"application/json": {
"schema": {
"required": [
"feed_file_id"
],
"type": "object",
"properties": {
"feed_file_id": {
"type": "string",
"description": "The unique ID of the feed file record created. Use this ID to retrieve the results of the import request."
}
}
}
}
}
},
"401": {
"description": "Unauthorized"
},
"403": {
"description": "Forbidden"
},
"404": {
"description": "Object not found. Refer to Medallia's Developer Portal for latest rate limit information returned in the headers."
},
"412": {
"description": "Precondition failed"
},
"500": {
"description": "Internal server error"
}
},
"security": [
{
"mecOauth": []
}
]
}
}
},
"components": {
"schemas": {
"input-object": {
"required": [
"ACCOUNT_ID",
"DATE_TO_SURVEY",
"DEVELOPMENT_CYCLE",
"EMAIL_ADDRESS",
"FIRST_NAME"
],
"type": "object",
"properties": {
"DATE_TO_SURVEY": {
"type": "string"
},
"DEVELOPMENT_CYCLE": {
"type": "string",
"enum": [
"QA",
"DEV",
"TEACH",
"UAT",
"DEMO",
"LIVE"
]
},
"FIRST_NAME": {
"type": "string"
},
"LAST_NAME": {
"type": "string"
},
"EMAIL_ADDRESS": {
"type": "string",
"format": "email"
},
"PHONE_NUMBER": {
"type": "string"
},
"CONTACT_ID": {
"type": "string"
},
"CONTACT_ROLE": {
"type": "string",
"enum": [
"Decision Maker",
"Influencer",
"End User",
"Procurement"
]
},
"LANGUAGE": {
"type": "string",
"enum": [
"English",
"Spanish (Spain)",
"French (France)",
"German (Germany)",
"Spanish (Mexico)",
"French (Canada)",
"Italian (Italy)",
"Portuguese (Brazil)",
"Chinese",
"Norwegian"
]
},
"COUNTRY": {
"type": "string"
},
"PRODUCT_LINE": {
"type": "string"
},
"ACCOUNT_ID": {
"type": "string"
}
}
}
},
"securitySchemes": {
"mecOauth": {
"type": "oauth2",
"flows": {
"clientCredentials": {
"tokenUrl": "example.apis.medallia.com/oauth/company/token"
}
}
}
}
}
}
Conclusion
Data Import APIs and Custom Import APIs are powerful entities for powering your Medallia processes. Usage is the same across both types, with the only difference being the data shape. The Medallia Apps available on the Medallia Xchange create Data Import APIs with opinionated data shapes; Custom Import APIs are created based on your provided data shape. Use the Feed file API to track the status and results of your import requests to troubleshoot data hygiene issues.
Leverage our metadata REST API — the Introspection API — to enable your systems to explore our Import API data shapes and automate Import API request structures accordingly.
Updated over 1 year ago