Developer Documentation


Getting started page explains what an embedded app and an integrated apps are. If you haven’t already, please looks through this website and familiarize yourself with key Tradeshift platform elements such as UI Components and API. This page is focused on application development.

Creating an Embedded App

Tradeshift maintains two main environments – and   Both are production-level environments.   Sandbox is where you should do your development, and when you are ready, you can deploy your app on production. 

Creating an App

To create an app, you need an account on Tradeshift, which you can create from the home page.

Once you login, you need to go to the Appstore and find the Developer App.  When you activate it, it will ask you to pick a Vendor Id.   All applications on Tradeshift are identified using VendorId.AppName.  For example, Tradeshift.Developer is the app you just installed.   So please pick a VendorId that you will want to also use on production. VendorId should not have any dots in its name

Screenshot 2016-06-28 06.54.17

Once you setup VendorId, you can then create a new app.  Click Create App.


Screenshot 2016-08-20 09.45.08

App Parameters

The App parameters are described in the Developer App.

Screenshot 2016-07-13 16.37.04

Creating the Simplest App

The simplest app possible simply shows a URL inside Tradeshift.  Since that does not need the app to authenticate against Tradeshift APIs, you don’t need to setup any OAUTH2 parameters.   To create the simplest app that simply shows a google map, paste this as Main URL:!1m10!1m8! 1m3!1d12613.0080182887!2d-122.39574375!3d37.78413355!3m2!1i1024!2i768!4f13.1!5e0!3m2!1sen!2sus!4v1433284539696

Once the app is saved, you can activate it, and you should see a map inside Tradeshift’s Chrome. 

Screenshot 2016-06-30 13.03.27

Note that the main app is served from a server other than Tradeshift (in this case Google). This means that you will need to host the server part of the embedded app wherever is most convenient to you. This both allows you to integrate existing applications with Tradeshift easily, and in general use infrastructure you are probably already managing.

Main URL Gotcha and X-Frame-Origin

Some development frameworks automatically send codes to prevent their pages to be included inside IFrames.  They will either send HTTP Header X-Frame-Origin: SAMEORIGIN or X-Frame-Origin: Deny.   The example above with google maps, we used the embedded code for maps, which does not send this.    See RFC 7034 for more information on X-Frame-Origin header.  Here is the Chrome console log that shows how the issue manifests itself (the user simply sees Tradeshift chrome with blank content).  

Screenshot 2016-06-30 13.12.40

We recommend that you ensure your server does not send X-Frame-Origin header – that will allow Tradeshift to embed your iframe without issues.  You could specify ALLOW-FROM, but it’s only supported by some browsers (Firefox and IE), and will show warnings for Chromium-based browsers.

Releasing App into Appstore

When you create an app, it is created in a hidden category, which means it’s not available in the Appstore, but can be installed by you for testing purposes (follow the link under Actions).

In order to publish the app in the Appstore, you will need to submit it for review to Tradeshift.  Email to with the VendorId and AppId, so we can review it and unhide it.   Tradeshift will assign it to one of the categories (feel free to recommend this).  

Once Tradeshift approved the App, it then becomes available in the Appstore for all organizations to activate.  

Once you tested the app on, then you can deploy it on production, and follow the same steps with Tradeshift doing a final review. For consistency, please use the same VendorId in both environments.  

Code Samples

Full App Samples

Tradeshift created several apps to act as samples for you to use to understand how the architecture looks like, and how to authenticate against Tradeshift’s servers. We have one app in Java using Sprint.Boot, Node.js, and PHP (Symphony) Please view them here on GitHub, and feel free to fork! Here is a video (12 min) showing how to deploy the Java Spring.boot app to Heroku and how to fully configure it to work with Tradeshift. We highly recommend you go through this exercise as it will help you understand how everything fits together.

Screenshot 2016-08-31 01.35.13

Sample App – Java Spring.Boot. Each tab shows a different aspect of Tradeshift Platform and has additional information explaining how it works.

Development Tip

Since during development, you often need to iterate on your app and Tradeshift servers need to be able to reach it to pass authentication tokens, we recommend that you use a tool such as ngrok or localtunnel, which allow you to expose your local development environment to the public internet.

