SESAR REST web services API documentation

Overview

SESAR provides several REST web services. The end point is: https://app.geosamples.org/webservices/ The test end point is: https://sesardev.geosamples.org/webservices/

  1. Sample registration web service
  2. Validate user credential and get user codes web service(new version v2)
  3. IGSN list web service for a specific user code
  4. IGSN list web service for a geospatial polygon
  5. IGSN list web service for a specific field program
  6. Sample profile web service for IGSN(New feature added)
  7. Update sample information by IGSN (New)

 

1. Sample registration web service

 

  • The web service https://app.geosamples.org/webservices/upload.php allows the client program to register a single sample or multiple samples.
  • It only accepts POST requests from client programs. GET, PUT and DELETE are not supported.
  • Notes:
    • The older version (v1) uploadservice.php is deprecated and its bugs will not be fixed. The current upload web service (upload.php v2) is backward compatible. The user is discouraged to use the v1 uploadservice.php. v1(uploadservice.php) only support the v1 schema. It does not support latest v2 sample schema (samplev2.xsd).
    • The user should use the following test URI during client program testing. So all test samples will not be populated to the production server.

 

POST API

URI: https://app.geosamples.org/webservices/upload.php

TEST URI: https://sesardev.geosamples.org/webservices/upload.php

GeoPass Account:

  • Before you start use this web service, you need to create GeoPass account. Here is the link to register a GeoPass account. It is free. https://geopass.iedadata.org/josso/.
  • After the account is created, you need to login SESAR system at least once to create your namespace (user code). Here is the link https://app.geosamples.org/ .
  • The user can only register sample(s) with IGSN(s) whose prefix (user code) is assigned to this user.

Request headers

Request body

username={yourusername}
password={yourpassword}
content={sampleinformation}

where {sampleinformation} is the xml text.

Example XML format for registering one sample:

<?xml version="1.0" encoding="UTF-8"?>
<samples xmlns="http://app.geosamples.org"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://app.geosamples.org/samplev2.xsd ">
<sample>
<user_code>ABC</user_code> <!-- required -->
<sample_type>Individual Sample</sample_type> <!-- required -->
<name>TestSample123</name> <!-- Required -->
<material>Rock</material> <!-- required, -->
<igsn>ABC123456</igsn> <!-- Not Required, If it is not specifed, the system will create it automatically. -->
<!-- If no classification.xsd is specified, the older format for classification is still supported e.g., Igneous>Plutonic>Felsic -->
<classification xmlns="http://app.geosamples.org"
                xmlns:xs="http://www.w3.org/2001/XMLSchema"
                xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                xsi:schemaLocation="http://app.geosamples.org/classifications.xsd">
<Rock><Igneous> <Plutonic> <PlutonicType>Felsic</PlutonicType> </Plutonic> </Igneous></Rock> </classification>
<description>arkose</description>
<age_min>6.5</age_min>
<age_max>13</age_max>
<age_unit>years</age_unit>
<collection_method>Grab</collection_method>
<latitude>35.5134</latitude>
<longitude>-117.3463</longitude>
<elevation>781.4</elevation>
<primary_location_name>Lava Mountains, Mojave Desert, California
</primary_location_name>
<country>United States</country>
<province>California</province>
<county>San Bernardino</county>
<collector>J. E. Andrew</collector>
<collection_start_date>2002-05-30T09:30:10Z
</collection_start_date>
<collection_date_precision>time</collection_date_precision>
<original_archive>University of Kansas</original_archive>
</sample>
</samples>

  • You can upload multiple samples by adding <sample></sample> block nested in <samples></samples> tag.

    The sample xml schema is here. You can find the XML sample template at this link.

 

Response body

HTTP status codes:

200 Sample registered successful. The response text is like the following.

<results>
<sample>
<status>Sample [Lulin Upload Status Sample test] was saved successfully with IGSN [LLS00009I].</status>
<name>Lulin Upload Status Sample test</name>
<igsn>LLS00009I</igsn>
</sample>
</results>

400 Bad Request - Request body either has syntax error or xml content has errors. Error messages will look like the following.

    XML Syntax error:

<results>
<valid code="InvalidXML">no</valid>
<error>Element '{http://app.geosamples.org}publish_date':[facet 'pattern'] The value '2016-03-0' is not accepted by the patter '([0-9]{4}-[0-9]{2})\(.........)'</error> ..........
</results>

