To call the authenticated public API you first need a User Key.
Use the authentication exchange endpoint documented here:
GET /authenticate/apikeyexchange
For the initial exchange:
X-MSS-API-APPID, X-MSS-CUSTOM-DATE, and X-MSS-SIGNATURE headersSigning requests
Portal signs requests with HMAC-SHA256 and Base64-encodes the result.
Build the canonical message by concatenating these parts with no separator:
[HTTP method][absolute URL][content type][timestamp][user API key]
Rules:
GET requests, omit the content-type segment.GET requests, include the exact content type sent in the request.X-MSS-CUSTOM-DATE.X-MSS-API-USERKEY.Example canonical message for the initial exchange:
GEThttps://api.portal.io/authenticate/apikeyexchange?UserName=user%40example.com&Password=MyP%40ss123Mon, 06 Apr 2026 00:22:19 GMT
If the exchange succeeds, use meta.apiKey from the response on all later authenticated requests. For the HMAC-based public API, this is the value that matters, not bearerToken.
Exchange your Portal username and password for a User API Key. Send the HMAC authentication headers with this request to obtain the key.
Success
Invalid credentials or User Email is not verified
{- "userId": "string",
- "sessionId": "string",
- "userName": "string",
- "displayName": "string",
- "referrerUrl": "string",
- "bearerToken": "string",
- "refreshToken": "string",
- "refreshTokenExpiry": "2019-08-24T14:15:22Z",
- "profileUrl": "string",
- "roles": [
- "string"
], - "permissions": [
- "string"
], - "authProvider": "string",
- "responseStatus": {
- "errorCode": "string",
- "message": "string",
- "stackTrace": "string",
- "errors": [
- {
- "errorCode": "string",
- "fieldName": "string",
- "message": "string",
- "meta": {
- "property1": "string",
- "property2": "string"
}
}
], - "meta": {
- "property1": "string",
- "property2": "string"
}
}, - "meta": {
- "property1": "string",
- "property2": "string"
}
}