App Authentication

Most application will need to interact with Tradeshift’s API.  To enable that, Tradeshift implemented OAUTH2 standard (RFC 6749).   For Apps, we use 3-legged protocol of OAUTH2.  When activating the app, the user will be asked to authorize that the app has permissions it needs to the account. 

When creating or editing an app, you can set the app secret and get the client identifier to use. Additionally, you will need to choose which resources your app will need to access (modeled as OAUTH Scopes).

OAuth2 Authentication Sequence


Step 1 – Redirect to Authorization Server to Obtain Auth Code

App vendor provides the Main URL and Redirect URL so that Tradeshift server knows where to communicate information in the authorization sequence. The Main URL will redirect to the following URL (TS authorization server) to obtain Authorization Code{vendor_id.app_id}&redirect_uri={redirect_uri}&scope=offline

Tradeshift authorization server then sends the following HTTP response:

HTTP/1.1 302 Found

Location: {redirect_uri}?state&code={auth_code}


vendor_id = Eltec; app_id = MapApp

Redirect URL =

When a user opens the iframe app, app vendor’s Main URL redirects to

Then the Tradeshift authorization server sends the following HTTP response:

HTTP/1.1 302 Found


Step 2 – Exchange Auth Code for Access Token

The app vendor makes a request to the token endpoint by making this call


  • Authorization: use Basic authorization. The parameter value is the Base64 encoded value of “username:password”. The username is {vendor_id.app_id}. The password is a OAUTH2 Client Secret that you set in the Developer app.  
  • Body content type: application/x-www-form-urlencoded
  • Send parameters in the POST body with a character encoding of UTF-8:
  • grant_type: value must be set to “authorization_code”
  • code:  The authorization code received in the previous step

Response should contain the following:

  • access_token: The token that can be used to access API resources
  • token_type: value is “Bearer”
  • expires_in: value is 30, meaning the access token expires in 30 minutes
  • id_token: a JSON Web Token (JWT) containing multiple assertions, including the ID of the user and the account the user belongs to. Needs to be decoded. For a web decoder: For details about JWT, see
  • client_id: the app vendor ID and app ID
  • refresh_token: after access token expires, the refresh token can be used to obtain new access tokens. The new access token will expire in 10 minutes. Refresh token never expires and can be used multiple times

Example Request: 

  • Full App Id Eltec.MappApp
  • Client secret = test123 (set up in the Developer App)
  • Value to be Base64 encoded: Eltec.MapApp:test123 (used in Basic authentication)


Authorization=Basic RWx0ZWMuTWFwQXBwOnRlc3QxMjM=&grant_type=authorization_code&code=sE7RFd48QkijbjZE