XML content error:

<results><sample name="your sample name">
<valid code="InvalidSample">no</valid><status>Not Saved</status>
<error>The User Code ABC in your IGSN ABC123456 does not belong to you.</error> ......
</sample>
</results>

401 Unauthorized - When it failed to login in, it will return text as following.

<results>
<valid code="InvalidAuth">no</valid>
<error>Invalid login, username not known or password not matched</error>
</results>


 

2. Validate user credential and get user code web service

 

POST API

URI: https://app.geosamples.org/webservices/credentials_service_v2.php

GeoPass Account:

  • Before you use this web service, you need to create GeoPass account. Here is the link to GeoPass account registration. It is free. https://geopass.iedadata.org/josso/.
  •  After the account is created, you can login SESAR system to create your namespace (user code) or request the user code owner to set up your access permission. Here is the link https://app.geosamples.org/.

Request headers

Request body

username={yourusername}
password={yourpassword}

Response body

HTTP status codes:

200 Successful. User name and password are valid. It will return user code(s) as following.

  <results>
       <valid>yes</valid>
       <user_codes>
           <user_code>MOB</user_code>
       </user_codes>
     </results> 

401 Unauthorized - When it failed to login, it will return text as following.

    <results>
      <valid>no</valid>
      <error>Invalid login, username not known or password not matched</error>
    </results>

Usage Example:

curl --data "username=your_user_name&password=your_password"
https://app.geosamples.org/webservices/credentials_service.php

Example 2.

  <?php

function curl_http_post_request($requestdata){
    $ch = curl_init();

    curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,false);
    curl_setopt($ch, CURLOPT_URL, $requestdata["url"]);

    curl_setopt($ch,CURLOPT_POST,true);
    curl_setopt($ch,CURLOPT_POSTFIELDS,$requestdata["data"]);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

    $result["content"]= curl_exec($ch);
    $result["errno"]= curl_errno($ch);
    $result["errmsg"] = curl_error($ch) ;
    $result["header"] = curl_getinfo($ch);

    curl_close($ch);
    return $result;
}


$baseurl="https://app.geosamples.org/webservices/credentials_service_v2.php";
$username="your_user_name";
$password="your_password";
$requestinfo["url"]=$baseurl;
$requestinfo["data"]=array("username"=>$username,"password"=>$password);

$result=curl_http_post_request($requestinfo);

echo $result["content"].PHP_EOL;
echo $result["header"]["http_code"].PHP_EOL;
echo $result["errno"].PHP_EOL;
echo $result["errmsg"].PHP_EOL;

?>  

3. IGSN list web service for specific user code

 

  • The end point is https://app.geosamples.org/samples/user_code/[user code] Examples of user code: IEUHM or IELCZ. The older three digits user code is supported also e.g., ODP, NHB or HRV
     
  • The service will retrieve all IGSNs for a specific user code. It only accepts GET request from client program.

GET API

Request headers

  • Accept: application/xml, application/json, text/xml, text/json

Request body

limit={limit}
    maximum IGSN number for each page. If it is not specified, it will default to 100.
page_no={page_no}
     page number. If it is not specified, it will default to 1.
hide_private={hide_private}
     indicates if the user would like to list private samples or not. If it is not specified, it will default to 0. If it is assigned to 1, the private samples will not be in the returned IGSN list. 'private sample' means that the sample metadata is not public. IGSN itself is always public.

Response body

HTTP status codes:

  • 400 Bad Request - User Code is not valid.
  • 404 Not Found - No IGSNs associate with the give user code.
  • 200 successful. It will return user IGSN(s) as following.
  • Output format when request is successful ( status code = 200 )

XML format:

<samples>

<sample>
<igsn>LLS00000L</igsn>
<url>https://app.geosamples.org/webservices/display.php?igsn=LLS00000L</url>
</sample>
<sample>
<igsn>LLS00000M</igsn>
<url>https://app.geosamples.org/webservices/display.php?igsn=LLS00000M</url>
</sample>
<sample>
<igsn>LLS00000N</igsn>
<url>https://app.geosamples.org/webservices/display.php?igsn=LLS00000N</url>
</sample>
...... 

