Authentication¶
P21 uses two distinct authentication mechanisms depending on which API family you are working with. The UI-based APIs (Common Services, Interactive, Transaction) use session-based authentication. The REST APIs (Entity API, Data Services) use Bearer token authentication.
Session-Based Authentication¶
The Interactive, Transaction, and Common Services APIs all operate within a P21 session. A session represents an authenticated user context on the P21 application server — it holds state, enforces security, and tracks open windows. Every call to these APIs must be associated with an active session.
Base URL¶
Creating a Session¶
Send a POST request to the sessions endpoint with Basic authentication credentials and a session parameters body.
Headers:
| Header | Value |
|---|---|
Authorization | Basic {base64(username:password)} |
Content-Type | application/json or application/xml |
Accept | application/json or application/xml |
Request Body — JSON¶
{
"SessionType": "User",
"WorkstationID": "MyIntegration-Host01",
"PrintMode": "Browser",
"SessionTimeout": 2147483647,
"ClientPlatformApp": "MyIntegrationName",
"OnBehalfOf": ""
}
Request Body — XML¶
The full XML schema, including all optional parameters:
<UserParameters xmlns="http://schemas.datacontract.org/2004/07/P21.UI.Service.Model.Common.V1">
<ClientPlatformApp>String content</ClientPlatformApp>
<OnBehalfOf>String content</OnBehalfOf>
<PrintMode>Browser</PrintMode>
<ResponseWindowHandlingEnabled>true</ResponseWindowHandlingEnabled>
<SessionTimeout>2147483647</SessionTimeout>
<SessionType>User</SessionType>
<TestingOptions>
<AutoOpenPortals>true</AutoOpenPortals>
<BypassApplicationRoleSecurity>true</BypassApplicationRoleSecurity>
<DisableCustomSoftware>true</DisableCustomSoftware>
<DisableDynachange>true</DisableDynachange>
<OverrideConfigNo>2147483647</OverrideConfigNo>
<Password>String content</Password>
<Programmer>true</Programmer>
</TestingOptions>
<WWMSOptions>
<BinID>String content</BinID>
<CompanyID>String content</CompanyID>
<LocationID>2147483647</LocationID>
<WwmsOnly>true</WwmsOnly>
</WWMSOptions>
<WorkstationID>String content</WorkstationID>
</UserParameters>
Session Parameters Reference¶
SessionType¶
Controls the mode in which the session operates.
| Value | Description |
|---|---|
User | Standard interactive user session. The most common type for integrations that drive P21 windows. |
Auto | Automated/background session. Does not support interactive window operations. Use for non-interactive integrations. |
AutoInteractive | Automated session that can also open windows. Combines automation with window access. |
Scheduler | Session type for P21 scheduled tasks. |
PrintMode¶
Controls how print output is handled during the session.
| Value | Description |
|---|---|
Browser | Print output is rendered for browser/web display. Default for API sessions. |
Local | Routes print jobs to a local printer. |
Network | Routes print jobs to a network printer. |
Other Parameters¶
| Parameter | Type | Description |
|---|---|---|
WorkstationID | string | Identifies the client calling the API. Use a descriptive name (e.g., ERP-Integration-Prod). Visible in P21 session management. |
ClientPlatformApp | string | The name of the calling application. Used for auditing and diagnostics. |
SessionTimeout | int | Inactivity timeout in milliseconds. Set to 2147483647 (max int) for integrations that manage their own keep-alive. |
OnBehalfOf | string | Run the session on behalf of another user. Requires elevated privileges. |
ResponseWindowHandlingEnabled | bool | Whether the session should handle response windows automatically. |
TestingOptions¶
Development and Testing Only
TestingOptions are intended for development and QA environments. Do not use these options in production — they bypass security controls and alter normal application behavior.
| Option | Description |
|---|---|
DisableCustomSoftware | Prevents custom software (Business Rules, event hooks) from running in this session. Useful when testing baseline P21 behavior. |
DisableDynachange | Disables Dynachange UI customizations for this session. |
BypassApplicationRoleSecurity | Skips P21 role-based security checks. |
Programmer | Enables programmer mode, which exposes additional diagnostic information. |
AutoOpenPortals | Controls whether portals open automatically. |
OverrideConfigNo | Overrides the configuration number used for this session. |
Password | Testing password override. |
WWMSOptions¶
Options specific to Warehouse Management (WWMS) sessions.
| Option | Description |
|---|---|
CompanyID | The P21 company ID for the WWMS session. |
BinID | Target bin ID. |
LocationID | Target location ID. |
WwmsOnly | Restricts the session to WWMS operations only. |
Session Lifecycle Management¶
Using the Session Token¶
After a successful POST /common/v1/sessions/, the response will contain a session token. Include this token as a header on all subsequent requests:
Note
The exact header name and token location in the response may vary by P21 version. Consult your P21 server's WADL documentation at /common/v1/info/ for confirmation.
Keeping a Session Alive¶
Sessions will time out after the configured inactivity period. For long-running integrations, send a periodic keep-alive ping:
A successful ping resets the session's inactivity timer. Implement this as a background task that fires every few minutes.
Closing a Session¶
Always close sessions explicitly when you are done:
Session License Exhaustion
Each P21 user license can hold a limited number of concurrent sessions. If your integration creates sessions without closing them, it will eventually lock the user account out of the P21 client. Always close sessions in error-handling and cleanup code paths.
Retrieving Session State¶
Returns information about the current session including company, location, user, and open windows.
Session Variables and Preferences¶
Session Variables¶
Session variables are key/value pairs stored in the session context. They can be used to pass information between API calls or to store state across a workflow.
Session Preferences¶
User preferences stored at the session level:
GET /common/v1/sessions/preference/{name}
POST /common/v1/sessions/preference/{name}
PUT /common/v1/sessions/preference/{name}
SDK Token Authentication (Entity API and Data Services)¶
The Entity API and Data Services API do not use session-based auth. They use a Bearer token that is obtained through the P21 SDK and tied to a P21 user account.
Base URLs¶
Using the Bearer Token¶
Include the token in the Authorization header on every request:
Example request:
GET https://{your-server}/api/entity/Customer
Authorization: Bearer eyJhbGciOiJSUzI1NiIsI...
Accept: application/xml
Token Acquisition
The process for obtaining an SDK Bearer token depends on your P21 version and configuration. In most cases, tokens are generated through the P21 administration console or via a separate token endpoint provided by your P21 implementation team. The token is long-lived and associated with a specific service account — treat it like a password.
Token vs. Session Comparison¶
| Aspect | Session-Based | Bearer Token |
|---|---|---|
| APIs | Common Services, Interactive, Transaction | Entity API, Data Services |
| State | Stateful (server holds session) | Stateless |
| Setup | POST to /sessions/ each time | Token stored and reused |
| License consumption | Consumes a P21 user session slot | No session slot consumed |
| Keep-alive needed | Yes | No |
| Best for | Window automation, workflows | Integrations, bulk reads |
Complete C# Authentication Example¶
The following example demonstrates the full session lifecycle for the UI-based APIs using HttpClient.
using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
public class P21SessionClient : IAsyncDisposable
{
private readonly HttpClient _client;
private readonly string _baseUrl;
private string? _sessionToken;
public P21SessionClient(string serverHost, string username, string password)
{
_baseUrl = $"https://{serverHost}/uiserver0/ui";
_client = new HttpClient();
// Set Basic auth for the initial session creation request
var credentials = Convert.ToBase64String(
Encoding.ASCII.GetBytes($"{username}:{password}"));
_client.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Basic", credentials);
_client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
}
/// <summary>
/// Creates a P21 session and stores the session token for subsequent calls.
/// </summary>
public async Task LoginAsync(string workstationId = "API-Client")
{
var sessionParams = new
{
SessionType = "User",
WorkstationID = workstationId,
PrintMode = "Browser",
SessionTimeout = 2147483647
};
var json = JsonSerializer.Serialize(sessionParams);
var content = new StringContent(json, Encoding.UTF8, "application/json");
var response = await _client.PostAsync(
$"{_baseUrl}/common/v1/sessions/", content);
response.EnsureSuccessStatusCode();
var responseBody = await response.Content.ReadAsStringAsync();
var result = JsonSerializer.Deserialize<JsonElement>(responseBody);
// Extract the session token from the response
// The exact property name depends on your P21 version — check your server's response
_sessionToken = result.GetProperty("SessionID").GetString()
?? throw new InvalidOperationException("No session token in response.");
// Set the session token on all future requests
_client.DefaultRequestHeaders.Remove("X-SessionToken");
_client.DefaultRequestHeaders.Add("X-SessionToken", _sessionToken);
Console.WriteLine($"Session established: {_sessionToken}");
}
/// <summary>
/// Sends a keep-alive ping to prevent session timeout.
/// </summary>
public async Task PingAsync()
{
if (_sessionToken is null)
throw new InvalidOperationException("Not logged in.");
var response = await _client.PostAsync(
$"{_baseUrl}/common/v1/sessions/ping",
new StringContent(string.Empty));
response.EnsureSuccessStatusCode();
}
/// <summary>
/// Retrieves current session state.
/// </summary>
public async Task<string> GetSessionStateAsync()
{
if (_sessionToken is null)
throw new InvalidOperationException("Not logged in.");
var response = await _client.GetAsync(
$"{_baseUrl}/common/v1/sessions/state");
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsStringAsync();
}
/// <summary>
/// Closes the session. Always call this when done.
/// </summary>
public async Task LogoutAsync()
{
if (_sessionToken is null) return;
try
{
var response = await _client.DeleteAsync(
$"{_baseUrl}/common/v1/sessions/");
response.EnsureSuccessStatusCode();
Console.WriteLine("Session closed.");
}
finally
{
_sessionToken = null;
}
}
public async ValueTask DisposeAsync()
{
await LogoutAsync();
_client.Dispose();
}
}
Usage:
await using var p21 = new P21SessionClient("p21-dev.yourcompany.com", "apiuser", "password");
await p21.LoginAsync("OrderSync-Prod");
var state = await p21.GetSessionStateAsync();
Console.WriteLine(state);
// ... make additional API calls using the shared HttpClient ...
// Session is closed automatically by DisposeAsync
Security Considerations¶
Use a Dedicated Service Account
Create a dedicated P21 user account for each integration. This isolates session usage, makes audit logs readable, and allows you to revoke access to one integration without affecting others.
Never Hard-Code Credentials
Store P21 credentials in environment variables, a secrets manager (Azure Key Vault, AWS Secrets Manager, HashiCorp Vault), or an encrypted configuration file — never in source code or committed configuration files.
Use TLS
Always connect to P21 over HTTPS. The Basic auth header transmits credentials in Base64, which is not encryption — TLS is the only thing protecting credentials in transit.