Example Response (includes access, id and refresh tokens)

 “access_token”: “EQ90um+/ODi7Gf1E98CSXNIhIVUY8w96n+6vKf5JtWwr2awGQoACND0XCVOaeza+HNocg10QujGnw6VlxMng3z7eVe6RCFAlGayFD4p3wVvaWzQKECwRoVxFjwcX3XwOcwfE1tT1MTAHGKb435VUaIN7peD9zo6L5SbdTuX5jNZzz4GWiZjdDo7iWVZQ0HmB/HzrIi6goTIohazOUJepAEZWV8koHrMwpqJFaKAaFJDgecJMREm18eaXhZ55Un2L6wwPOqF3KPV0dj/7ycNVRPlWrUC6M1oVlH4zsrdEGVMvN6ccpnD3pcDskQwLNtmos8srCXvy7doMsKmm1tliB8hmrzh/P9Eywjw8xSKeiW0wWGpe/oYLEgL10loqVGUn1vGRBRR5GUjIs+ysBVAAWgIAAQ==”,

 “token_type”: “Bearer”,

 “expires_in”: 30,

 “id_token”: “eyJhbGciOiJub25lIn0.eyJleHAiOjE0MzYyMjYyNzAsInN1YiI6InNtYStzYXJhaGJyb3duQHRyYWRlc2hpZnQuY29tIiwidXNlcklkIjoiMjFkMjVjOTItYzBmNy00NGZkLWJiMzgtMzhiZjZmYmE3NDBmIiwiYXVkIjpbIkFCQ0luYy5NYXBBcHAiXSwiaXNzIjoiaHR0cHM6XC9cL2FwaS1zYW5kYm94LnRyYWRlc2hpZnQuY29tXC90cmFkZXNoaWZ0XC8iLCJqdGkiOiJqMmFyQXhRNHJOMFVVQm1qIiwiY29tcGFueUlkIjoiMDZhY2Q5MmItNmNiNS00OWZlLWFmZWUtOWY3YTBmZjMxODU1IiwiaWF0IjoxNDM2MjI2MjQwfQ.”,

 “client_id”: “ABCInc.MapApp”,

 “refresh_token”: “EQ90um+/ODi7Gf1E98CSXNIhIVUY8w96n+6vKf5JtWwr2awGQoACS8+RJkINGl1T50JQSVbLfxNhMPYb50Wv/t1ULeNdiPHrVqU1r/1wkjw56M1xhYSkkrXJsS25KCfHecV8lbrCt9d80ZASR6QrHd1O5/gWQ3Hzg09xCefVLm2Apq1ZRihWUIx2CEQU6SR+0U6cNbbtY7JdW/iwhD2ygPW40deguOrqYHtwZKqG/vSR1InWMBEzRNC2EZmSKkAfx+qoQa8ZDGcLRMvn3d4Jqc2W57YNzpOSTu/z8+Yeiob1Eeg3Ocse44yivDEkv9N82AgLSxpkQgWhZglkh+OgSnFU0Lt5dvQl/KuRb8+CgdFAg6usaUU+NYf/31pp68kZb5G4+7bxcUjAjPG7BVADWgIAAQ==”

Passing Tradeshift User Identity to Apps

id_token described above is a standard JWT implementation. JWT is described in RFC 7519. The JWT token has everything the app needs to understand under which context (user and company) it’s running. If the app is integrating with a system that has its own user space, it is encouraged to do user mapping between tradeshift’s user ids and internal user ids. This way the app can render itself properly for the current user. The JWT token is unsigned, which means it has alg = none, and no signature. However, because it’s received in response to a specific request from third party servers, no signature is needed to validate the token.