<total_counts>320</total_counts><previous_list>https://app.geosamples.org/samples/user_code/LLS?limit=20&page_no=1</previous_list>
<next_list>https://app.geosamples.org/samples/user_code/LLS?limit=20&page_no=3</next_list>
</samples>

 

JSON format:   

{ "igsn_list": [ "MOB000001", "MOB000002", "MOB000003", "MOB000004", ...... ], "total_counts":450, "previous_list": [ "http: //app.geosamples.org/samples/user_code/MOB?limit=100&page_no=1" ], "next_list": [ "http: //app.geosamples.org/samples/user_code/MOB?limit=100&page_no=3" ] }

 

Example:

curl -X GET -H "accept: application/xml"
"https://app.geosamples.org/samples/user_code/ARF?limit=20&page_no=2&hide_private=1"

4. IGSN list web service for a geospatial polygon

 

  • The end point is https://app.geosamples.org/samples/polygon/[lon1 lat1, lon2 lat2, lon3 lat3, lon4 lat4, lon5 lat5]. [lon1 lat1, lon2 lat2, lon3 lat3, lon4 lat4, lon1 lat1] are points of concave polygon. Please note the last point is the same as the first point.
     
  • The service will retrieve all IGSNs for user defined polygon. It only accepts GET request from the client program.

GET API

Request headers

  • Accept: application/xml, application/json, text/xml, text/json

Request body

lon1 lat1, lon2 lat2, lon3 lat3, lon4 lat4, lon1 lat1 = floating points of longitude, latitude for a polygon
limit={limit}
    maximum IGSN number for each page. If it is not specified, it will default to 100.
page_no={page_no}
     page number. If it is not specified, it will default to 1.
hide_private={hide_private}
     indicates if the user would like to list private samples or not. If it is not specified, it will default to 0. If it is assigned to 1, the private samples will not be in the returned IGSN list.
srs={SRS number}NEW
     Spatial Reference System (SRS) number. If it is not specified, it will default to EPSG:4326.

Response body

HTTP status codes:

  • 400 Bad Request - User specified polygon is not valid.
  • 404 Not Found - No IGSNs associate with the give polygon
  • 200 successful. It will return user IGSN(s) as following.

Output format when request is successful ( status code = 200 )

XML format:

<samples><sample>
<igsn>LCZ7700AN</igsn>
<url>https://app.geosamples.org/webservices/display.php?igsn=LCZ7700AN</url>
</sample>
<sample>
<igsn>LCZ7700AM</igsn>
<url>https://app.geosamples.org/webservices/display.php?igsn=LCZ7700AM</url>
</sample>
<sample>
<igsn>LCZ7700AL</igsn>
<url>https://app.geosamples.org/webservices/display.php?igsn=LCZ7700AL</url>
</sample>
<sample>
<igsn>LCZ7700AK</igsn>
<url>https://app.geosamples.org/webservices/display.php?igsn=LCZ7700AK</url>
</sample>
<total_counts>1489</total_counts>
<previous_list>https://app.geosamples.org/samples/polygon/-67.4156 18.6972,-67.4968 17.6568,-65.4526 17.6865,-65.5252 18.5649,-67.4156 18.6972?limit=4&amp;page_no=1&amp;hide_private=1</previous_list>
<next_list>https://app.geosamples.org/samples/polygon/-67.4156 18.6972,-67.4968 17.6568,-65.4526 17.6865,-65.5252 18.5649,-67.4156 18.6972?limit=4&amp;page_no=3&amp;hide_private=1</next_list>
</samples>

JSON format:   

{ "igsn_list": [ "LCZ7700AN", "LCZ7700AM", "LCZ7700AL", "LCZ7700AK" ], "total_counts": 1489, "previous_list": "https://app.geosamples.org/samples/polygon/-67.4156 18.6972,-67.4968 17.6568,-65.4526 17.6865,-65.5252 18.5649,-67.4156 18.6972?limit=4&page_no=1&hide_private=1", "next_list": "https://app.geosamples.org/samples/polygon/-67.4156 18.6972,-67.4968 17.6568,-65.4526 17.6865,-65.5252 18.5649,-67.4156 18.6972?limit=4&page_no=3&hide_private=1" }

 Please note: Total count of IGSN is tagged as "total_counts" in the returned content. If there are limit and page number, etc. are specified, the returned content will have <previous_list> and <next_list> tags when there are more than one page of IGSN.

