{"templateId":"markdown","sharedDataIds":{"sidebar":"sidebar-guides/sidebars.yaml"},"props":{"metadata":{"markdoc":{"tagList":["accordion","img","code-walkthrough","step","admonition"]},"type":"markdown"},"seo":{"title":"Quickstart","description":"Transform your commerce with PXP's unified platform—seamless payments, real-time insights, and global growth in one powerful integration.","lang":"en-UK","siteUrl":"https://developer.pxp.io","llmstxt":{"hide":false,"sections":[{"title":"Table of contents","includeFiles":["**/*"],"excludeFiles":[]}],"excludeFiles":[]}},"dynamicMarkdocComponents":[],"compilationErrors":[],"ast":{"$$mdtype":"Tag","name":"article","attributes":{},"children":[{"$$mdtype":"Tag","name":"Heading","attributes":{"level":1,"id":"quickstart","__idx":0},"children":["Quickstart"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"span","attributes":{"style":{"display":"inline-block","fontSize":"20px","color":"#3A3D40","borderRadius":"0","fontWeight":"500","verticalAlign":"middle","lineHeight":"1.5","margin":"0 auto 20px auto!important"}},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Follow our walkthrough to get Checkout Drop-in running in minutes."]}]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"pre-requisites","__idx":1},"children":["Pre-requisites"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Before you start, make sure you have:"]},{"$$mdtype":"Tag","name":"ul","attributes":{"className":"code-walkthrough-list"},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Node.js 22.x or higher (for Node.js backend) or .NET SDK (for .NET backend) installed on your computer"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Your API credentials from the ",{"$$mdtype":"Tag","name":"a","attributes":{"href":"https://portal.pxp.io","target":"_blank"},"children":["Unity Portal"]}]}]},{"$$mdtype":"Tag","name":"Accordion","attributes":{"title":"Where to find your credentials","defaultOpen":false},"children":[{"$$mdtype":"Tag","name":"ol","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["In the Unity Portal, go to ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Merchant setup > Merchant groups"]}," and select a merchant group."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Click the ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Inbound calls"]}," tab. Your client ID is in the top right:",{"$$mdtype":"Tag","name":"Image","attributes":{"src":"/assets/copy-client-id.0a23af7974c95fd4eb1889f740594750a69954f5f6ea5dbc5f3acf5a56d25922.fa48401d.png","alt":"","withLightbox":true,"className":"screenshot","width":"","height":""},"children":[]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Click ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["+ New token"]}," to create a token, then copy both the ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["ID"]}," and the ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Value"]},".",{"$$mdtype":"Tag","name":"Image","attributes":{"src":"/assets/copy-token-value.51ecc9c77324b3383f3b7837f1e085d7bf7959bfe13773ed49fcfea8f9a78f0d.fa48401d.png","alt":"","withLightbox":true,"className":"screenshot","width":"","height":""},"children":[]}]}]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"install-the-sdk","__idx":2},"children":["Install the SDK"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["To get started, install the latest version of the Web SDK from the ",{"$$mdtype":"Tag","name":"a","attributes":{"href":"https://www.npmjs.com/package/@pxpio/web-components-sdk","target":"_blank"},"children":["npm public registry"]},". You'll need to have Node.js 22.x or higher."]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"shell","header":{"controls":{"copy":{}}},"source":"npm i @pxpio/web-components-sdk\n","lang":"shell"},"children":[]},{"$$mdtype":"Tag","name":"CodeWalkthrough","attributes":{"__idx":1,"filters":{"Backend":{"items":[{"label":"Node.js","value":"nodejs"},{"label":".NET","value":"dotnet"}],"default":"nodejs"}},"filesets":[{"files":[{"path":"guides/checkout/drop-in/web/_filesets/installation/create-session.js","content":["import crypto from 'crypto';\r","\r",{"start":2,"condition":{"steps":["credentials-setup"]},"children":["// Your API credentials from the Unity Portal\r","const TOKEN_ID = '9aac6071-38d0-4545-9d2f-15b936af6d7f'; // Replace this with your token ID\r","const TOKEN_VALUE = 'your-token-value-here'; // Replace this with your token value\r","const CLIENT_ID = 'f47ac10b-58cc-4372-a567-0e02b2c3d479'; // Replace this with your client ID\r"]},"\r",{"start":9,"condition":{"steps":["create-signature-function"]},"children":["/**\r"," * Creates an HMAC signature for authenticating API requests\r"," */\r","function createHmacSignature(tokenId, timestamp, requestId, requestPath, requestBody, tokenValue) {\r",{"start":14,"condition":{"steps":["generate-signature"]},"children":["  // Combine all parts with colons\r","  const stringToHash = `${tokenId}:${timestamp}:${requestId}:${requestPath}:${requestBody}`;\r","  \r","  // Create HMAC SHA256 hash using the token value as the secret\r","  const hmac = crypto.createHmac('sha256', tokenValue);\r","  hmac.update(stringToHash);\r","  \r","  // Return the hash as a hex string\r","  return hmac.digest('hex').toUpperCase();\r"]},"}\r"]},"\r","/**\r"," * Creates a new checkout session\r"," */\r","export async function createSession(merchantId, siteId, amount, currency) {\r","  // Generate unique IDs for this request\r","  const timestamp = Math.floor(Date.now() / 1000);\r","  const requestId = crypto.randomUUID();\r","  const merchantTransactionId = crypto.randomUUID();\r","  \r",{"start":37,"condition":{"steps":["build-request-body"]},"children":["  // Build the request body\r","  const requestBody = {\r","    merchant: merchantId, // Replace with your merchant ID\r","    site: siteId, // Replace with your site ID\r","    sessionTimeout: 120,\r","    merchantTransactionId: merchantTransactionId, // Replace with a unique transaction ID\r","    transactionMethod: {\r","      intent: {\r","        card: 'Authorisation',\r","        paypal: 'Purchase'\r","      }\r","    },\r","    amounts: {\r","      currencyCode: currency,\r","      transactionValue: amount\r","    },\r","    allowTransaction: true,\r","    serviceType: 'CheckoutDropIn'\r","  };\r","  \r","  // Minify the request body (no whitespace)\r","  const requestBodyString = JSON.stringify(requestBody);\r","  const requestPath = 'api/v1/sessions';\r"]},"  \r",{"start":63,"condition":{"steps":["generate-signature"]},"children":["  // Create the HMAC signature\r","  const signature = createHmacSignature(\r","    TOKEN_ID,\r","    timestamp,\r","    requestId,\r","    requestPath,\r","    requestBodyString,\r","    TOKEN_VALUE\r","  );\r"]},"  \r",{"start":75,"condition":{"steps":["build-auth-header"]},"children":["  // Build the Authorization header\r","  const authHeader = `${TOKEN_ID}:${timestamp}:${requestId}:${signature}`;\r"]},"  \r",{"start":80,"condition":{"steps":["send-session-request"]},"children":["  // Send the request\r","  const response = await fetch('https://api-services.pxp.io/api/v1/sessions', {\r","    method: 'POST',\r","    headers: {\r","      'Authorization': authHeader,\r","      'X-Request-Id': requestId,\r","      'X-Client-Id': CLIENT_ID,\r","      'Content-Type': 'application/json'\r","    },\r","    body: requestBodyString\r","  });\r"]},"  \r",{"start":94,"condition":{"steps":["handle-response"]},"children":["  if (!response.ok) {\r","    throw new Error(`Session creation failed: ${response.statusText}`);\r","  }\r","  \r","  const sessionData = await response.json();\r","  \r","  return {\r","    ...sessionData,\r","    merchantTransactionId\r","  };\r"]},"}"],"metadata":{"steps":["credentials-setup","create-signature-function","generate-signature","build-request-body","generate-signature","build-auth-header","send-session-request","handle-response"]},"basename":"create-session.js","language":"javascript"}],"downloadAssociatedFiles":[{"path":"guides/checkout/drop-in/web/_filesets/installation/create-session.js","content":["import crypto from 'crypto';\r","\r",{"start":2,"condition":{"steps":["credentials-setup"]},"children":["// Your API credentials from the Unity Portal\r","const TOKEN_ID = '9aac6071-38d0-4545-9d2f-15b936af6d7f'; // Replace this with your token ID\r","const TOKEN_VALUE = 'your-token-value-here'; // Replace this with your token value\r","const CLIENT_ID = 'f47ac10b-58cc-4372-a567-0e02b2c3d479'; // Replace this with your client ID\r"]},"\r",{"start":9,"condition":{"steps":["create-signature-function"]},"children":["/**\r"," * Creates an HMAC signature for authenticating API requests\r"," */\r","function createHmacSignature(tokenId, timestamp, requestId, requestPath, requestBody, tokenValue) {\r",{"start":14,"condition":{"steps":["generate-signature"]},"children":["  // Combine all parts with colons\r","  const stringToHash = `${tokenId}:${timestamp}:${requestId}:${requestPath}:${requestBody}`;\r","  \r","  // Create HMAC SHA256 hash using the token value as the secret\r","  const hmac = crypto.createHmac('sha256', tokenValue);\r","  hmac.update(stringToHash);\r","  \r","  // Return the hash as a hex string\r","  return hmac.digest('hex').toUpperCase();\r"]},"}\r"]},"\r","/**\r"," * Creates a new checkout session\r"," */\r","export async function createSession(merchantId, siteId, amount, currency) {\r","  // Generate unique IDs for this request\r","  const timestamp = Math.floor(Date.now() / 1000);\r","  const requestId = crypto.randomUUID();\r","  const merchantTransactionId = crypto.randomUUID();\r","  \r",{"start":37,"condition":{"steps":["build-request-body"]},"children":["  // Build the request body\r","  const requestBody = {\r","    merchant: merchantId, // Replace with your merchant ID\r","    site: siteId, // Replace with your site ID\r","    sessionTimeout: 120,\r","    merchantTransactionId: merchantTransactionId, // Replace with a unique transaction ID\r","    transactionMethod: {\r","      intent: {\r","        card: 'Authorisation',\r","        paypal: 'Purchase'\r","      }\r","    },\r","    amounts: {\r","      currencyCode: currency,\r","      transactionValue: amount\r","    },\r","    allowTransaction: true,\r","    serviceType: 'CheckoutDropIn'\r","  };\r","  \r","  // Minify the request body (no whitespace)\r","  const requestBodyString = JSON.stringify(requestBody);\r","  const requestPath = 'api/v1/sessions';\r"]},"  \r",{"start":63,"condition":{"steps":["generate-signature"]},"children":["  // Create the HMAC signature\r","  const signature = createHmacSignature(\r","    TOKEN_ID,\r","    timestamp,\r","    requestId,\r","    requestPath,\r","    requestBodyString,\r","    TOKEN_VALUE\r","  );\r"]},"  \r",{"start":75,"condition":{"steps":["build-auth-header"]},"children":["  // Build the Authorization header\r","  const authHeader = `${TOKEN_ID}:${timestamp}:${requestId}:${signature}`;\r"]},"  \r",{"start":80,"condition":{"steps":["send-session-request"]},"children":["  // Send the request\r","  const response = await fetch('https://api-services.pxp.io/api/v1/sessions', {\r","    method: 'POST',\r","    headers: {\r","      'Authorization': authHeader,\r","      'X-Request-Id': requestId,\r","      'X-Client-Id': CLIENT_ID,\r","      'Content-Type': 'application/json'\r","    },\r","    body: requestBodyString\r","  });\r"]},"  \r",{"start":94,"condition":{"steps":["handle-response"]},"children":["  if (!response.ok) {\r","    throw new Error(`Session creation failed: ${response.statusText}`);\r","  }\r","  \r","  const sessionData = await response.json();\r","  \r","  return {\r","    ...sessionData,\r","    merchantTransactionId\r","  };\r"]},"}"],"metadata":{"steps":["credentials-setup","create-signature-function","generate-signature","build-request-body","generate-signature","build-auth-header","send-session-request","handle-response"]},"basename":"create-session.js","language":"javascript"}],"when":{"Backend":"nodejs"}},{"files":[{"path":"guides/checkout/drop-in/web/_filesets/installation/create-session.cs","content":["using System.Security.Cryptography;","using System.Text;","using System.Text.Json;","using System.Text.Json.Serialization;","",{"start":5,"condition":{"steps":["credentials-setup"]},"children":["// Your API credentials from the Unity Portal","private const string TokenId = \"9aac6071-38d0-4545-9d2f-15b936af6d7f\"; // Replace this with your token ID","private const string TokenValue = \"your-token-value-here\"; // Replace this with your token value","private const string ClientId = \"f47ac10b-58cc-4372-a567-0e02b2c3d479\"; // Replace this with your client ID","private const string SessionUrl = \"https://api-services.pxp.io/api/v1/sessions\";"]},"","private static readonly HttpClient HttpClient = new();","private static readonly JsonSerializerOptions IndentedJsonOptions = new() { WriteIndented = true };","",{"start":16,"condition":{"steps":["create-signature-function"]},"children":["/// <summary>","/// Creates an HMAC signature for authenticating API requests","/// </summary>","private static string CreateHmacSignature(","    string timestamp,","    string requestId,","    string requestPath,","    string requestBody,","    string tokenValue)","{","    // Combine all parts in the order expected by the PXP API","    var stringToHash = $\"{timestamp}{requestId}{requestPath}{requestBody}\";","    var keyBytes = Encoding.UTF8.GetBytes(tokenValue);","    var payloadBytes = Encoding.UTF8.GetBytes(stringToHash);","","    // Create HMAC SHA256 hash using the token value as the secret","    using var hmac = new HMACSHA256(keyBytes);","    var hashBytes = hmac.ComputeHash(payloadBytes);","","    // Return the hash as an uppercase hex string","    return Convert.ToHexString(hashBytes);","}"]},"","/// <summary>","/// Creates a new checkout session","/// </summary>","public static async Task<string> CreateSessionAsync(string merchantId, string siteId, decimal amount, string currency)","{","    // Generate unique IDs for this request","    var merchantTransactionId = Guid.NewGuid().ToString();","    var timestamp = DateTimeOffset.UtcNow.ToUnixTimeSeconds().ToString();","    var requestId = Guid.NewGuid().ToString();","",{"start":51,"condition":{"steps":["build-request-body"]},"children":["    // Build the request body","    var requestBody = new SessionRequestBody","    {","        Merchant = merchantId, // Replace with your merchant ID","        Site = siteId, // Replace with your site ID","        SessionTimeout = 120,","        MerchantTransactionId = merchantTransactionId, // Replace with a unique transaction ID","        TransactionMethod = new SessionTransactionMethod","        {","            Intent = new SessionIntent","            {","                Card = \"Authorisation\",","                Paypal = \"Purchase\"","            }","        },","        Amounts = new SessionAmounts","        {","            CurrencyCode = currency,","            TransactionValue = amount","        },","        AllowTransaction = true,","        ServiceType = \"CheckoutDropIn\"","    };","","    // Minify the request body (no whitespace)","    var requestBodyString = JsonSerializer.Serialize(requestBody);","    var normalizedRequestBody = string.IsNullOrWhiteSpace(requestBodyString) ? string.Empty : requestBodyString;","    var requestPath = new Uri(SessionUrl).AbsolutePath.Trim('/');"]},"","    // Create the HMAC signature","    var signature = CreateHmacSignature(","        timestamp,","        requestId,","        requestPath,","        normalizedRequestBody,","        TokenValue);","",{"start":90,"condition":{"steps":["send-session-request"]},"children":["    // Build the Authorization header","    const string authenticationScheme = \"PXP-UST1\";","    var authorizationHeader = $\"{authenticationScheme} {TokenId}:{timestamp}:{signature}\";","","    // Send the request","    var request = new HttpRequestMessage(HttpMethod.Post, SessionUrl)","    {","        Content = new StringContent(requestBodyString, Encoding.UTF8, \"application/json\")","    };","","    request.Headers.TryAddWithoutValidation(\"Authorization\", authorizationHeader);","    request.Headers.Add(\"X-Request-Id\", requestId);","    request.Headers.Add(\"X-Client-Id\", ClientId);","","    using (request)","    {","        using var response = await HttpClient.SendAsync(request);","        var responseContent = await response.Content.ReadAsStringAsync();"]},"",{"start":111,"condition":{"steps":["handle-response"]},"children":["        if (!response.IsSuccessStatusCode)","        {","            throw new InvalidOperationException(","                $\"Session creation failed: {(int)response.StatusCode} {response.ReasonPhrase}{Environment.NewLine}{responseContent}\");","        }","","        var sessionResponse = JsonSerializer.Deserialize<SessionResponse>(responseContent)","            ?? throw new InvalidOperationException(\"Session response could not be read.\");","","        sessionResponse.MerchantTransactionId = merchantTransactionId;","","        return JsonSerializer.Serialize(sessionResponse, IndentedJsonOptions);"]},"    }","}","","// Data transfer objects for session creation","public sealed class SessionRequestBody","{","    [JsonPropertyName(\"merchant\")]","    public string Merchant { get; set; } = string.Empty;","","    [JsonPropertyName(\"site\")]","    public string Site { get; set; } = string.Empty;","","    [JsonPropertyName(\"sessionTimeout\")]","    public int SessionTimeout { get; set; }","","    [JsonPropertyName(\"merchantTransactionId\")]","    public string MerchantTransactionId { get; set; } = string.Empty;","","    [JsonPropertyName(\"transactionMethod\")]","    public SessionTransactionMethod TransactionMethod { get; set; } = new();","","    [JsonPropertyName(\"amounts\")]","    public SessionAmounts Amounts { get; set; } = new();","","    [JsonPropertyName(\"allowTransaction\")]","    public bool AllowTransaction { get; set; }","","    [JsonPropertyName(\"serviceType\")]","    public string ServiceType { get; set; } = string.Empty;","}","","public sealed class SessionTransactionMethod","{","    [JsonPropertyName(\"intent\")]","    public SessionIntent Intent { get; set; } = new();","}","","public sealed class SessionIntent","{","    [JsonPropertyName(\"card\")]","    public string Card { get; set; } = string.Empty;","","    [JsonPropertyName(\"paypal\")]","    public string Paypal { get; set; } = string.Empty;","}","","public sealed class SessionAmounts","{","    [JsonPropertyName(\"currencyCode\")]","    public string CurrencyCode { get; set; } = string.Empty;","","    [JsonPropertyName(\"transactionValue\")]","    public decimal TransactionValue { get; set; }","}","","public sealed class SessionResponse","{","    [JsonPropertyName(\"merchantTransactionId\")]","    public string MerchantTransactionId { get; set; } = string.Empty;","","    [JsonPropertyName(\"sessionId\")]","    public string SessionId { get; set; } = string.Empty;","","    [JsonPropertyName(\"hmacKey\")]","    public string HmacKey { get; set; } = string.Empty;","","    [JsonPropertyName(\"encryptionKey\")]","    public string EncryptionKey { get; set; } = string.Empty;","","    [JsonPropertyName(\"sessionExpiry\")]","    public DateTimeOffset SessionExpiry { get; set; }","","    [JsonPropertyName(\"allowedFundingTypes\")]","    public SessionAllowedFundingTypes AllowedFundingTypes { get; set; } = new();","}","","public sealed class SessionAllowedFundingTypes","{","    [JsonPropertyName(\"cardSchemes\")]","    public List<string> CardSchemes { get; set; } = [];","","    [JsonPropertyName(\"cards\")]","    public List<string> Cards { get; set; } = [];","","    [JsonPropertyName(\"wallets\")]","    public SessionWallets Wallets { get; set; } = new();","}","","public sealed class SessionWallets","{","    [JsonPropertyName(\"paypal\")]","    public SessionPaypalWallet Paypal { get; set; } = new();","","    [JsonPropertyName(\"applePay\")]","    public SessionApplePayWallet ApplePay { get; set; } = new();","","    [JsonPropertyName(\"googlePay\")]","    public SessionGooglePayWallet? GooglePay { get; set; }","}","","public sealed class SessionPaypalWallet","{","    [JsonPropertyName(\"allowedFundingOptions\")]","    public List<string> AllowedFundingOptions { get; set; } = [];","","    [JsonPropertyName(\"merchantId\")]","    public string? MerchantId { get; set; }","}","","public sealed class SessionApplePayWallet","{","    [JsonPropertyName(\"merchantId\")]","    public string? MerchantId { get; set; }","}","","public sealed class SessionGooglePayWallet","{","    [JsonPropertyName(\"merchantId\")]","    public string? MerchantId { get; set; }","","    [JsonPropertyName(\"gatewayMerchantId\")]","    public string? GatewayMerchantId { get; set; }","","    [JsonPropertyName(\"merchantName\")]","    public string? MerchantName { get; set; }","}",""],"metadata":{"steps":["credentials-setup","create-signature-function","build-request-body","send-session-request","handle-response"]},"basename":"create-session.cs","language":"csharp"}],"downloadAssociatedFiles":[{"path":"guides/checkout/drop-in/web/_filesets/installation/create-session.cs","content":["using System.Security.Cryptography;","using System.Text;","using System.Text.Json;","using System.Text.Json.Serialization;","",{"start":5,"condition":{"steps":["credentials-setup"]},"children":["// Your API credentials from the Unity Portal","private const string TokenId = \"9aac6071-38d0-4545-9d2f-15b936af6d7f\"; // Replace this with your token ID","private const string TokenValue = \"your-token-value-here\"; // Replace this with your token value","private const string ClientId = \"f47ac10b-58cc-4372-a567-0e02b2c3d479\"; // Replace this with your client ID","private const string SessionUrl = \"https://api-services.pxp.io/api/v1/sessions\";"]},"","private static readonly HttpClient HttpClient = new();","private static readonly JsonSerializerOptions IndentedJsonOptions = new() { WriteIndented = true };","",{"start":16,"condition":{"steps":["create-signature-function"]},"children":["/// <summary>","/// Creates an HMAC signature for authenticating API requests","/// </summary>","private static string CreateHmacSignature(","    string timestamp,","    string requestId,","    string requestPath,","    string requestBody,","    string tokenValue)","{","    // Combine all parts in the order expected by the PXP API","    var stringToHash = $\"{timestamp}{requestId}{requestPath}{requestBody}\";","    var keyBytes = Encoding.UTF8.GetBytes(tokenValue);","    var payloadBytes = Encoding.UTF8.GetBytes(stringToHash);","","    // Create HMAC SHA256 hash using the token value as the secret","    using var hmac = new HMACSHA256(keyBytes);","    var hashBytes = hmac.ComputeHash(payloadBytes);","","    // Return the hash as an uppercase hex string","    return Convert.ToHexString(hashBytes);","}"]},"","/// <summary>","/// Creates a new checkout session","/// </summary>","public static async Task<string> CreateSessionAsync(string merchantId, string siteId, decimal amount, string currency)","{","    // Generate unique IDs for this request","    var merchantTransactionId = Guid.NewGuid().ToString();","    var timestamp = DateTimeOffset.UtcNow.ToUnixTimeSeconds().ToString();","    var requestId = Guid.NewGuid().ToString();","",{"start":51,"condition":{"steps":["build-request-body"]},"children":["    // Build the request body","    var requestBody = new SessionRequestBody","    {","        Merchant = merchantId, // Replace with your merchant ID","        Site = siteId, // Replace with your site ID","        SessionTimeout = 120,","        MerchantTransactionId = merchantTransactionId, // Replace with a unique transaction ID","        TransactionMethod = new SessionTransactionMethod","        {","            Intent = new SessionIntent","            {","                Card = \"Authorisation\",","                Paypal = \"Purchase\"","            }","        },","        Amounts = new SessionAmounts","        {","            CurrencyCode = currency,","            TransactionValue = amount","        },","        AllowTransaction = true,","        ServiceType = \"CheckoutDropIn\"","    };","","    // Minify the request body (no whitespace)","    var requestBodyString = JsonSerializer.Serialize(requestBody);","    var normalizedRequestBody = string.IsNullOrWhiteSpace(requestBodyString) ? string.Empty : requestBodyString;","    var requestPath = new Uri(SessionUrl).AbsolutePath.Trim('/');"]},"","    // Create the HMAC signature","    var signature = CreateHmacSignature(","        timestamp,","        requestId,","        requestPath,","        normalizedRequestBody,","        TokenValue);","",{"start":90,"condition":{"steps":["send-session-request"]},"children":["    // Build the Authorization header","    const string authenticationScheme = \"PXP-UST1\";","    var authorizationHeader = $\"{authenticationScheme} {TokenId}:{timestamp}:{signature}\";","","    // Send the request","    var request = new HttpRequestMessage(HttpMethod.Post, SessionUrl)","    {","        Content = new StringContent(requestBodyString, Encoding.UTF8, \"application/json\")","    };","","    request.Headers.TryAddWithoutValidation(\"Authorization\", authorizationHeader);","    request.Headers.Add(\"X-Request-Id\", requestId);","    request.Headers.Add(\"X-Client-Id\", ClientId);","","    using (request)","    {","        using var response = await HttpClient.SendAsync(request);","        var responseContent = await response.Content.ReadAsStringAsync();"]},"",{"start":111,"condition":{"steps":["handle-response"]},"children":["        if (!response.IsSuccessStatusCode)","        {","            throw new InvalidOperationException(","                $\"Session creation failed: {(int)response.StatusCode} {response.ReasonPhrase}{Environment.NewLine}{responseContent}\");","        }","","        var sessionResponse = JsonSerializer.Deserialize<SessionResponse>(responseContent)","            ?? throw new InvalidOperationException(\"Session response could not be read.\");","","        sessionResponse.MerchantTransactionId = merchantTransactionId;","","        return JsonSerializer.Serialize(sessionResponse, IndentedJsonOptions);"]},"    }","}","","// Data transfer objects for session creation","public sealed class SessionRequestBody","{","    [JsonPropertyName(\"merchant\")]","    public string Merchant { get; set; } = string.Empty;","","    [JsonPropertyName(\"site\")]","    public string Site { get; set; } = string.Empty;","","    [JsonPropertyName(\"sessionTimeout\")]","    public int SessionTimeout { get; set; }","","    [JsonPropertyName(\"merchantTransactionId\")]","    public string MerchantTransactionId { get; set; } = string.Empty;","","    [JsonPropertyName(\"transactionMethod\")]","    public SessionTransactionMethod TransactionMethod { get; set; } = new();","","    [JsonPropertyName(\"amounts\")]","    public SessionAmounts Amounts { get; set; } = new();","","    [JsonPropertyName(\"allowTransaction\")]","    public bool AllowTransaction { get; set; }","","    [JsonPropertyName(\"serviceType\")]","    public string ServiceType { get; set; } = string.Empty;","}","","public sealed class SessionTransactionMethod","{","    [JsonPropertyName(\"intent\")]","    public SessionIntent Intent { get; set; } = new();","}","","public sealed class SessionIntent","{","    [JsonPropertyName(\"card\")]","    public string Card { get; set; } = string.Empty;","","    [JsonPropertyName(\"paypal\")]","    public string Paypal { get; set; } = string.Empty;","}","","public sealed class SessionAmounts","{","    [JsonPropertyName(\"currencyCode\")]","    public string CurrencyCode { get; set; } = string.Empty;","","    [JsonPropertyName(\"transactionValue\")]","    public decimal TransactionValue { get; set; }","}","","public sealed class SessionResponse","{","    [JsonPropertyName(\"merchantTransactionId\")]","    public string MerchantTransactionId { get; set; } = string.Empty;","","    [JsonPropertyName(\"sessionId\")]","    public string SessionId { get; set; } = string.Empty;","","    [JsonPropertyName(\"hmacKey\")]","    public string HmacKey { get; set; } = string.Empty;","","    [JsonPropertyName(\"encryptionKey\")]","    public string EncryptionKey { get; set; } = string.Empty;","","    [JsonPropertyName(\"sessionExpiry\")]","    public DateTimeOffset SessionExpiry { get; set; }","","    [JsonPropertyName(\"allowedFundingTypes\")]","    public SessionAllowedFundingTypes AllowedFundingTypes { get; set; } = new();","}","","public sealed class SessionAllowedFundingTypes","{","    [JsonPropertyName(\"cardSchemes\")]","    public List<string> CardSchemes { get; set; } = [];","","    [JsonPropertyName(\"cards\")]","    public List<string> Cards { get; set; } = [];","","    [JsonPropertyName(\"wallets\")]","    public SessionWallets Wallets { get; set; } = new();","}","","public sealed class SessionWallets","{","    [JsonPropertyName(\"paypal\")]","    public SessionPaypalWallet Paypal { get; set; } = new();","","    [JsonPropertyName(\"applePay\")]","    public SessionApplePayWallet ApplePay { get; set; } = new();","","    [JsonPropertyName(\"googlePay\")]","    public SessionGooglePayWallet? GooglePay { get; set; }","}","","public sealed class SessionPaypalWallet","{","    [JsonPropertyName(\"allowedFundingOptions\")]","    public List<string> AllowedFundingOptions { get; set; } = [];","","    [JsonPropertyName(\"merchantId\")]","    public string? MerchantId { get; set; }","}","","public sealed class SessionApplePayWallet","{","    [JsonPropertyName(\"merchantId\")]","    public string? MerchantId { get; set; }","}","","public sealed class SessionGooglePayWallet","{","    [JsonPropertyName(\"merchantId\")]","    public string? MerchantId { get; set; }","","    [JsonPropertyName(\"gatewayMerchantId\")]","    public string? GatewayMerchantId { get; set; }","","    [JsonPropertyName(\"merchantName\")]","    public string? MerchantName { get; set; }","}",""],"metadata":{"steps":["credentials-setup","create-signature-function","build-request-body","send-session-request","handle-response"]},"basename":"create-session.cs","language":"csharp"}],"when":{"Backend":"dotnet"}}],"steps":[{"id":"credentials-setup","heading":"Store your credentials securely"},{"id":"create-signature-function","heading":"Create the HMAC signature function"},{"id":"build-request-body","heading":"Build the session request body"},{"id":"send-session-request","heading":"Send the session creation request"},{"id":"handle-response","heading":"Return the session data to your frontend"}],"inputs":{},"toggles":{}},"children":[{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"create-a-session-on-your-backend","__idx":3},"children":["Create a session on your backend"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Drop-in needs a session from the PXP API. This must happen on your backend using HMAC authentication."]},{"$$mdtype":"Tag","name":"CodeStep","attributes":{"id":"credentials-setup","heading":"Store your credentials securely"},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Set up your API credentials as environment variables — never hardcode them in your application."]}]},{"$$mdtype":"Tag","name":"CodeStep","attributes":{"id":"create-signature-function","heading":"Create the HMAC signature function"},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["This function generates a secure authentication hash by combining your token ID, timestamp, request ID, request path, and request body, then hashing with your token value using HMAC SHA256."]}]},{"$$mdtype":"Tag","name":"CodeStep","attributes":{"id":"build-request-body","heading":"Build the session request body"},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Create a request with your merchant details and transaction information. The request body must be minified (no whitespace) for the HMAC signature."]}]},{"$$mdtype":"Tag","name":"CodeStep","attributes":{"id":"send-session-request","heading":"Send the session creation request"},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["POST to ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["https://api-services.pxp.io/api/v1/sessions"]}," with your authentication headers and request body."]}]},{"$$mdtype":"Tag","name":"CodeStep","attributes":{"id":"handle-response","heading":"Return the session data to your frontend"},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The API returns ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["sessionId"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["hmacKey"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["encryptionKey"]},", and ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["allowedFundingTypes"]},". Pass this entire response to your frontend."]}]}]},{"$$mdtype":"Tag","name":"CodeWalkthrough","attributes":{"__idx":2,"filters":{},"filesets":[{"files":[{"path":"guides/checkout/drop-in/web/_filesets/installation/CheckoutPage.tsx","content":[{"start":0,"condition":{"steps":["import-dependencies"]},"children":["import CheckoutDropIn from '@pxpio/web-components-sdk/src/checkoutDropIn/CheckoutDropIn';\r","import IntentType from '@pxpio/web-components-sdk/src/basePxpCheckout/types/IntentType';\r","import PaymentMethod from '@pxpio/web-components-sdk/src/components/checkoutDropInComponents/types/PaymentMethod';\r","import { BaseSubmitResult } from '@pxpio/web-components-sdk/src/checkoutDropIn/types/BaseSubmitResult';\r","import BaseSdkException from '@pxpio/web-components-sdk/src/types/sdkExceptions/BaseSdkException';\r","import { useEffect } from 'react';\r"]},"\r",{"start":9,"condition":{"steps":["setup-component"]},"children":["export default function CheckoutPage() {\r","  useEffect(() => {\r","    initialiseCheckoutDropIn();\r","  }, []);\r","\r","  async function initialiseCheckoutDropIn() {\r",{"start":16,"condition":{"steps":["fetch-session"]},"children":["    // 1. Get the session data from your backend\r","    const sessionData = await fetch('/api/create-session', {\r","      method: 'POST',\r","      headers: { 'Content-Type': 'application/json' },\r","      body: JSON.stringify({\r","        merchantId: 'MERCHANT-1', // Replace with your merchant ID\r","        siteId: 'SITE-1', // Replace with your site ID\r","        amount: 25.00,\r","        currency: 'USD'\r","      })\r","    }).then(response => response.json());\r"]},"\r",{"start":30,"condition":{"steps":["initialize-dropin"]},"children":["    // 2. Initialise Checkout Drop-in\r","    const checkoutDropIn = CheckoutDropIn.initialize({\r","      environment: 'test',\r","      session: sessionData,\r","      ownerId: 'MERCHANT-1',\r","      ownerType: 'MerchantGroup',\r",{"start":37,"condition":{"steps":["configure-transaction"]},"children":["      transactionData: {\r","        currency: 'USD',\r","        amount: 25.00,\r","        entryType: 'Ecom',\r","        intent: {\r","          card: IntentType.Authorisation,\r","          paypal: IntentType.Purchase\r","        },\r","        merchantTransactionId: sessionData.merchantTransactionId,\r","        merchantTransactionDate: () => new Date().toISOString()\r","      },\r"]},{"start":50,"condition":{"steps":["setup-shopper"]},"children":["      onGetShopper: () => Promise.resolve({ id: 'shopper-123' }),\r"]},{"start":53,"condition":{"steps":["before-submit-callback"]},"children":["      onBeforeSubmit: async (paymentMethod: PaymentMethod) => {\r","        console.log('Payment method selected:', paymentMethod);\r","        return true;\r","      },\r"]},{"start":59,"condition":{"steps":["submit-callback"]},"children":["      onSubmit: (paymentMethod: PaymentMethod) => {\r","        console.log('Payment being processed:', paymentMethod);\r","      },\r"]},{"start":64,"condition":{"steps":["success-callback"]},"children":["      onSuccess: async (result: BaseSubmitResult) => {\r","        // CRITICAL: Do NOT fulfill order here!\r","        // Frontend callbacks can be manipulated by malicious users.\r","        // Always verify payment on your backend first.\r","        \r","        console.log('Payment successful:', result.systemTransactionId);\r","        \r","        // Verify payment on your backend\r","        const verified = await fetch('/api/verify-payment', {\r","          method: 'POST',\r","          headers: { 'Content-Type': 'application/json' },\r","          body: JSON.stringify({\r","            systemTransactionId: result.systemTransactionId,\r","            merchantTransactionId: result.merchantTransactionId,\r","            amount: 25.00\r","          })\r","        }).then(r => r.json());\r","        \r","        if (verified.success) {\r","          window.location.href = `/success?orderId=${verified.orderId}`;\r","        } else {\r","          alert('Payment verification failed. Please contact support.');\r","        }\r","      },\r"]},{"start":90,"condition":{"steps":["error-callback"]},"children":["      onError: (error: BaseSdkException) => {\r","        console.error('Payment failed:', error);\r","        alert(`Payment failed: ${error.message}`);\r","      }\r"]},"    });\r"]},"\r",{"start":99,"condition":{"steps":["mount-dropin"]},"children":["    // 3. Mount the drop-in to your page\r","    await checkoutDropIn.create('checkout-drop-in-container');\r"]},"  }\r","\r",{"start":105,"condition":{"steps":["render-container"]},"children":["  return (\r","    <div>\r","      <h1>Complete Your Purchase</h1>\r","      <div id=\"checkout-drop-in-container\"></div>\r","    </div>\r","  );\r"]},"}\r"]},""],"metadata":{"steps":["import-dependencies","setup-component","fetch-session","initialize-dropin","configure-transaction","setup-shopper","before-submit-callback","submit-callback","success-callback","error-callback","mount-dropin","render-container"]},"basename":"CheckoutPage.tsx","language":"tsx"}],"downloadAssociatedFiles":[{"path":"guides/checkout/drop-in/web/_filesets/installation/CheckoutPage.tsx","content":[{"start":0,"condition":{"steps":["import-dependencies"]},"children":["import CheckoutDropIn from '@pxpio/web-components-sdk/src/checkoutDropIn/CheckoutDropIn';\r","import IntentType from '@pxpio/web-components-sdk/src/basePxpCheckout/types/IntentType';\r","import PaymentMethod from '@pxpio/web-components-sdk/src/components/checkoutDropInComponents/types/PaymentMethod';\r","import { BaseSubmitResult } from '@pxpio/web-components-sdk/src/checkoutDropIn/types/BaseSubmitResult';\r","import BaseSdkException from '@pxpio/web-components-sdk/src/types/sdkExceptions/BaseSdkException';\r","import { useEffect } from 'react';\r"]},"\r",{"start":9,"condition":{"steps":["setup-component"]},"children":["export default function CheckoutPage() {\r","  useEffect(() => {\r","    initialiseCheckoutDropIn();\r","  }, []);\r","\r","  async function initialiseCheckoutDropIn() {\r",{"start":16,"condition":{"steps":["fetch-session"]},"children":["    // 1. Get the session data from your backend\r","    const sessionData = await fetch('/api/create-session', {\r","      method: 'POST',\r","      headers: { 'Content-Type': 'application/json' },\r","      body: JSON.stringify({\r","        merchantId: 'MERCHANT-1', // Replace with your merchant ID\r","        siteId: 'SITE-1', // Replace with your site ID\r","        amount: 25.00,\r","        currency: 'USD'\r","      })\r","    }).then(response => response.json());\r"]},"\r",{"start":30,"condition":{"steps":["initialize-dropin"]},"children":["    // 2. Initialise Checkout Drop-in\r","    const checkoutDropIn = CheckoutDropIn.initialize({\r","      environment: 'test',\r","      session: sessionData,\r","      ownerId: 'MERCHANT-1',\r","      ownerType: 'MerchantGroup',\r",{"start":37,"condition":{"steps":["configure-transaction"]},"children":["      transactionData: {\r","        currency: 'USD',\r","        amount: 25.00,\r","        entryType: 'Ecom',\r","        intent: {\r","          card: IntentType.Authorisation,\r","          paypal: IntentType.Purchase\r","        },\r","        merchantTransactionId: sessionData.merchantTransactionId,\r","        merchantTransactionDate: () => new Date().toISOString()\r","      },\r"]},{"start":50,"condition":{"steps":["setup-shopper"]},"children":["      onGetShopper: () => Promise.resolve({ id: 'shopper-123' }),\r"]},{"start":53,"condition":{"steps":["before-submit-callback"]},"children":["      onBeforeSubmit: async (paymentMethod: PaymentMethod) => {\r","        console.log('Payment method selected:', paymentMethod);\r","        return true;\r","      },\r"]},{"start":59,"condition":{"steps":["submit-callback"]},"children":["      onSubmit: (paymentMethod: PaymentMethod) => {\r","        console.log('Payment being processed:', paymentMethod);\r","      },\r"]},{"start":64,"condition":{"steps":["success-callback"]},"children":["      onSuccess: async (result: BaseSubmitResult) => {\r","        // CRITICAL: Do NOT fulfill order here!\r","        // Frontend callbacks can be manipulated by malicious users.\r","        // Always verify payment on your backend first.\r","        \r","        console.log('Payment successful:', result.systemTransactionId);\r","        \r","        // Verify payment on your backend\r","        const verified = await fetch('/api/verify-payment', {\r","          method: 'POST',\r","          headers: { 'Content-Type': 'application/json' },\r","          body: JSON.stringify({\r","            systemTransactionId: result.systemTransactionId,\r","            merchantTransactionId: result.merchantTransactionId,\r","            amount: 25.00\r","          })\r","        }).then(r => r.json());\r","        \r","        if (verified.success) {\r","          window.location.href = `/success?orderId=${verified.orderId}`;\r","        } else {\r","          alert('Payment verification failed. Please contact support.');\r","        }\r","      },\r"]},{"start":90,"condition":{"steps":["error-callback"]},"children":["      onError: (error: BaseSdkException) => {\r","        console.error('Payment failed:', error);\r","        alert(`Payment failed: ${error.message}`);\r","      }\r"]},"    });\r"]},"\r",{"start":99,"condition":{"steps":["mount-dropin"]},"children":["    // 3. Mount the drop-in to your page\r","    await checkoutDropIn.create('checkout-drop-in-container');\r"]},"  }\r","\r",{"start":105,"condition":{"steps":["render-container"]},"children":["  return (\r","    <div>\r","      <h1>Complete Your Purchase</h1>\r","      <div id=\"checkout-drop-in-container\"></div>\r","    </div>\r","  );\r"]},"}\r"]},""],"metadata":{"steps":["import-dependencies","setup-component","fetch-session","initialize-dropin","configure-transaction","setup-shopper","before-submit-callback","submit-callback","success-callback","error-callback","mount-dropin","render-container"]},"basename":"CheckoutPage.tsx","language":"tsx"},{"path":"guides/checkout/drop-in/web/_filesets/installation/package.json","content":[{"start":0,"condition":{"steps":["install-sdk"]},"children":["{\r","  \"name\": \"checkout-integration\",\r","  \"version\": \"1.0.0\",\r","  \"description\": \"PXP Checkout Drop-in integration example\",\r","  \"type\": \"module\",\r","  \"scripts\": {\r","    \"dev\": \"vite\",\r","    \"build\": \"vite build\"\r","  },\r","  \"dependencies\": {\r","    \"@pxpio/web-components-sdk\": \"^latest\",\r","    \"react\": \"^18.2.0\",\r","    \"react-dom\": \"^18.2.0\"\r","  },\r","  \"devDependencies\": {\r","    \"@vitejs/plugin-react\": \"^4.0.0\",\r","    \"vite\": \"^4.0.0\"\r","  }\r","}\r"]}],"metadata":{"steps":["install-sdk"]},"basename":"package.json","language":"text"}]}],"steps":[{"id":"import-dependencies","heading":"Import the required dependencies"},{"id":"setup-component","heading":"Set up your React component"},{"id":"fetch-session","heading":"Fetch the session data from your backend"},{"id":"initialize-dropin","heading":"Initialise Checkout Drop-in"},{"id":"configure-transaction","heading":"Configure the transaction data"},{"id":"setup-shopper","heading":"Provide a shopper identifier"},{"id":"success-callback","heading":"Handle successful payments"},{"id":"error-callback","heading":"Handle payment errors"},{"id":"mount-dropin","heading":"Mount Drop-in to the page"},{"id":"render-container","heading":"Add a container element to your page"}],"inputs":{},"toggles":{}},"children":[{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"initialise-drop-in-on-your-frontend","__idx":4},"children":["Initialise Drop-in on your frontend"]},{"$$mdtype":"Tag","name":"CodeStep","attributes":{"id":"import-dependencies","heading":"Import the required dependencies"},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Import ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["CheckoutDropIn"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["IntentType"]},", and the necessary types from the Web SDK."]}]},{"$$mdtype":"Tag","name":"CodeStep","attributes":{"id":"setup-component","heading":"Set up your React component"},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Create a React component that will host the Checkout Drop-in interface."]}]},{"$$mdtype":"Tag","name":"CodeStep","attributes":{"id":"fetch-session","heading":"Fetch the session data from your backend"},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Call your backend endpoint to get the session data you created in the previous steps."]}]},{"$$mdtype":"Tag","name":"CodeStep","attributes":{"id":"initialize-dropin","heading":"Initialise Checkout Drop-in"},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Configure Drop-in with your environment, session data, and transaction details."]}]},{"$$mdtype":"Tag","name":"CodeStep","attributes":{"id":"configure-transaction","heading":"Configure the transaction data"},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Specify the currency, amount, entry type, and payment intents for each payment method."]}]},{"$$mdtype":"Tag","name":"CodeStep","attributes":{"id":"setup-shopper","heading":"Provide a shopper identifier"},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Implement the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onGetShopper"]}," callback to provide shopper information. This is required for Card-on-File functionality."]}]},{"$$mdtype":"Tag","name":"CodeStep","attributes":{"id":"success-callback","heading":"Handle successful payments"},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Implement the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onSuccess"]}," callback to handle successful payments. Always verify payments on your backend before fulfilling orders — frontend callbacks can be manipulated."]}]},{"$$mdtype":"Tag","name":"CodeStep","attributes":{"id":"error-callback","heading":"Handle payment errors"},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Implement the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onError"]}," callback to handle payment failures and display appropriate error messages."]}]},{"$$mdtype":"Tag","name":"CodeStep","attributes":{"id":"mount-dropin","heading":"Mount Drop-in to the page"},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Call the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["create()"]}," method with your container element ID to render the payment interface."]}]},{"$$mdtype":"Tag","name":"CodeStep","attributes":{"id":"render-container","heading":"Add a container element to your page"},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Return JSX that includes a container div where Checkout Drop-in will mount itself."]}]}]},{"$$mdtype":"Tag","name":"CodeWalkthrough","attributes":{"__idx":3,"filters":{"Backend":{"items":[{"label":"Node.js","value":"nodejs"},{"label":".NET","value":"dotnet"}],"default":"nodejs"}},"filesets":[{"files":[{"path":"guides/checkout/drop-in/web/_filesets/installation/webhook-handler.js","content":[{"start":0,"condition":{"steps":["webhook-endpoint"]},"children":["// Webhook endpoint to receive payment notifications\r","// Configure this URL in the Unity Portal under Webhooks\r","app.post('/webhooks/pxp', async (req, res) => {\r"]},{"start":5,"condition":{"steps":["process-events"]},"children":["  const events = req.body;\r","  \r","  // Process each webhook event\r","  for (const event of events) {\r","    if (event.eventCategory === 'Transaction') {\r","      const txn = event.eventData;\r"]},"      \r",{"start":14,"condition":{"steps":["check-state"]},"children":["      // Check if payment was successful\r","      if (txn.state === 'Authorised' || txn.state === 'Captured') {\r"]},{"start":18,"condition":{"steps":["prevent-duplicates"]},"children":["        // Prevent duplicate processing\r","        const alreadyProcessed = await isTransactionProcessed(txn.systemTransactionId);\r","        if (alreadyProcessed) {\r","          continue;\r","        }\r"]},"        \r",{"start":26,"condition":{"steps":["verify-details"]},"children":["        // Verify transaction details match your records\r","        const expectedOrder = await getOrderByMerchantTransactionId(txn.merchantTransactionId);\r","        \r","        if (expectedOrder && \r","            txn.amounts.transactionValue === expectedOrder.amount &&\r","            txn.amounts.currencyCode === expectedOrder.currency) {\r"]},"          \r",{"start":35,"condition":{"steps":["fulfill-order"]},"children":["          // Payment verified - fulfill the order\r","          await fulfillOrder(txn.merchantTransactionId);\r","          \r","          // Mark as processed to prevent duplicates\r","          await markTransactionProcessed(txn.systemTransactionId);\r","          \r","          console.log(`Order ${txn.merchantTransactionId} fulfilled successfully`);\r"]},"        } else {\r","          console.error('Transaction verification failed - amount or currency mismatch');\r","        }\r","      }\r","    }\r","  }\r","  \r",{"start":51,"condition":{"steps":["respond"]},"children":["  // Always return success to acknowledge receipt\r","  res.json({ state: 'Success' });\r"]},"});\r",""],"metadata":{"steps":["webhook-endpoint","process-events","check-state","prevent-duplicates","verify-details","fulfill-order","respond"]},"basename":"webhook-handler.js","language":"javascript"}],"downloadAssociatedFiles":[{"path":"guides/checkout/drop-in/web/_filesets/installation/webhook-handler.js","content":[{"start":0,"condition":{"steps":["webhook-endpoint"]},"children":["// Webhook endpoint to receive payment notifications\r","// Configure this URL in the Unity Portal under Webhooks\r","app.post('/webhooks/pxp', async (req, res) => {\r"]},{"start":5,"condition":{"steps":["process-events"]},"children":["  const events = req.body;\r","  \r","  // Process each webhook event\r","  for (const event of events) {\r","    if (event.eventCategory === 'Transaction') {\r","      const txn = event.eventData;\r"]},"      \r",{"start":14,"condition":{"steps":["check-state"]},"children":["      // Check if payment was successful\r","      if (txn.state === 'Authorised' || txn.state === 'Captured') {\r"]},{"start":18,"condition":{"steps":["prevent-duplicates"]},"children":["        // Prevent duplicate processing\r","        const alreadyProcessed = await isTransactionProcessed(txn.systemTransactionId);\r","        if (alreadyProcessed) {\r","          continue;\r","        }\r"]},"        \r",{"start":26,"condition":{"steps":["verify-details"]},"children":["        // Verify transaction details match your records\r","        const expectedOrder = await getOrderByMerchantTransactionId(txn.merchantTransactionId);\r","        \r","        if (expectedOrder && \r","            txn.amounts.transactionValue === expectedOrder.amount &&\r","            txn.amounts.currencyCode === expectedOrder.currency) {\r"]},"          \r",{"start":35,"condition":{"steps":["fulfill-order"]},"children":["          // Payment verified - fulfill the order\r","          await fulfillOrder(txn.merchantTransactionId);\r","          \r","          // Mark as processed to prevent duplicates\r","          await markTransactionProcessed(txn.systemTransactionId);\r","          \r","          console.log(`Order ${txn.merchantTransactionId} fulfilled successfully`);\r"]},"        } else {\r","          console.error('Transaction verification failed - amount or currency mismatch');\r","        }\r","      }\r","    }\r","  }\r","  \r",{"start":51,"condition":{"steps":["respond"]},"children":["  // Always return success to acknowledge receipt\r","  res.json({ state: 'Success' });\r"]},"});\r",""],"metadata":{"steps":["webhook-endpoint","process-events","check-state","prevent-duplicates","verify-details","fulfill-order","respond"]},"basename":"webhook-handler.js","language":"javascript"}],"when":{"Backend":"nodejs"}},{"files":[{"path":"guides/checkout/drop-in/web/_filesets/installation/webhook-handler.cs","content":["using System.Text.Json;","using System.Text.Json.Serialization;","",{"start":3,"condition":{"steps":["webhook-endpoint"]},"children":["// Webhook endpoint to receive payment notifications","// Configure this URL in the Unity Portal under Webhooks","app.MapPost(\"/webhooks/pxp\", async (string webhookJson) =>","{"]},{"start":9,"condition":{"steps":["process-events"]},"children":["    var events = JsonSerializer.Deserialize<List<PxpWebhookEvent>>(webhookJson)","        ?? [];","","    // Process each webhook event","    foreach (var webhookEvent in events)","    {","        if (webhookEvent.EventCategory == \"Transaction\" && webhookEvent.EventData is not null)","        {","            var transaction = webhookEvent.EventData;"]},"",{"start":21,"condition":{"steps":["check-state"]},"children":["            // Check if payment was successful","            if (transaction.State == \"Authorised\" || transaction.State == \"Captured\")","            {"]},{"start":26,"condition":{"steps":["prevent-duplicates"]},"children":["                // Prevent duplicate processing","                var alreadyProcessed = await IsTransactionProcessedAsync(transaction.SystemTransactionId);","                if (alreadyProcessed)","                {","                    continue;","                }"]},"",{"start":35,"condition":{"steps":["verify-details"]},"children":["                // Verify transaction details match your records","                var expectedOrder = await GetOrderByMerchantTransactionIdAsync(transaction.MerchantTransactionId);","","                if (expectedOrder is not null &&","                    transaction.Amounts.TransactionValue == expectedOrder.Amount &&","                    transaction.Amounts.CurrencyCode == expectedOrder.Currency)","                {"]},"",{"start":45,"condition":{"steps":["fulfill-order"]},"children":["                    // Payment verified - fulfill the order","                    await FulfillOrderAsync(transaction.MerchantTransactionId);","","                    // Mark as processed to prevent duplicates","                    await MarkTransactionProcessedAsync(transaction.SystemTransactionId);","","                    Console.WriteLine($\"Order {transaction.MerchantTransactionId} fulfilled successfully\");"]},"                }","                else","                {","                    Console.Error.WriteLine(\"Transaction verification failed - amount or currency mismatch\");","                }","            }","        }","    }","",{"start":63,"condition":{"steps":["respond"]},"children":["    // Always return success to acknowledge receipt","    return Results.Content(JsonSerializer.Serialize(new WebhookAcknowledgement","    {","        State = \"Success\"","    }), \"application/json\");"]},"});","","// Helper methods (replace with your own implementation)","static Task<bool> IsTransactionProcessedAsync(string systemTransactionId)","{","    // Replace this with your real storage check","    return Task.FromResult(false);","}","","static Task<OrderRecord?> GetOrderByMerchantTransactionIdAsync(string merchantTransactionId)","{","    // Replace this with your real order lookup","    return Task.FromResult<OrderRecord?>(null);","}","","static Task FulfillOrderAsync(string merchantTransactionId)","{","    // Replace this with your real order fulfillment logic","    return Task.CompletedTask;","}","","static Task MarkTransactionProcessedAsync(string systemTransactionId)","{","    // Replace this with your real duplicate-protection storage update","    return Task.CompletedTask;","}","","// Data transfer objects for webhook handling","public sealed class PxpWebhookEvent","{","    [JsonPropertyName(\"eventCategory\")]","    public string EventCategory { get; set; } = string.Empty;","","    [JsonPropertyName(\"eventData\")]","    public TransactionWebhookData? EventData { get; set; }","}","","public sealed class TransactionWebhookData","{","    [JsonPropertyName(\"state\")]","    public string State { get; set; } = string.Empty;","","    [JsonPropertyName(\"systemTransactionId\")]","    public string SystemTransactionId { get; set; } = string.Empty;","","    [JsonPropertyName(\"merchantTransactionId\")]","    public string MerchantTransactionId { get; set; } = string.Empty;","","    [JsonPropertyName(\"amounts\")]","    public WebhookAmounts Amounts { get; set; } = new();","}","","public sealed class WebhookAmounts","{","    [JsonPropertyName(\"transactionValue\")]","    public decimal TransactionValue { get; set; }","","    [JsonPropertyName(\"currencyCode\")]","    public string CurrencyCode { get; set; } = string.Empty;","}","","public sealed class OrderRecord","{","    public decimal Amount { get; set; }","","    public string Currency { get; set; } = string.Empty;","}","","public sealed class WebhookAcknowledgement","{","    [JsonPropertyName(\"state\")]","    public string State { get; set; } = string.Empty;","}",""],"metadata":{"steps":["webhook-endpoint","process-events","check-state","prevent-duplicates","verify-details","fulfill-order","respond"]},"basename":"webhook-handler.cs","language":"csharp"}],"downloadAssociatedFiles":[{"path":"guides/checkout/drop-in/web/_filesets/installation/webhook-handler.cs","content":["using System.Text.Json;","using System.Text.Json.Serialization;","",{"start":3,"condition":{"steps":["webhook-endpoint"]},"children":["// Webhook endpoint to receive payment notifications","// Configure this URL in the Unity Portal under Webhooks","app.MapPost(\"/webhooks/pxp\", async (string webhookJson) =>","{"]},{"start":9,"condition":{"steps":["process-events"]},"children":["    var events = JsonSerializer.Deserialize<List<PxpWebhookEvent>>(webhookJson)","        ?? [];","","    // Process each webhook event","    foreach (var webhookEvent in events)","    {","        if (webhookEvent.EventCategory == \"Transaction\" && webhookEvent.EventData is not null)","        {","            var transaction = webhookEvent.EventData;"]},"",{"start":21,"condition":{"steps":["check-state"]},"children":["            // Check if payment was successful","            if (transaction.State == \"Authorised\" || transaction.State == \"Captured\")","            {"]},{"start":26,"condition":{"steps":["prevent-duplicates"]},"children":["                // Prevent duplicate processing","                var alreadyProcessed = await IsTransactionProcessedAsync(transaction.SystemTransactionId);","                if (alreadyProcessed)","                {","                    continue;","                }"]},"",{"start":35,"condition":{"steps":["verify-details"]},"children":["                // Verify transaction details match your records","                var expectedOrder = await GetOrderByMerchantTransactionIdAsync(transaction.MerchantTransactionId);","","                if (expectedOrder is not null &&","                    transaction.Amounts.TransactionValue == expectedOrder.Amount &&","                    transaction.Amounts.CurrencyCode == expectedOrder.Currency)","                {"]},"",{"start":45,"condition":{"steps":["fulfill-order"]},"children":["                    // Payment verified - fulfill the order","                    await FulfillOrderAsync(transaction.MerchantTransactionId);","","                    // Mark as processed to prevent duplicates","                    await MarkTransactionProcessedAsync(transaction.SystemTransactionId);","","                    Console.WriteLine($\"Order {transaction.MerchantTransactionId} fulfilled successfully\");"]},"                }","                else","                {","                    Console.Error.WriteLine(\"Transaction verification failed - amount or currency mismatch\");","                }","            }","        }","    }","",{"start":63,"condition":{"steps":["respond"]},"children":["    // Always return success to acknowledge receipt","    return Results.Content(JsonSerializer.Serialize(new WebhookAcknowledgement","    {","        State = \"Success\"","    }), \"application/json\");"]},"});","","// Helper methods (replace with your own implementation)","static Task<bool> IsTransactionProcessedAsync(string systemTransactionId)","{","    // Replace this with your real storage check","    return Task.FromResult(false);","}","","static Task<OrderRecord?> GetOrderByMerchantTransactionIdAsync(string merchantTransactionId)","{","    // Replace this with your real order lookup","    return Task.FromResult<OrderRecord?>(null);","}","","static Task FulfillOrderAsync(string merchantTransactionId)","{","    // Replace this with your real order fulfillment logic","    return Task.CompletedTask;","}","","static Task MarkTransactionProcessedAsync(string systemTransactionId)","{","    // Replace this with your real duplicate-protection storage update","    return Task.CompletedTask;","}","","// Data transfer objects for webhook handling","public sealed class PxpWebhookEvent","{","    [JsonPropertyName(\"eventCategory\")]","    public string EventCategory { get; set; } = string.Empty;","","    [JsonPropertyName(\"eventData\")]","    public TransactionWebhookData? EventData { get; set; }","}","","public sealed class TransactionWebhookData","{","    [JsonPropertyName(\"state\")]","    public string State { get; set; } = string.Empty;","","    [JsonPropertyName(\"systemTransactionId\")]","    public string SystemTransactionId { get; set; } = string.Empty;","","    [JsonPropertyName(\"merchantTransactionId\")]","    public string MerchantTransactionId { get; set; } = string.Empty;","","    [JsonPropertyName(\"amounts\")]","    public WebhookAmounts Amounts { get; set; } = new();","}","","public sealed class WebhookAmounts","{","    [JsonPropertyName(\"transactionValue\")]","    public decimal TransactionValue { get; set; }","","    [JsonPropertyName(\"currencyCode\")]","    public string CurrencyCode { get; set; } = string.Empty;","}","","public sealed class OrderRecord","{","    public decimal Amount { get; set; }","","    public string Currency { get; set; } = string.Empty;","}","","public sealed class WebhookAcknowledgement","{","    [JsonPropertyName(\"state\")]","    public string State { get; set; } = string.Empty;","}",""],"metadata":{"steps":["webhook-endpoint","process-events","check-state","prevent-duplicates","verify-details","fulfill-order","respond"]},"basename":"webhook-handler.cs","language":"csharp"}],"when":{"Backend":"dotnet"}}],"steps":[{"id":"webhook-endpoint","heading":"Create the webhook endpoint"},{"id":"process-events","heading":"Process webhook events"},{"id":"check-state","heading":"Check payment state"},{"id":"prevent-duplicates","heading":"Prevent duplicate processing"},{"id":"verify-details","heading":"Verify transaction details"},{"id":"fulfill-order","heading":"Fulfill the order"},{"id":"respond","heading":"Respond to webhook"}],"inputs":{},"toggles":{}},"children":[{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"verify-payments","__idx":5},"children":["Verify payments"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["When a payment succeeds, the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onSuccess"]}," callback fires with transaction details. However, you must ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["always verify the payment on your backend"]}," before fulfilling orders."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Configure webhooks in the Unity Portal to receive real-time payment notifications on your backend."]},{"$$mdtype":"Tag","name":"CodeStep","attributes":{"id":"webhook-endpoint","heading":"Create the webhook endpoint"},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Set up an endpoint at ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["/webhooks/pxp"]}," to receive payment notifications from Unity."]}]},{"$$mdtype":"Tag","name":"CodeStep","attributes":{"id":"process-events","heading":"Process webhook events"},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Loop through the events array and filter for Transaction events."]}]},{"$$mdtype":"Tag","name":"CodeStep","attributes":{"id":"check-state","heading":"Check payment state"},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Verify the transaction state is ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["Authorised"]}," or ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["Captured"]}," before processing."]}]},{"$$mdtype":"Tag","name":"CodeStep","attributes":{"id":"prevent-duplicates","heading":"Prevent duplicate processing"},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Check if you've already processed this transaction using ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["systemTransactionId"]},"."]}]},{"$$mdtype":"Tag","name":"CodeStep","attributes":{"id":"verify-details","heading":"Verify transaction details"},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Match the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["merchantTransactionId"]},", amount, and currency against your order records."]}]},{"$$mdtype":"Tag","name":"CodeStep","attributes":{"id":"fulfill-order","heading":"Fulfill the order"},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["If verification passes, fulfill the order and mark the transaction as processed."]}]},{"$$mdtype":"Tag","name":"CodeStep","attributes":{"id":"respond","heading":"Respond to webhook"},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Always return ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["{ state: 'Success' }"]}," to acknowledge receipt, even if processing failed."]}]},{"$$mdtype":"Tag","name":"Admonition","attributes":{"type":"info"},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["You can also verify payments using the Transactions API to query transaction status directly. See the ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/guides/checkout/drop-in/web/implementation#backend-verification-critical"},"children":["Integration guide"]}," for details."]}]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["That's it! You now have a working Checkout Drop-in integration."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"whats-next","__idx":6},"children":["What's next?"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Now that you have Drop-in running, here are the recommended next steps:"]},{"$$mdtype":"Tag","name":"ul","attributes":{"className":"code-walkthrough-list"},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":[{"$$mdtype":"Tag","name":"a","attributes":{"href":"/guides/checkout/drop-in/branding"},"children":["Customise the look and feel"]}]}," to match your brand"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":[{"$$mdtype":"Tag","name":"a","attributes":{"href":"/guides/checkout/drop-in/web/implementation#backend-verification-critical"},"children":["Set up backend verification for Web"]}]}," to verify payments before fulfilling orders"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":[{"$$mdtype":"Tag","name":"a","attributes":{"href":"/guides/checkout/drop-in/web/events"},"children":["Add optional callbacks for Web"]}]}," to enhance the user experience with validation and loading states"]}]}]},"headings":[{"value":"Quickstart","id":"quickstart","depth":1},{"value":"Pre-requisites","id":"pre-requisites","depth":2},{"value":"Install the SDK","id":"install-the-sdk","depth":2},{"value":"Create a session on your backend","id":"create-a-session-on-your-backend","depth":2},{"value":"Initialise Drop-in on your frontend","id":"initialise-drop-in-on-your-frontend","depth":2},{"value":"Verify payments","id":"verify-payments","depth":2},{"value":"What's next?","id":"whats-next","depth":2}],"frontmatter":{"markdown":{"toc":{"hide":true}},"footer":{"hide":true},"seo":{"title":"Quickstart"}},"lastModified":"2026-05-20T12:46:49.000Z","pagePropGetterError":{"message":"","name":""}},"slug":"/guides/checkout/drop-in/web/quickstart","userData":{"isAuthenticated":false,"teams":["anonymous"]},"isPublic":true}