Here is the decoded information Tradeshift passes to clients:

  alg: "none"
  exp: 1436226270,
  sub: "",
  userId: "21d25c92-c0f7-44fd-bb38-38bf6fba740f",
  aud: [
  iss: "https:\/\/\/tradeshift\/",
  jti: "j2arAxQ4rN0UUBmj",
  companyId: "xxxxxxxx-6cb5-49fe-afee-9f7a0ff31855",
  iat: 1436226240

The above claims are (most standard JWT claims, last two Tradeshift-specific):

  • exp – Expiration time
  • sub – Subject, or Tradeshift user’s email
  • aud – Audience, the recipient JWT is intended for. The value here is the App Name
  • iss – Issuer, or URL of server that issues the JWT token
  • jti – JWT Unique identifier
  • iat – Issued at time
  • companyId – Tradeshift’s organization id where the app is activated
  • userId – Tradeshift’s user UUID

What About Single Sign On (SSO) capability?

The user logs into Tradeshift, so if SSO is configured on their account, by the time the App is invoked, the user is already logged in. The app itself, during initial request, can find out the user that it’s running under using the regular OAuth2 flow and getting the decoded JWT tokens that Tradeshift passes as id_token. Then the app can set the current session and current user appropriately, including if it needs to connect to other APIs.


Your app calls Tradeshift API, and when activating the app, the user will need to . In the developer app you can control which permissions your app needs. When activating the app, the user or administrator will review permissions that it needs, so please only enable the permissions you really need.  The permissions that have lock next to them you cannot change.

The permissions can be enabled or disabled in the Developer App. The permissions map to OAUTH2 scopes.

Screenshot 2016-08-13 15.16.41


Often, the embedded apps need to react to events in Tradeshift.  For example, when an invoice or a purchase order is received into a company that has an app activated, the app may need to respond – either store the document, or take some other action.

Webhooks allow you to react to certain events in Tradeshift.  When one of those events happens, we’ll send a HTTP POST request to the webhook’s configured URL.  Webhooks are configured on the application level, and when triggered, they send information about which company they have been installed with as parameters.  The body of the event contains additional information, such as the document that was received.

You can configure webhooks in the Developer App.   Edit your app, scroll down to Webhooks section, and click Add.  You will need to name the webhook, and provide a URL where the POST request will be made.

Screenshot 2016-08-20 09.46.40

Here is an example request, for AFTER_DOCUMENT_RECEIVE webhook:

POST ?event= AFTER_DOCUMENT_RECEIVE&id={event uuid}&tsUserId={user uuid}&tsCompanyAccountId={account uuid}&tsUserLanguage={user language}


  • event: Event Name, e.g. AFTER_DOCUMENT_RECEIVE
  • id: event id
  • tsUserLanguage: the user’s language, e.g. en_UK
  • tsUserId: user id if relevant.  Otherwise, you’ll receive user id of the user who created the account
  • tsCompanyAccountId: company where the app has been activated

Tip:  If you want to view requests so you have a sample to develop against, you can configure the webhook to point to service such as or

Webhook Events

When configuring a webhook, you can choose which events you would like to receive payloads for. Document-related webhooks currently only support these document types: Invoice, Order, and OrderChange.

Document Sending Events

  • DOCUMENT_VALIDATING – First step – before trying to send the document, check that it has all the needed information.
  • DOCUMENT_SENDING – Started sending the document, waiting for receipt confirmation.
  • DOCUMENT_SENT – Last step. Sending is complete.

Document Receiving Events

  • BEFORE_DOCUMENT_RECEIVE – fires when the document is first arriving to the receiver
  • AFTER_DOCUMENT_RECEIVE – fires after the document was fully received.

Network Connection Events

  • NETWORK_REQUEST_RECEIVED – company received a new network connection request
  • NETWORK_REQUEST_ACCEPTED – network connection was accepted by the other party
  • NETWORK_RESPONSE_RECEIVED – received response to network request

App Settings

Sometimes an embedded app needs to store some information specific to each activation.  Tradeshift exposes an API that allows to store key-value pairs, or settings, in the app activation.

API Usage Best Practices

The Tradeshift REST API is can be used in a number of ways. Here are some best practices when you develop with the API.

Client Considerations

  • Always send a User-Agent header in all requests. The header should identify your client and version. Use something like BananaCorpClient/3.4.
  • Always send an Accept header indicating either application/json or text/xml
  • All requests can fail in a number of ways. For application errors, we always return the same error structure, so be prepared to handle that always. The structure is described on the REST API page.

Document Synchronization

  • One often seen use of the API is to synchronize documents to another system. This is possible by polling the external/documents resource for changes. There are two strategies for this:
    • Poll for changes since last poll.  When polling for changes since last poll, simply do a poll, save the timestamp, and include it in the “since” query parameter in the next poll.
    • Poll for unknown documents. When polling for unknown documents, do a poll, loop through all received documents, use the external/documents/{documentId}/tags/{tag} resource to PUT a custom tag to the document, such as “POLLED_BY_BANANACORP”. All requests to external/documents should then include a withouttag=POLLED_BY_BANANACORP query parameter, and will only retrieve documents which do not have the corresponding tag.
  • There’s currently no rate limiting on the API, which means you need to be careful not to issue too many requests. Since document transfers in Tradeshift are asynchronous by nature, there shouldn’t be a need to poll more often than once per 5 minutes, for example.
  • Sending Documents. When sending documents, be aware of the asynchronous processing. Even though the dispatch request returns 200 OK, the dispatch might fail later on, for example due to email bounces, custom validation rules on the receiving side, and so on. If you want to be sure the document is delivered, poll the external/documents/{documentId}/dispatches/latest resource until the status is COMPLETED. If the status changes to FAILED, the dispatch failed, and it will contain information about the failure. If it’s FAILED_TRANSIENT, the dispatch failed, but it will be retried automatically.

3-legged OAuth2

3-legged OAuth is used by Tradeshift to enable Embedded Tradeshift Apps to access the REST API. When creating an app, a consumer key will be issued to the app. Since the app can be installed by many users, Tradeshift uses the 3-legged OAuth token to identify the actual user. The token will be different for each user who has installed the app.

2-legged OAuth1

When developing integration (not embedded) Apps, you can get access to your own account by installing the Access to own account app. When the app is installed, go to the app page to get the OAuth1 parameters you need to run the examples below. The examples below only use a small portion of the API. Look at the detailed API to get the full overview.

We are working on full OAUTH2 support for integration apps.

We also have a public Git repository at Github, which contains some examples.

Java Client

This Java client example is done using Jersey client and the OAuth client+signature contributions in Java. Running this example will create a request similar to the HTTP example. Before running the example, replace the keys, secrets and TenantId with that of your own account.

This same code is packaged together in a Maven project available on GitHub.

import com.sun.jersey.api.client.*;
import com.sun.jersey.oauth.client.OAuthClientFilter;
import com.sun.jersey.oauth.signature.OAuthParameters;
import com.sun.jersey.oauth.signature.OAuthSecrets;

public void getConnections() {
Client client = Client.create();
OAuthParameters params = new OAuthParameters().signatureMethod("HMAC-SHA1").consumerKey("key").token("token").version();
OAuthSecrets secrets = new OAuthSecrets().consumerSecret("secret").tokenSecret("tokenSecret");
OAuthClientFilter filter = new OAuthClientFilter(client.getProviders(), params, secrets);
WebResource res = client.resource("");
String networkResult = res.header("X-Tradeshift-TenantId", "634a8633-6368-433a-bf33-7904f5080db0")
.header("User-Agent", "TradeshiftJerseyTest/0.1")

To run this example you will need the following Maven dependencies:



This example uses oauth2 and will list all your documents. The response is in JSON.

import oauth2 as oauth

CONSUMER_KEY='ExampleVendorSnCSYZCHW' # Vendor id + random string (From App Developer (App->Tools->Tradeshift API Keys)
CONSUMER_SECRET='Qrjhva4g7SugSsHON1cSDpVJf5qUub1UNIAfcwiq' # Example secret (for the app to be authorized, from App Developer (App->Tools->Tradeshift API Keys))
TOKEN_KEY='3jT@egqm4mscm7@p85@nLcycjgYz@5' # Example token key, per user
TOKEN_SECRET='AF5pMGWZ7B3c7Etp@kZdl80mmyGdqvcQ24CrSVjf' # Example token secret, per user
TENANT_ID='alg7y5i8-1455-4612-c9d1-c1a107ef1dfd' # Example tenant id. Found in HTML source on every page or in the App 'API Access to own Account'

def oauth_req(url):
consumer = oauth.Consumer(key=CONSUMER_KEY, secret=CONSUMER_SECRET)
token = oauth.Token(key=TOKEN_KEY, secret=TOKEN_SECRET)
client = oauth.Client(consumer, token)

http_headers = {}
http_headers['X-Tradeshift-TenantId'] = TENANT_ID
http_headers['User-Agent'] = 'MegaPythonAPIster 2.0'
http_headers['Accept'] = 'application/json'

resp, content = client.request(
return content

# The base url of the the sandbox API
baseurl = ""

# The specific url of the document resource
url = baseurl + "documents/"

print oauth_req(url)

2-legged OAuth

Please note that 2-legged OAuth is deprecated. Use 3-legged, as described above, instead. If you require 2-legged OAuth, you need to contact Tradeshift to set up the keys.

Below is an example of a common 2-legged OAuth integration example where a Consumer (a user of the API on behalf of a Tradeshift Tenant) request the network list for a given Tenant. A Consumer is always associated with a unique Consumer Key and a Consumer Secret which is used for signing OAuth requests. After a Tradeshift Tenant has authorized a Consumer to act on its behalf, the Consumer will be able to perform request and access the Tenants data – the Tenant that a Consumer wishes to act on behalf of is indicated using the X-Tradeshift-TenantId HTTP header.

In this example the Consumer has a Consumer Key with value “key” and a Consumer Secret with the value “secret“. The Consumer is acting on behalf of a Tenant (which has previously authorized the Consumer to act on its behalf) with Tenant ID634a8633-6368-433a-bf33-7904f5080db0“.

Please note that the OAuth protocol is based on timestamps and nonces to prevent replays, so the examples below cannot be run directly, they simply show the structure of requests. Using an OAuth API to build the requests is strongly recommended.

HTTP Communication

This HTTP example uses a randomly-generated UUID as nonce. It requests a response in XML format. The Authorization: header wraps multiple lines in the example for legibility, but would be a single header line in a real request.

The full HTTP request:

GET /tradeshift/rest/external/network/connections HTTP/1.1
X-Tradeshift-TenantId: 634a8633-6368-433a-bf33-7904f5080db0
Accept: text/xml
Authorization: OAuth oauth_signature="%2Bno%2BkynZILdt%2Fsdxg%2BYoyiHVwUE%3D", 

An example response to this request could be like:

200 OK
Content-Type: text/html

<ns3:ConnectionList xmlns:ns3="" xmlns:ns2="" 
itemCount="0" itemsPerPage="0" numPages="0" pageId="0">
<ns3:DocumentProfile id="str">


This sample in Python is dependent on oauth2 and will list all your documents. The response is in JSON. Note how the OAuth header is created according to the HTTP example.

import urllib, urllib2, time, sys
import oauth2 as oauth # Make sure you've installed oauth2:

http_headers = {}

# The base url of the the sandbox API
baseurl = ""

# The specific url of the document resource
url = baseurl + "documents/"

# OAuth credentials... put in your own
key = 'xxx'
secret = 'yyy'
tenant = 'zzz'

# Create the OAuth header, including the signing of our request
consumer = oauth.Consumer(key=key, secret=secret)
params = {
'oauth_version': "1.0",
'oauth_nonce': oauth.generate_nonce(),
'oauth_timestamp': int(time.time()),
'oauth_consumer_key': consumer.key,
oauthheader = oauth.Request.from_consumer_and_token(http_method="GET", http_url=url, parameters=params, consumer=consumer, token=None)
oauthheader.sign_request(oauth.SignatureMethod_HMAC_SHA1(), consumer, None)

# Build the Authorization header by stiching together all parts of the OAuth header
oauthstring = "OAuth "
for key, value in oauthheader.iteritems(): 
url_encoded_value = urllib.quote(str(value)) # Make sure to URL encode the header, since the OAuth signature might very well contain non-valid characters
oauthstring += key + "=" + url_encoded_value + ","

http_headers['Authorization'] = oauthstring

# The 3 other mandatory HTTP headers
http_headers['X-Tradeshift-TenantId'] = tenant
http_headers['User-Agent'] = 'MegaPythonAPIster 1.0'
http_headers['Accept'] = 'application/json'

# Time for the actual HTTP call
req= urllib2.Request(url, headers=http_headers)
result = urllib2.urlopen(req)

except Exception as e:
print e


Java Client

This Java client example is done using Jersey client and the OAuth client+signature contributions in Java. Running this example will create a request similar to the HTTP example.

import com.sun.jersey.api.client.*;
public void test() {
Client client = Client.create();
OAuthParameters params = new OAuthParameters().signatureMethod("HMAC-SHA1").consumerKey("key").version();
OAuthSecrets secrets = new OAuthSecrets().consumerSecret("secret");
OAuthClientFilter filter = new OAuthClientFilter(client.getProviders(), params, secrets);
WebResource res = client.resource("");
String networkResult = res.header("X-Tradeshift-TenantId", "634a8633-6368-433a-bf33-7904f5080db0")
.header("User-Agent", "TradeshiftJerseyTest/0.1")

To run this example you will need the following Maven dependencies:


PHP Client

Requires the PHP OAuth PECL extension –

$consumerKey = 'key';
$consumerSecret = 'secret';
$oa = new OAuth($consumerKey, $consumerSecret, OAUTH_SIG_METHOD_HMACSHA1,OAUTH_AUTH_TYPE_URI);
// Set token and token secret (remove this line if no token/token secret is applicable)

$res = $oa->fetch('', null, 'GET',
'Accept' => 'application/json',
'X-Tradeshift-TenantId' => '634a8633-6368-433a-bf33-7904f5080db0',
'User-Agent' => 'TradeshiftPHPTest/0.1',

Downloading all documents with PHP

Using the REST API, it is possible to sync all documents to a local filesystem. The download-documents.php script is a PHP script which saves all documents which have changed since the last run.

Save the PHP script as a file and run it. Instructions are given in the script itself.

Requires the PHP OAuth PECL extension –

Listing documents and connections with Visual Basic

Example in VB that shows how to call the REST API using the OAuthBase class.

Note that HttpUtility.UrlEncode(url) generates an encoding that cannot be used, wherefore we’ve wrapped it and added %xx values with upper case letters and enforce the use of %20 for spaces (unlike + which HttpUtility uses).

' We use the C# OAuthBase class that can be found here:
' Written by Eric Sandler (
Dim OAuthBase As New OAuth.OAuthBase()

' The API demands that we declare what client we are using
Dim clientName = "Tradeshift.Net Example Client Beta 1.0"

' What type of data do we expect back? The other option is "application/json"
Dim dataType = "text/xml"

' Your OAuth credentials go here. Ask tradeshift support in case you have yet not received them
Dim token As String = String.Empty
Dim tokenSecret As String = String.Empty
Dim consumerKey As String = "xxx"
Dim consumerSecret As String = "xxx"

' The root of the tradeshift sandbox API
Dim baseUrl = ""

Sub Main()
Dim tradeshiftUserTenantId = New Guid("your-tenant-id-here")


End Sub

Public Sub list_connections(ByRef tradeshiftTenantId As Guid)
Dim url = String.Concat(baseUrl, "network/connections/")

Dim request = create_oAuth_request(New Uri(url), tradeshiftTenantId)
Dim response = New StreamReader(request.GetResponse.GetResponseStream())
Catch e As WebException
End Try

End Sub

Public Sub list_documents(ByRef tradeshiftTenantId As Guid)
Dim url = String.Concat(baseUrl, "documents/")

Dim request = create_oAuth_request(New Uri(url), tradeshiftTenantId)
Dim response = New StreamReader(request.GetResponse.GetResponseStream())
Catch e As WebException
End Try

End Sub

Private Function create_oAuth_request(ByRef url As Uri, ByRef tradeshiftTenantId As Guid, Optional ByVal method As String = "GET") As HttpWebRequest
Dim timeStamp = OAuthBase.GenerateTimeStamp()
Dim nonce As String = OAuthBase.GenerateNonce()
Dim normalizedUrl As String = String.Empty
Dim normalizedRequestParameters As String = String.Empty

Dim sig As String = OAuthBase.GenerateSignature(url, consumerKey, consumerSecret, token, tokenSecret, method, timeStamp, nonce, OAuth.OAuthBase.SignatureTypes.HMACSHA1, normalizedUrl, normalizedRequestParameters)
Dim oAuthHeader = String.Format("OAuth oauth_version=1.0, oauth_signature_method=HMAC-SHA1, oauth_nonce={0}, oauth_timestamp={1}, oauth_consumer_key={2}, oauth_signature={3}", nonce, timeStamp, consumerKey, UrlEncodeUpperCase(sig))

Dim request As HttpWebRequest = WebRequest.Create(url)
request.Method = method
request.Accept = dataType
request.UserAgent = clientName
request.Headers.Add("X-Tradeshift-TenantId", tradeshiftTenantId.ToString())
request.Headers.Add("Authorization", oAuthHeader)

Return request
End Function

' Note: This is by no means a complete implementation of the percentage style URL encoder, needed to generate proper
' OAuth headers, but good enough for demo purposes
Private Function UrlEncodeUpperCase(ByVal url As String) As String

' Encodes the string, and replaces all letters in percentage encodings to CAPS
Dim newurl = HttpUtility.UrlEncode(url)
newurl = Regex.Replace(newurl, "(%[0-9a-f][0-9a-f])", Function(c) c.Value.ToUpper())

' Note: UrlEncode uses old URL encoding standards, and replaces spaces with + instead of proper percentage encoding
' where you'd replace spaces with %20, which won't be accepted when calculating the OAuth sign, so we change it back
Return newurl.Replace("+", "%20")
End Function