Example:

curl -X GET -H "accept: application/xml" "https://app.geosamples.org/samples/polygon/-67.4156%2018.6972,-67.4968%2017.6568,-65.4526%2017.6865,-65.5252%2018.5649,-67.4156%2018.6972&hide_private=1&limit=4&page_no=2"

curl -X GET -H "accept: application/json" "https://app.geosamples.org/samples/polygon/-67.4156%2018.6972,-67.4968%2017.6568,-65.4526%2017.6865,-65.5252%2018.5649,-67.4156%2018.6972&hide_private=1&limit=4&page_no=2"

NEW curl -X GET -H "accept: application/json" "https://app.geosamples.org/samples/polygon/-43096291.5430165%20223829530.742031,-53338557.3468762%20277024863.02079,87260142.0817049%20268278668.61794,70504128.9133862%20216762812.731158,-43096291.5430165%20223829530.742031&srs=3031&hide_private=1&limit=4&page_no=2"

5. IGSN list web service for a specific field program

  •  The end point is https://app.geosamples.org/samples/field_program/[field program name].
  •  The service will retrieve all IGSNs for user defined field program. It only accepts GET request from client program.

GET API

Request headers

  • Accept: application/xml, application/json, text/xml, text/json

Request body

field program name = exact name of the field program (case sensivtive)

limit={limit}
    maximum IGSN number for each page. If it is not specified, it will default to 100.
page_no={page_no}
     page number. If it is not specified, it will default to 1.
hide_private={hide_private}
     indicates if the user would like to list private samples or not. If it is not specified, it will default to 0. If it is assigned to 1, the private samples will not be in the returned IGSN list.

Response body

HTTP status codes:

  • 400 Bad Request - Field program name is not valid.
  • 404 Not Found - No IGSNs associate with the give field program name.
  • 200 successful. It will return user IGSN(s) as following.

Output format when request is successful ( status code = 200 )

XML format:
<samples><sample>
<igsn>SSH0002V6</igsn>
<url>https://app.geosamples.org/webservices/display.php?igsn=SSH0002V6</url>
</sample>
<sample>
<igsn>SSH0002V5</igsn>
<url>https://app.geosamples.org/webservices/display.php?igsn=SSH0002V5</url>
</sample>
<sample>
<igsn>SSH0002V4</igsn>
<url>https://app.geosamples.org/webservices/display.php?igsn=SSH0002V4</url>
</sample>
<sample>
<igsn>SSH0002V3</igsn>
<url>https://app.geosamples.org/webservices/display.php?igsn=SSH0002V3</url>
</sample>
<total_counts>4339</total_counts>
<previous_list>https://app.geosamples.org/samples/field_program/Susquehanna Shale Hills Critical Zone Observatory (CZO)?limit=4&amp;page_no=99&amp;hide_private=0</previous_list>
<next_list>https://app.geosamples.org/samples/field_program/Susquehanna Shale Hills Critical Zone Observatory (CZO)?limit=4&amp;page_no=101&amp;hide_private=0</next_list>
</samples>

JSON format:   

{ "igsn_list": [ "SSH0002V6", "SSH0002V5", "SSH0002V4", "SSH0002V3" ], "total_counts": 4339, "previous_list": "https://app.geosamples.org/samples/field_program/Susquehanna Shale Hills Critical Zone Observatory (CZO)?limit=4&page_no=99&hide_private=0", "next_list": "https://app.geosamples.org/samples/field_program/Susquehanna Shale Hills Critical Zone Observatory (CZO)?limit=4&page_no=101&hide_private=0" }

 Please note: Total count of IGSN is tagged as "total_counts" in the returned content. If limit and page number, etc. are specified in URL, the returned content will have <previous_list> and <next_list> tags when there are more than one page of IGSN.

Example:

curl -X GET -H "accept: application/xml" "https://app.geosamples.org/samples/field_program/Susquehanna%20Shale%20Hills%20Critical%20Zone%20Observatory%20(CZO)&limit=4&page_no=100";

