Import a Data CSV via API

With Watershed's CSV Import Feature, you can bring both xAPI and groups data into Watershed with a flat CSV file. This is done by first creating an xAPI template or creating a template for organizational hierarchy data. Users can then upload files with new data on a regular basis.

To avoid having to manually upload the CSV, you can use Watershed’s CSV Data Import API to send the CSV data to Watershed automatically.

This guide outlines the allowed resources and methods of the CSV Data Import API. In order to interact with the CSV Data Import API, you will need authentication credentials and an organization id (org id).

 Please note: you will be to create a template via the UI before importing CSVs either by API or UI. We don’t recommend creating templates via API as the UI includes helpful validation to ensure the template works.

Upload Data as a CSV

Request URL: /api/organizations/[org-id]/csv-import

Method: POST

Expected response code: 202 Accepted

Request headers

If you are using a code library for sending files, it will likely take care of setting the proper Content-Type header.  Consult your code library documentation.

If you are building a request directly in your code, you will need the following header:

Header

Details

Content-Type

The content type for this request is multipart/form-data. The content type header should also include the boundary used in the request content. E.g. multipart/form-data; boundary=BOUNDARY

 Please note: The boundary string used should be a string which does not occur within the csv file.

Request parameters

Parameter

Details

template

Name (or id) of the template to use for the import import.

fileSize

Size of the file in bytes.  This number must be exact.  Optional if file size < 10Mb.

notify

Email address to notify with details once the import completes (or fails). Can be a single email address or a comma-separated lists of email addresses.

 

Request content

The content of the request uses the multipart/form-data format. Most libraries for sending files will properly handle setting up the request body without having to worry about details such as the boundary separator string. Consult the documentation for your library of choice.

If you find that you have to build a request body in your own code, a single part contains the contents of the csv file. For example:

--BOUNDARY
Content-Disposition: form-data; name="file"; filename="name.csv"
Content-Type: text/csv

header A, header B
cell 1A, cell 1B
cell 2A, cell 2B
--BOUNDARY--

 Please note: we recommend against building API requests by hand, but if you do, be sure to use the right type of line break in your requests to avoid errors.

Response

A successful response contains the id of the import job that was started.

 Please note: No errors are returned in the API call so long as the csv file is uploaded successful, even if there are problems with the contents of the CSV file. Errors are logged in Watershed’s CSV Data Import UI (or via email if a notify email address is specified). To check a CSV for errors before uploading it, make a request to preview the file.

Preview a CSV Upload

The preview request is similar to the upload request except that it returns generated statements and any errors, instead of storing them in Watershed.

 Please note: unless you are doing something very complex such as building out your own CSV upload UI, there is not normally any reason to preview the upload when using the API; you can skip straight to the upload request.

Request URL: /api/organizations/[org-id]/statement-import/preview

Method: POST

Expected response code: 200 OK

Request headers

Header

Details

Content-Type

The content type for this request is multipart/form-data. The content type header should also include the boundary used in the request content. E.g. multipart/form-data; boundary=BOUNDARY

 

Request parameters

Parameter

Details

template

Name (or id) of the template to use for the import import.

 

Request content

The content of the request is multipart. The first part is the csv file and the second part is a form parameter containing the size of the csv file. For example:

--BOUNDARY
Content-Disposition: form-data; name="file"; filename="name.csv"
Content-Type: text/csv

header A, header B
cell 1A, cell 1B
cell 2A, cell 2B

--BOUNDARY
Content-Disposition: form-data; name="filesize"
52
--BOUNDARY--

 Please note: we recommend against building API requests by hand, but if you do, be sure to use the right type of line break in your requests to avoid errors.

Response

A successful response contains an object with two properties, failedRows and statements. Both of these properties contain an object, the properties of which are strings named with the row numbers of failed or successful rows.

Within the failedRows object, the value of each property is an error message outlining the error encountered with that row. For example (line breaks added for clarity):

"failedRows": {
    "1388": "Statement must include an ID, and the ID must
    be a UUID. The current value of the field is: 
    some-invalid-id."
 }

Within the statements object, the value of each property is an array of xAPI statements generated by that row.

 Please note: the header row counts as row 1 so normally the first successful or failed row will be row 2.

