The DFDS Logistics API allows only authenticated access.
Please contact your DFDS representative if you do not already have access to this API, or if you need access to a specific feature.
Your representative will create a DFDS user account, which can be used to enable manual and server-server access to the API as described in the following sections.
Server-server communication with the DFDS Logistics API requires a DFDS service account. To create a DFDS service account, you need an access token to authenticate towards the Service Account part of the API.
Please follow the steps in user authentication to request this access token.
Upon creation of a new DFDS service account a private key is returned, and this key is used when generating the access token that is used in all subsequent requests. These steps are covered in depth in the service authentication section.
The high level flow is then:
Authentication is based on the OAuth2 protocol using username/password grants. Use this type of authentication when a person is communicating with the API. This includes the process of setting up server-server authentication as described in the Service Authentication section. However this is not suitable for actual server-server authentication.
POST https://logisticsapi.dfds.com/api/token
This endpoint accepts username/password combinations and issues bearer tokens which can be used to access the API. This example will request an access token for the user account account@dfds.com using the password PASSWORD.
Content-Type: application/x-www-form-urlencoded
grant_type=password&username=account%40dfds.com&password=PASSWORD
The response for a successfull authentication request will include a token and expiration time. You should use the access token the entire user session. Do not issue a new access token for every request. Please refer to the token validity section for more details about the validity of the issued tokens.
{
"access_token":"N1qaNDfDIhgjj-yNSZS8UIuOBasdErEVy_7ebmsiGFBgj82OVuSzp5t46cCT8hAK72kh0s0igs...",
"token_type":"bearer",
"expires_in":1199
}
If authentication fails because of a wrong username/password combination, you will get a response similar to this.
HTTP/1.1 400 Bad Request
Content-Type: application/json
{"error":"invalid_grant"}
When communicating with the API, the access token must be included as a bearer token in the request header. An access token is required for all requests towards the API. This includes server-server communication as described in the service authentication section.
Authorization: Bearer [token]
For security reasons, an authentication request may be challanged. The challenge is based on Google ReCaptcha. The public key is
[CaptchaPublicKey]
When this is the cause for a failed authentication, the following header will be included in the authentication response.
X-ChallengeRequired: true
This challenge must be solved in a standard token request. Include the captca response in a header value.
X-CaptchaAuthChallengeResponse: [value]
If the authentication fails because of an invalid captche response, the following header is included in the response.
X-ChallengeNotAccepted: true
Issued access tokens are generally valid for 20min. Do not rely on this, use the expiration time returned from the token endpoint instead.
When an access token expires, you must supply the username/password to issue a new token.
Service authentication is intended for server-server communication. To use service authentication, you must create a service account. When a service account has been created, you can communicate with this API without a username/password combination. See the authentication section for details.
Service accounts can be created, viewed and deleted using the API. You may create any number of service accounts in segments appropriate to your system. You may assign any feature access to a service account which the calling account itself has access to.
When the account is created, a private key is returned. The private key is later used to request the server-server access token as described in the service authentication section. We are not able to retrieve the private key for you - we will only keep the corresponding public key.
Keep the private key secure! You are responsible for securing the private key. Do not put it in source control. If you suspect your private key may have been compromised, delete the account immediately and contact DFDS.
A service account is created by posting account details to the serivce account endpoint.
POST https://logisticsapi.dfds.com/api/authentication/serviceaccount
Please remember that all communication with the API requires an access token to be included as a bearer token in the request header. When requesting, managing or deleting a service account, the access token to use is your personal access token. The process of requesting a personal access token is described in the user authentication section.
Authorization: Bearer [token]
The post to create a service account requires the following fields.
Name | Description | Type |
name | The name used to identify this service token. The name is meant to help you identify your service accounts. | string |
description | A description of the use of this token. This information is for your own reference only. | string |
A valid email associated with your sevice account. This address must be unique. It is used to identify the service account. It should not be associated with a single individual person. Information or issues related to the service account will be communicated to this email address. | ||
expirationTime | The date and time of expiration in UTC. The account will be deactived on this date. | date |
features | The set of features this service account has access to. Please refer to the feature access section for the meaning of these identifiers. | array of number |
The sample request below, create a service account.
{
"name": "nameofserviceaccount",
"description": "a description",
"email": "service@company.com",
"expirationTime": "2020-12-31",
"features": [0, 1, 2]
}
The response of a successful account creation will include all the supplied details. Additionally it will include an id for the account and the generated private key. See below for structure of said private key.
{
"privateKey":"...",
"serviceAccount": {
"id": 1794,
"name": "name",
"description": "description",
"email": "prod-trackingupdate@company.com",
"expirationTime": "2018-09-09T10:00:00Z",
"creationTime": "2018-01-09T10:00:00Z",
"verified": false,
"features": [2,5,7]
}
The 2048 bit public and private key is returned with individual RSA parameters as Base64 encoded byte arrays. An example is shown below.
Store the private key in a safe place. The private key does not expire, but is valid as long as it's not revoked for some reason.
The key is later used to request the server-server access token as described in the service authentication section.
{
{
"privateExponent": "agK1Ogn5ptgCmo2O4s3yLU345j0rM+Y0eO23Yj2fCPpgLbDigRcIzDyJdt6EMXZLBRHdC41K7iTD...",
"exponentOne": "Dt6xKK2scgrrCLsl783Av6eLz8GVXYqTjIdHIs63jPeUwGtwfw1V65lU145oj7zk4yigeg8Kys885V7p...",
"exponentTwo": "dnAOLuBv5fosSNbMaoSux+E1mpp5yZJTgtv/mP5YSMaBhFVH0vDJa0uh+i8itQHTi2j5ogOB0EDh36p9...",
"publicExponent": "AQAB",
"coefficient": "c9034KqiyU+2JDjn2u1U1j2SEXKHfG9ARTavjihz26v4d5NaHGstseGDWfso7sCk/AB0J2gN/HCjCZdZ...",
"modulus": "uzOgCs9xokwX4l4xdclcqt/n2+Wo/3NzsRN5i/ikUySEsANP8+zyhgHDh4IYC7dFudrc3X4MO593nhj/QtyQ...",
"primeOne": "zuf6UCkmys8IWeiqLMUA1mHOLNy7XBHjCS0YIxqLIAVPrkOqCokFYJkUl+2+dXr6rSP2JSai8MhvkHVUsZh...",
"primeTwo": "556+ilkXsxNEh7FzFbQMEvHdIkjhK0yNNZeEOW4SwTpw5XfP5/zLWi3vi0ijkYsYm3GGOcpfXTeRRLlFDxl..."
}
}
The following example code can be used to compute as SHA256 signature. This is used whenever a token is needed to communicate with Velocity Public API.
public static string Sign(string token)
{
var partialToken = $"{base64UTF8EncodedHeader}.{base64UTF8EncodedClaims}"
using (var rsa = new RSACryptoServiceProvider())
{
rsa.ImportParameters(RSAParameters());
rsa.PersistKeyInCsp = false;
return Convert.ToBase64String(rsa.SignData(Encoding.UTF8.GetBytes(partialToken), "SHA256"));
}
}
public static RSAParameters RSAParameters()
{
var privateExponent = "agK1Ogn5ptgCmo2O4s3yLU345j0rM+Y0eO23Yj2fCPpgLbDigRcIzDyJdt6EMXZLBRHdC41K7iTD...";
var exponentOne = "Dt6xKK2scgrrCLsl783Av6eLz8GVXYqTjIdHIs63jPeUwGtwfw1V65lU145oj7zk4yigeg8Kys885V7p...";
var exponentTwo = "dnAOLuBv5fosSNbMaoSux+E1mpp5yZJTgtv/mP5YSMaBhFVH0vDJa0uh+i8itQHTi2j5ogOB0EDh36p9...";
var publicExponent = "AQAB";
var coefficient = "c9034KqiyU+2JDjn2u1U1j2SEXKHfG9ARTavjihz26v4d5NaHGstseGDWfso7sCk/AB0J2gN/HCjCZdZ...";
var modulus = "uzOgCs9xokwX4l4xdclcqt/n2+Wo/3NzsRN5i/ikUySEsANP8+zyhgHDh4IYC7dFudrc3X4MO593nhj/QtyQ...";
var primeOne = "zuf6UCkmys8IWeiqLMUA1mHOLNy7XBHjCS0YIxqLIAVPrkOqCokFYJkUl+2+dXr6rSP2JSai8MhvkHVUsZh...";
var primeTwo = "556+ilkXsxNEh7FzFbQMEvHdIkjhK0yNNZeEOW4SwTpw5XfP5/zLWi3vi0ijkYsYm3GGOcpfXTeRRLlFDxl...";
return new RSAParameters()
{
D = Convert.FromBase64String(privateExponent),
DP = Convert.FromBase64String(exponentOne),
DQ = Convert.FromBase64String(exponentTwo),
Exponent = Convert.FromBase64String(publicExponent),
InverseQ = Convert.FromBase64String(coefficient),
Modulus = Convert.FromBase64String(modulus),
P = Convert.FromBase64String(primeOne),
Q = Convert.FromBase64String(primeTwo)
};
}
var moment = require('moment');
var NodeRSA = require('node-rsa');
var header = {
typ: "JWT",
alg: "RS256"
};
var claims = {
account: "account@domain.com",
expiration: moment().add(30, 'minutes').format()
}
var headerJson = JSON.stringify(header);
var encodedHeader = Buffer.from(headerJson, 'utf8').toString('base64');
var claimsJson = JSON.stringify(claims);
var encodedClaims = Buffer.from(claimsJson, 'utf8').toString('base64');
var partialToken = encodedHeader + "." + encodedClaims;
var key = new NodeRSA();
key.importKey({
// Modulus
n: Buffer.from("...", "base64"),
// Public Exponent
e: Buffer.from("...", "base64"),
// Private Exponent
d: Buffer.from("...", "base64"),
// Prime One
p: Buffer.from("...", "base64"),
// Prime Two
q: Buffer.from("...", "base64"),
// d mod (p - 1) | Exponent One
dmp1: Buffer.from("...", "base64"),
// d mod (q - 1) | Exponent Two
dmq1: Buffer.from("...", "base64"),
// InverseQ / Coefficient
coeff: Buffer.from("...", "base64"),
}, "components");
var encodedSignature = key.sign(partialToken, "base64");
var jwt = partialToken + "." + encodedSignature;
HTTP/1.1 400 Bad Request
Error parsing service account data
HTTP/1.1 400 Bad Request
Email must be specified when creating a service account
HTTP/1.1 400 Bad Request
Expiration time must be specified and cannot be in the past
HTTP/1.1 400 Bad Request
You already have a service account with the specified email address. The existing service account has id: 'N'
HTTP/1.1 400 Bad Request
Name must be specified when creating a service account
HTTP/1.1 400 Bad Request
Expiration time can at most be 1 year in the future
HTTP/1.1 400 Bad Request
At least one feature access must be associated with the service account
HTTP/1.1 400 Bad Request
You cannot assign feature access '7' to the service account because the calling account does not have this feature access
When the account has been created, a verification email is sent to the email address associated with the service account. The verification email is sent from noreply@dfds.com and contains instructions on how to validate the account. It must be validated within 24-hours, otherwise the account is automatically deleted. The account can be used for authentication only after the verification step has been completed.
Service accounts can be viewed and deleted using the API. Managing service accounts requires the Service Account feature access.
A list of service accounts can be retrieved on the following endpoint.
The result of this method is paged, with a max of 20 items per page.
Note that the private key associated with accounts cannnot be retrieved.
GET https://logisticsapi.dfds.com/api/authentication/serviceaccount?page={page}
This api returns an array of registered service accounts.
[{
"id": 1794,
"name": "name",
"description": "description",
"email": "prod-trackingupdate@company.com",
"expirationTime": "2018-09-09T10:00:00Z",
"creationTime": "2018-01-09T10:00:00Z",
"verified": false,
"features": [2,5,7]
}]
Use the response header 'X-HasMoreItems' to determine whether additional pages are available. Pages are indexed starting at 1. If no page page is specified, the first page is returned.
X-HasMoreItems: True
HTTP Status 400 if the provided page is less than 1.
HTTP/1.1 400 Bad Request
The page numbering starts a '1', but you specified 0. Please try again using a page number of 1 or larger
Details about a single service account can be retried on the following endpoint.
GET https://logisticsapi.dfds.com/api/authentication/serviceaccount/{accountId}
An existing service account can be updated. Use the list endpoint if you do not know the id of your account.
POST https://logisticsapi.dfds.com/api/authentication/serviceaccount/{accountId}/update
Name | Description | Type |
name | The name used to identify this service token. The name is meant to help you identify your service accounts. | string |
description | A description of the use of this token. This information is for your own reference only. | string |
expirationTime | The date and time of expiration in UTC. The account will be deactived on this date. | date |
features | The set of features this service account has access to. Please refer to the feature access section for the meaning of these identifiers. | array of number |
{
"features": [0, 1, 2],
"name": "My Service Account Name",
"description": "Service account for example usage.",
"expirationTime": "2018-04-22T12:30:12.4059736+02:00"
}
Note you only need to provide the fields that needs updating in the request, see an example below on how to update only the name and description.
{
"name": "My New Service Account Name",
"description": "Service New account for example usage."
}
{
"id": 4711,
"features": [0, 1, 2],
"email": "service@company.com",
"name": "My Service Account Name",
"description": "Service account for example usage.",
"expirationTime": "2022-04-22T12:30:12.407"
}
HTTP/1.1 400 Bad Request
Error parsing service account data.
HTTP/1.1 404 Not Found.
if no service account with the specified {accountId} could be found.
HTTP/1.1 400 Bad Request
If email is specified, Updating email adrres for service accounts is not allowed through update.
HTTP/1.1 400 Bad Request
If expirationTime is specified and expiration time is in the past or if expiration time is more than a 1 year into the future.
HTTP/1.1 400 Bad Request
If name is specified and Name is en empty string or consists entirely of whitespaces.
HTTP/1.1 400 Bad Request
If features is specified as an empty list, at least one feature access must be associated with the service account
HTTP/1.1 400 Bad Request
You cannot assign feature access '7' to the service account because the calling account does not have this feature access
An existing service account can be deleted. Use the list endpoint if you do not know the id of your account.
DELETE https://logisticsapi.dfds.com/api/authentication/serviceaccount/{accountId}
A service account cannot be deleted if it is the owner of one or more notification hooks. To delete the service account, delete the notification hooks first.
This section describes how to authenticate using a service account, which is required for server-server communication. To set up authentication a service account and its corresponding private key is required as described in the previous sections.
The authentication relies on Json Web Tokens (JWT) and the OAuth2 protocol.
The JWT header specifies the signing algorithm used for the token. The only supported algorithm by the token endpoint is RS256 (RSA Signature with SHA-256)
{
"typ": "JWT",
"alg": "RS256"
}
The set of claim MUST include the following parameters. The account is the email associated with service account you want to authenticate. The expiration is the time at which the JWT is no longer valid in UTC. This time must at most be 1 hour into the future.
{
"account": "prod-trackingupdate@company.com",
"expiration": "2018-01-01T15:41Z"
}
This information must now be signed using the specified SHA256 algorithm with the private key associated with the service account. Sign the following string as UTF8 bytes.
{UTF8HeaderBytes as Base64}.{UTF8ClaimsBytes as Base64}
The signature is then concatinated with the header and claims to form the complete JWT.
{UTF8HeaderBytes as Base64}.{UTF8ClaimsBytes as Base64}.{SignatureBytes as Base64}
The generated JWT is used to issue an OAuth token which can then be used for authenticating API requests.
POST https://logisticsapi.dfds.com/api/token
Content-Type: application/x-www-form-urlencoded
grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer
assertion={JWTFromTokenEndpoint}
The following code shows how to create HTTP request to exchange into Velocity Token
var httpClient = new HttpClient();
httpClient.BaseAddress = new Uri("https://test-logisticsapi.dfds.com");
var message = new HttpRequestMessage()
{
Method = HttpMethod.Post,
RequestUri = new Uri(httpClient.BaseAddress, "/api/token")
};
message.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
message.Content = new FormUrlEncodedContent(new Dictionary<string, string>)
{
{ "grant_type", "urn:ietf:params:oauth:grant-type:jwt-bearer" },
{ "assertion", token }
});
var response = httpClient.SendAsync(message);
response.Wait();
Successful authentication will return a standard OAuth2 token.
Use the access token returned to authentication requests against the API.
The response will not include a refresh token, so when it expires a new token must be requested.
HTTP/1.1 400 Bad Request
When using JWT grants an assertion must be specified
HTTP/1.1 400 Bad Request
When using JWT grants the specified assertion must be in the format {base64header}.{base64claims}.{base64signature}.
HTTP/1.1 400 Bad Request
The specified expiration time cannot be in the past
HTTP/1.1 400 Bad Request
The specified expiration time can at most be one hour in the future
HTTP/1.1 400 Bad Request
The provided service account could not be authenticated.
HTTP/1.1 400 Bad Request
The provided JWT signature is not valid
The following code example can be used to create and sign a OAuth token, and exchange this for to a Velocity Token
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Constructing token");
var token = Serialize();
var httpClient = new HttpClient();
httpClient.BaseAddress = new Uri("https://logisticsapi.dfds.com");
var message = new HttpRequestMessage()
{
Method = HttpMethod.Post,
RequestUri = new Uri(httpClient.BaseAddress, "/api/token")
};
message.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
message.Content = new FormUrlEncodedContent(new Dictionary()
{
{ "grant_type", "urn:ietf:params:oauth:grant-type:jwt-bearer" },
{ "assertion", token }
});
var response = httpClient.SendAsync(message);
response.Wait();
Console.WriteLine(response.Result.IsSuccessStatusCode ? "Everything ok" : "Error");
var contentStream = response.Result.Content.ReadAsStringAsync();
contentStream.Wait();
Console.WriteLine(contentStream.Result);
Console.ReadKey();
}
private static string Serialize(JObject json)
{
using (var ms = new MemoryStream())
{
var encoding = new UTF8Encoding(false); // Exclude BOM
using (var streamWriter = new StreamWriter(ms, encoding))
{
using (var jsonWriter = new JsonTextWriter(streamWriter))
{
json.WriteTo(jsonWriter);
jsonWriter.Flush();
streamWriter.Flush();
return Convert.ToBase64String(ms.GetBuffer(), 0, (int)ms.Position);
}
}
}
}
public static string Serialize()
{
var header = new JObject();
header["typ"] = "JWT";
header["alg"] = "RS256";
var encodedHeader = Serialize(header);
var expiration = DateTime.UtcNow.AddMinutes(45);
var claims = new JObject();
claims["account"] = "service@company.com";
claims["expiration"] = expiration;
var encodedClaims = Serialize(claims);
var partialToken = $"{encodedHeader}.{encodedClaims}";
var token = $"{partialToken}.{Sign(partialToken)}";
return token;
}
public static string Sign(string token)
{
using (var rsa = new RSACryptoServiceProvider())
{
rsa.ImportParameters(RSAParameters());
rsa.PersistKeyInCsp = false;
return Convert.ToBase64String(rsa.SignData(Encoding.UTF8.GetBytes(token), "SHA256"));
}
}
public static RSAParameters RSAParameters()
{
var privateExponent = "agK1Ogn5ptgCmo2O4s3yLU345j0rM+Y0eO23Yj2fCPpgLbDigRcIzDyJdt6EMXZLBRHdC41K7iTD...";
var exponentOne = "Dt6xKK2scgrrCLsl783Av6eLz8GVXYqTjIdHIs63jPeUwGtwfw1V65lU145oj7zk4yigeg8Kys885V7p...";
var exponentTwo = "dnAOLuBv5fosSNbMaoSux+E1mpp5yZJTgtv/mP5YSMaBhFVH0vDJa0uh+i8itQHTi2j5ogOB0EDh36p9...";
var publicExponent = "AQAB";
var coefficient = "c9034KqiyU+2JDjn2u1U1j2SEXKHfG9ARTavjihz26v4d5NaHGstseGDWfso7sCk/AB0J2gN/HCjCZdZ...";
var modulus = "uzOgCs9xokwX4l4xdclcqt/n2+Wo/3NzsRN5i/ikUySEsANP8+zyhgHDh4IYC7dFudrc3X4MO593nhj/QtyQ...";
var primeOne = "zuf6UCkmys8IWeiqLMUA1mHOLNy7XBHjCS0YIxqLIAVPrkOqCokFYJkUl+2+dXr6rSP2JSai8MhvkHVUsZh...";
var primeTwo = "556+ilkXsxNEh7FzFbQMEvHdIkjhK0yNNZeEOW4SwTpw5XfP5/zLWi3vi0ijkYsYm3GGOcpfXTeRRLlFDxl...";
return new RSAParameters()
{
D = Convert.FromBase64String(privateExponent),
DP = Convert.FromBase64String(exponentOne),
DQ = Convert.FromBase64String(exponentTwo),
Exponent = Convert.FromBase64String(publicExponent),
InverseQ = Convert.FromBase64String(coefficient),
Modulus = Convert.FromBase64String(modulus),
P = Convert.FromBase64String(primeOne),
Q = Convert.FromBase64String(primeTwo)
};
}
}
Should there be a need for using the private key issued by the service account creation in another context, one can export it into a PKCS#1 or PKCS#8 format with little effort. See sections below for details regarding desired format.
public static void ExportPrivateKeyPKCS1ToFile()
{
using (var rsa = new RSACryptoServiceProvider())
{
rsa.ImportParameters(RSAParameters());
var privateKeyAsBytes = rsa.ExportRSAPrivateKey();
var tempPath = Path.GetTempPath();
var privateKeyFile = Path.Combine(tempPath, "privatekey_pkcs1.pem");
File.WriteAllText(privateKeyFile,
"-----BEGIN RSA PRIVATE KEY-----\r\n"
+ Convert.ToBase64String(
privateKeyAsBytes,
Base64FormattingOptions.InsertLineBreaks)
+ "\r\n-----END RSA PRIVATE KEY-----");
}
}
public static RSAParameters RSAParameters()
{
var privateExponent = "agK1Ogn5ptgCmo2O4s3yLU345j0rM+Y0eO23Yj2fCPpgLbDigRcIzDyJdt6EMXZLBRHdC41K7iTD...";
var exponentOne = "Dt6xKK2scgrrCLsl783Av6eLz8GVXYqTjIdHIs63jPeUwGtwfw1V65lU145oj7zk4yigeg8Kys885V7p...";
var exponentTwo = "dnAOLuBv5fosSNbMaoSux+E1mpp5yZJTgtv/mP5YSMaBhFVH0vDJa0uh+i8itQHTi2j5ogOB0EDh36p9...";
var publicExponent = "AQAB";
var coefficient = "c9034KqiyU+2JDjn2u1U1j2SEXKHfG9ARTavjihz26v4d5NaHGstseGDWfso7sCk/AB0J2gN/HCjCZdZ...";
var modulus = "uzOgCs9xokwX4l4xdclcqt/n2+Wo/3NzsRN5i/ikUySEsANP8+zyhgHDh4IYC7dFudrc3X4MO593nhj/QtyQ...";
var primeOne = "zuf6UCkmys8IWeiqLMUA1mHOLNy7XBHjCS0YIxqLIAVPrkOqCokFYJkUl+2+dXr6rSP2JSai8MhvkHVUsZh...";
var primeTwo = "556+ilkXsxNEh7FzFbQMEvHdIkjhK0yNNZeEOW4SwTpw5XfP5/zLWi3vi0ijkYsYm3GGOcpfXTeRRLlFDxl...";
return new RSAParameters()
{
D = Convert.FromBase64String(privateExponent),
DP = Convert.FromBase64String(exponentOne),
DQ = Convert.FromBase64String(exponentTwo),
Exponent = Convert.FromBase64String(publicExponent),
InverseQ = Convert.FromBase64String(coefficient),
Modulus = Convert.FromBase64String(modulus),
P = Convert.FromBase64String(primeOne),
Q = Convert.FromBase64String(primeTwo)
};
}
public static void ExportPrivateKeyPKCS8ToFile()
{
using (var rsa = new RSACryptoServiceProvider())
{
rsa.ImportParameters(RSAParameters());
var privateKeyAsBytes = rsa.ExportPkcs8PrivateKey();
var tempPath = Path.GetTempPath();
var privateKeyFile = Path.Combine(tempPath, "privatekey_pkcs8.pem");
File.WriteAllText(privateKeyFile,
"-----BEGIN PRIVATE KEY-----\r\n"
+ Convert.ToBase64String(
privateKeyAsBytes,
Base64FormattingOptions.InsertLineBreaks)
+ "\r\n-----END PRIVATE KEY-----");
}
}
public static RSAParameters RSAParameters()
{
var privateExponent = "agK1Ogn5ptgCmo2O4s3yLU345j0rM+Y0eO23Yj2fCPpgLbDigRcIzDyJdt6EMXZLBRHdC41K7iTD...";
var exponentOne = "Dt6xKK2scgrrCLsl783Av6eLz8GVXYqTjIdHIs63jPeUwGtwfw1V65lU145oj7zk4yigeg8Kys885V7p...";
var exponentTwo = "dnAOLuBv5fosSNbMaoSux+E1mpp5yZJTgtv/mP5YSMaBhFVH0vDJa0uh+i8itQHTi2j5ogOB0EDh36p9...";
var publicExponent = "AQAB";
var coefficient = "c9034KqiyU+2JDjn2u1U1j2SEXKHfG9ARTavjihz26v4d5NaHGstseGDWfso7sCk/AB0J2gN/HCjCZdZ...";
var modulus = "uzOgCs9xokwX4l4xdclcqt/n2+Wo/3NzsRN5i/ikUySEsANP8+zyhgHDh4IYC7dFudrc3X4MO593nhj/QtyQ...";
var primeOne = "zuf6UCkmys8IWeiqLMUA1mHOLNy7XBHjCS0YIxqLIAVPrkOqCokFYJkUl+2+dXr6rSP2JSai8MhvkHVUsZh...";
var primeTwo = "556+ilkXsxNEh7FzFbQMEvHdIkjhK0yNNZeEOW4SwTpw5XfP5/zLWi3vi0ijkYsYm3GGOcpfXTeRRLlFDxl...";
return new RSAParameters()
{
D = Convert.FromBase64String(privateExponent),
DP = Convert.FromBase64String(exponentOne),
DQ = Convert.FromBase64String(exponentTwo),
Exponent = Convert.FromBase64String(publicExponent),
InverseQ = Convert.FromBase64String(coefficient),
Modulus = Convert.FromBase64String(modulus),
P = Convert.FromBase64String(primeOne),
Q = Convert.FromBase64String(primeTwo)
};
}
The single booking access token authentication provides simplified access to a single booking for a limited time. It is intended to be used by end user as an alternative to the username/password based User Authentication. Like service- and user-authentication, the single booking token authentication is based on OAuth2. The granttype is restricted-booking. The feature access associated with an access token can vary and is decided when the token is issued.
POST https://logisticsapi.dfds.com/api/token
This endpoint accepts a token and issues bearer tokens which can be used to access the API.
Content-Type: application/x-www-form-urlencoded
grant_type=restricted-booking&token=YOURTOKENVALUE
The response for a successfull authentication request will include a bearer access token and expiration time.
The API is segmented in features. Features provide high level access to segments. Access to specific data or operations may be further constrained. Please refer to documentation of individual api sections for details. If your user account is missing access to a particular feature, please contact your DFDS representative. Feature access delegation for service accounts is managed by you.
Name | Description | Id |
CreateBooking | Allows creation of bookings | 1 |
EditBooking | Allows modification of bookings | 0 |
ViewPOD | Allows read access to Proof of Delivery documents | 2 |
ViewInvoice | Allows read access to booking invoices | 3 |
ViewBookingTracking | Allows read access booking event and position tracking | 15 |
NotificationHooks | Allows access to notification hooks management. | 5 |
CreateAddress | Allows creation of new freight addresses. | 7 |
ServiceAccounts | Allows access to service account management. | 16 |
UploadAndViewBookingDocuments | Upload / view booking documents | 19 |
ViewConsignments | View Consignments | 21 |
CreateAndUpdateConsignments | Create and Update Consignment | 22 |
TestScenarioOne | Allows access to test scenario #1. | 17 |