6. Sample Profile web service for IGSN

 

  • XXXXXXXX is the IGSN of sample. e.g., GEE0000O4, ODP000002
  • The service will retrieve most meta data of the sample. It only accepts GET request from the client program. When user name and password are provided, none public sample profile will be returned if the user has access permission.

GET API

Request headers

  • Accept: text/xml, application/xml, application/json, text/json

Request body

igsn={igsn}
username={yourusername}(NEW)(optional)
password={yourpassword}(NEW)(optional)

Response body

HTTP status codes:

  • 400 Bad Request -  IGSN is not valid.
  • 403 Forbidden - IGSN has either deactived or none public metadata
  • 404 Not Found - IGSN not found.
  • 200 successful. It will return meta data related to the IGSN.

Output format when request is successful ( status code = 200 )

  • XML format:

  (NEW) The returned xml file uses the following xml schema. https://app.geosamples.org/downloadSample.xsd

Notes:To be backward compatible, the old end point (https://app.geosamples.org/webservices/display.php?igsn=XXXXXXXXX)
will return the old XML format if the user executes from the browser or send ACCEPT header with 'text/html'. The old format is as following.
<results> <user_code>XXX</user_code><igsn>XXXXXXXXX</igsn><name>myname</name> .... </results>
The old end point was REST-Type so it did not follow HTTP protocol standards. If your client program used any HTTP standards, you need to adjust them according to the current documentation.

  • JSON format:   

         {
    "sample": {
        "qrcode_img_src": "app.geosamples.org/barcode/image.php?igsn=ODP000002&sample_id=Core 1-1*-1M",
        "user_code": "ODP",
        "igsn": "ODP000002",
        "name": "Core 1-1*-1M",
        "sample_type": "Core",
        "parent_igsn": "ODP000001",
        "collection_method": "Coring",
        "collection_method_description": "M: This represents material that could not be labeled with a standard core type.  This category includes limited numbers of cores which are recovered using experimental drilling methods which, once they are established, are assigned their own core type.",
        "latitude": "25.8583",
        "longitude": "-92.1833",
        "elevation": "-2827",
        "cruise_field_prgrm": "DSDP Leg 1",
        "platform_type": "Ship",
        "platform_name": "Glomar Challenger",
        "collector": "Curator",
        "collector_detail": "Texas A&M University, Integrated Ocean Drilling Program, College Station, TX, 77845, USA",
        "current_archive": "Texas A&M University, Integrated Ocean Drilling Program, College Station, TX, 77845, USA",
        "current_archive_contact": "Curator",
        "original_archive": "Texas A&M University, Integrated Ocean Drilling Program, College Station, TX, 77845, USA",
        "original_archive_contact": "Texas A&M University, Integrated Ocean Drilling Program, College Station, TX, 77845, USA",
        "parents": {
            "samples": {
                "sample": {
                    "igsn": "ODP000001",
                    "name": "Hole 1-1*"
                }
            }
        },
        "siblings": {
            "samples": {
                "sample": [
                    {
                        "igsn": "ODP000003",
                        "name": "Core 1-1*-1R"
                    },
                    {
                        "igsn": "ODP000004",
                        "name": "Core 1-1*-2R"
                    },
                    {
                        "igsn": "ODP000005",
                        "name": "Core 1-1*-3R"
                    },
                    {
                        "igsn": "ODP000006",
                        "name": "Core 1-1*-40"
                    },
                    {
                        "igsn": "ODP000007",
                        "name": "Core 1-1*-5R"
                    },
                    {
                        "igsn": "ODP000008",
                        "name": "Core 1-1*-6R"
                    },
                    {
                        "igsn": "ODP000009",
                        "name": "Core 1-1*-7R"
                    },
                    {
                        "igsn": "ODP000010",
                        "name": "Core 1-1*-8R"
                    },
                    {
                        "igsn": "ODP000011",
                        "name": "Core 1-1*-9R"
                    }
                ]
            }
        },
        "children": {
            "samples": {
                "sample": [
                    {
                        "igsn": "ODP01133U",
                        "name": "Section 1-1*-1M-1"
                    },
                    {
                        "igsn": "ODP01133Y",
                        "name": "Section 1-1*-1M-2"
                    },
                    {
                        "igsn": "ODP011342",
                        "name": "Section 1-1*-1M-3"
                    },
                    {
                        "igsn": "ODP011346",
                        "name": "Section 1-1*-1M-4"
                    },
                    {
                        "igsn": "ODP01134A",
                        "name": "Section 1-1*-1M-5"
                    },
                    {
                        "igsn": "ODP01134E",
                        "name": "Section 1-1*-1M-6"
                    },
                    {
                        "igsn": "ODP01134I",
                        "name": "Section 1-1*-1M-7"
                    }
                ]
            }
        }
    }
}

Example:

curl -X GET -H "accept: application/xml"
"https://app.geosamples.org/webservices/display.php?igsn=ODP000002"

curl -X GET -H "accept: application/xml"
"https://app.geosamples.org/sample/igsn/ODP000002" -L

(NEW) curl -X GET -H "accept: application/xml"
"https://app.geosamples.org/sample/igsn/ODP000002" -L -u yourusername

  

7. Update sample information web service

 

  • The web service https://app.geosamples.org/webservices/update.php allows the client program to update registered sample(s) metadata profile.
  • It only accepts POST requests from client programs. GET, PUT and DELETE are not supported.
  • Notes:
    • The user should use the following test URI during client program testing. So the sample profile on production site will not be changed accidently.
    • New The user can replace an existing URL using 'old_url' element. See document in updateSample.xsd schema file.
      E.G. <external_urls><external_url><old_url>http://oneurl.tobereplaced.org </old_url><url>http://oneurl.new.org</url></external_url></external_urls>

 

POST API

URI: https://app.geosamples.org/webservices/update.php

TEST URI: https://sesardev.geosamples.org/webservices/update.php

Request headers

Request body

username={yourusername}
password={yourpassword}
content={sampleinformation}

where {sampleinformation} is the xml text.

Example XML format for update one sample profile:

<?xml version="1.0" encoding="UTF-8"?>
<samples xmlns="http://app.geosamples.org"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://app.geosamples.org/updateSample.xsd ">
<sample>
<sample_type>Individual Sample</sample_type>
<name>TestSample123</name>
<material>Rock</material> 
<igsn>ABC123456</igsn> <!-- Required. -->
<!-- If no classification.xsd is specified, the older format for classification is still supported e.g., Igneous>Plutonic>Felsic -->
<classification xmlns="http://app.geosamples.org"
                xmlns:xs="http://www.w3.org/2001/XMLSchema"
                xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                xsi:schemaLocation="http://app.geosamples.org/classifications.xsd">
<Rock><Igneous> <Plutonic> <PlutonicType>Felsic</PlutonicType> </Plutonic> </Igneous></Rock> </classification>
<description>arkose</description>
<age_min>6.5</age_min>
<age_max>13</age_max>
<age_unit>years</age_unit>
<collection_method>Grab</collection_method>
<latitude>35.5134</latitude>
<longitude>-117.3463</longitude>
<elevation>781.4</elevation>
<primary_location_name>Lava Mountains, Mojave Desert, California
</primary_location_name>
<country>United States</country>
<province>California</province>
<county>San Bernardino</county>
<collector>J. E. Andrew</collector>
<collection_start_date>2002-05-30T09:30:10Z
</collection_start_date>
<collection_date_precision>time</collection_date_precision>
<original_archive>University of Kansas</original_archive>
</sample>
</samples>

  • You can update multiple samples by adding <sample></sample> block nested in <samples></samples> tag.

 

Response body

HTTP status codes:

200 Sample registered successful. The response text is like the following.

<results>
<sample>
<status>Sample [Lulin Update Status Sample test] was updated successfully with IGSN [LLS00009I].</status>
<name>Lulin Update Status Sample test</name>
<igsn>LLS00009I</igsn>
</sample>
</results>

400 Bad Request - Request body either has syntax error or xml content has errors. Error messages will look like the following.

    XML Syntax error:

<results>
<valid code="InvalidXML">no</valid>
<error>Element '{http://app.geosamples.org}user_code':......</error>
</results>

XML content error:

<results> <sample name="your sample name">
<valid code="InvalidSample">no</valid><status>Not Saved</status>
<error>You do not have permission to edit the sample metadata.</error> ......
</sample>
</results>

401 Unauthorized - When it failed to login in, it will return text as following.

<results>
<valid code="InvalidAuth">no</valid>
<error>Invalid login, username not known or password not matched</error>
</results>