Fetch CSV Imports

Gets details of csvs that have been imported and not voided. This might be useful if you need to void an import via API (see below).

 Please note: the response to this request can be large if a large number of statements was generated.

Request URL: /api/organizations/[org-id]/csv-import

Method: GET

Expected response code: 200 OK

Request parameters

Parameter

Details

id

Id of the import to get. If not included all imports will be returned.

template

Name of template to filter by. Returns only those imports using this template.

 

Response

A successful response returns a collection object with count and results properties. The count property contains a count of the results. The results property contains an array of import objects, the properties of which are outlined in the table below.

Property

Details

id

Id of the import.

created

ISO 8602 timestamp of when the CSV was imported

version

Not necessary

size

Size of file?

originalFilename

The name of the file imported

file

The name of the file imported

mediaType

Always text/csv

hashFileName

 

userName

The full name of the user who uploaded the file.

statemenIds

A comma separated string listing the ids of all the statements generated by the import.

alllStatementIds

An array of ids of all the statements generated by the import.

failedRows

An object whose properties correspond to row numbers of rows that errored. The value of each property is the error generated for that row.

template

The name of the template used for the import

Void an Import

If a CSV has been uploaded in error, it is possible to delete the import and void all statements created. If the file had groups information, voiding the file will remove any people, groups, and permissions created by the import, even if the information had been edited by a later import. It won't revert any changes made to people and groups that previously existed.

 Please note: voiding statements should normally be avoided on production environments and only correct CSVs containing new data should be uploaded. Integrations that routinely void large numbers of statements are strongly discouraged and can cause problems with reporting.

Request URL: /api/organizations/[org-id]/csv-import/[import-id]

Method: DELETE

Expected response code: 200 OK

Response

A successful responses returns no content.

Code samples

This section provides reference code samples for the above API calls using Python 3.

Code: Upload Data as a CSV

import os
import requests

# Get the CSV Data
## Using open to get the csv data
with open('my_csv.csv', 'r') as infile:
csv_data = infile.read()

## Alternatively using Pandas to get the csv data:
import pandas as pd
df = pd.read_csv('my_csv.csv')
csv_data = df.to_csv(index=False)

# Create the request
## Get the size of the file
filesize = len(csv_data.encode('utf-8'))
### Alternatively use the os module to get the file size:
filesize = os.path.getsize('my_csv.csv')

files = {'file': (filename, csv_data)}
notification_email = "your_email@example.com"
## Alternatively, a list of emails
notification_email = "your_email1@example.com,your_email2@example.com"

template_name "My Template"
ws_key = "your_watershed_key"
ws_secret = "your_watershed_secret"
url = f"https://sandbox.watershedlrs.com/api/organizations/5664/csv-import?template={template_name}&fileSize={filesize}&{notify}"
r = requests.post(url, auth=(ws_key, ws_secret), files=files, timeout=1200)

Code: Preview a CSV Upload

# Using the same code from above, we change the url to:
url = f"https://sandbox.watershedlrs.com/api/organizations/5664/statement-import/preview?template={template_name}&fileSize={filesize}&{notify}"
r = requests.post(url, auth=(ws_key, ws_secret), files=files, timeout=1200)

Code: Fetch CSV Imports

# Getting all imports
url = "https://sandbox.watershedlrs.com/api/organizations/5664/csv-import"
res = requests.get(url, headers=headers, auth=(ws_key, ws_secret), timeout=60)

# Getting all imports for a specific template
url = f"https://sandbox.watershedlrs.com/api/organizations/5664/csv-import?template={template_name}"
res = requests.get(url, headers=headers, auth=(ws_key, ws_secret), timeout=60)

Code: Void a CSV Import

# Get the import ID from either the csv_import request above or from the CSV Data Page on the UI by hovering over the "Source" link
url = f"https://sandbox.watershedlrs.com/api/organizations/5664/statement-import/{import_id}?deleteLrsStatements=true"
res = requests.delete(url, headers=headers, auth=(ws_key, ws_secret), timeout=60)
Was this article helpful?
0 out of 0 found this helpful

If you can't find what you need or you want to ask a real person a question, please contact customer support.