From 0cb467325df3519112e91bb4d869348fc8fc12c3 Mon Sep 17 00:00:00 2001
From: Justintime50 <39606064+Justintime50@users.noreply.github.com>
Date: Wed, 19 Nov 2025 15:26:18 -0700
Subject: [PATCH 1/2] feat: add portal and embeddable sessions
---
CHANGELOG.md | 6 +++
.../Models/API/CustomerPortalAccountLink.cs | 39 +++++++++++++++
EasyPost/Models/API/EmbeddablesSession.cs | 40 +++++++++++++++
.../CustomerPortal/CreateAccountLink.cs | 49 +++++++++++++++++++
.../Parameters/Embeddable/CreateSession.cs | 1 +
EasyPost/Services/CustomerPortalService.cs | 39 +++++++++++++++
EasyPost/Services/EmbeddableService.cs | 1 +
7 files changed, 175 insertions(+)
create mode 100644 EasyPost/Models/API/CustomerPortalAccountLink.cs
create mode 100644 EasyPost/Models/API/EmbeddablesSession.cs
create mode 100644 EasyPost/Parameters/CustomerPortal/CreateAccountLink.cs
create mode 100644 EasyPost/Parameters/Embeddable/CreateSession.cs
create mode 100644 EasyPost/Services/CustomerPortalService.cs
create mode 100644 EasyPost/Services/EmbeddableService.cs
diff --git a/CHANGELOG.md b/CHANGELOG.md
index a5b167ed..1c397829 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,11 @@
# CHANGELOG
+## Next Release
+
+- Adds the following functions:
+ - `CustomerPortal.CreateAccountLink`
+ - `Embeddable.CreateSession`
+
## v7.3.0 (2025-11-10)
- Adds support for `UspsShipAccount`
diff --git a/EasyPost/Models/API/CustomerPortalAccountLink.cs b/EasyPost/Models/API/CustomerPortalAccountLink.cs
new file mode 100644
index 00000000..7eff0032
--- /dev/null
+++ b/EasyPost/Models/API/CustomerPortalAccountLink.cs
@@ -0,0 +1,39 @@
+using EasyPost._base;
+using Newtonsoft.Json;
+
+namespace EasyPost.Models.API
+{
+ ///
+ /// Class representing a CustomerPortalAccountLink.
+ ///
+ public class CustomerPortalAccountLink : EphemeralEasyPostObject
+ {
+ #region JSON Properties
+
+ ///
+ /// Always returns "CustomerPortalAccountLink".
+ ///
+ [JsonProperty("object")]
+ public string? Object { get; set; }
+
+ ///
+ /// One-time-use session URL for initiating the Customer Portal.
+ ///
+ [JsonProperty("link")]
+ public string? Link { get; set; }
+
+ ///
+ /// One-time-use session URL for initiating the Customer Portal.
+ ///
+ [JsonProperty("created_at")]
+ public string? CreatedAt { get; set; }
+
+ ///
+ /// ISO 8601 timestamp when the link will expire (5 minutes from creation).
+ ///
+ [JsonProperty("expires_at")]
+ public string? ExpiresAt { get; set; }
+
+ #endregion
+ }
+}
diff --git a/EasyPost/Models/API/EmbeddablesSession.cs b/EasyPost/Models/API/EmbeddablesSession.cs
new file mode 100644
index 00000000..51dc88ee
--- /dev/null
+++ b/EasyPost/Models/API/EmbeddablesSession.cs
@@ -0,0 +1,40 @@
+using EasyPost._base;
+using Newtonsoft.Json;
+
+namespace EasyPost.Models.API
+{
+ ///
+ /// Class representing an EmbeddablesSession.
+ ///
+ public class EmbeddablesSession : EphemeralEasyPostObject
+ {
+ #region JSON Properties
+
+ ///
+ /// Always returns "EmbeddablesSession".
+ ///
+ [JsonProperty("object")]
+ public string? Object { get; set; }
+
+ ///
+ /// Short-lived, one-time-use token that authorizes an Embeddables Components session.
+ /// Must be provided to the client-side Embeddables script to initialize the component.
+ ///
+ [JsonProperty("session_id")]
+ public string? SessionId { get; set; }
+
+ ///
+ /// ISO 8601 timestamp indicating when the session was created.
+ ///
+ [JsonProperty("created_at")]
+ public string? CreatedAt { get; set; }
+
+ ///
+ /// ISO 8601 timestamp indicating when the session expires.
+ ///
+ [JsonProperty("expires_at")]
+ public string? ExpiresAt { get; set; }
+
+ #endregion
+ }
+}
diff --git a/EasyPost/Parameters/CustomerPortal/CreateAccountLink.cs b/EasyPost/Parameters/CustomerPortal/CreateAccountLink.cs
new file mode 100644
index 00000000..d11e1483
--- /dev/null
+++ b/EasyPost/Parameters/CustomerPortal/CreateAccountLink.cs
@@ -0,0 +1,49 @@
+using System.Diagnostics.CodeAnalysis;
+using EasyPost.Models.API;
+using EasyPost.Utilities.Internal.Attributes;
+
+namespace EasyPost.Parameters.Claim
+{
+ ///
+ /// Parameters for API calls.
+ ///
+ [ExcludeFromCodeCoverage]
+ public class CreateAccountLink : BaseParameters
+ {
+ #region Request Parameters
+
+ ///
+ /// Type of Customer Portal session.
+ ///
+ [TopLevelRequestParameter(Necessity.Required, "session_type")]
+ public string? SessionType { get; set; }
+
+ ///
+ /// The User ID of the sub account for which the portal session is being created.
+ ///
+ [TopLevelRequestParameter(Necessity.Required, "user_id")]
+ public string? UserId { get; set; }
+
+ ///
+ /// The URL to which the sub account will be redirected if the session URL is expired, reused, or otherwise invalid.
+ /// This should trigger a new session request.
+ ///
+ [TopLevelRequestParameter(Necessity.Required, "refresh_url")]
+ public string? RefreshUrl { get; set; }
+
+ ///
+ /// The URL to which the sub account will be redirected after exiting the Customer Portal session.
+ /// This does not confirm completion of the flow; webhook or API polling is recommended for confirmation.
+ ///
+ [TopLevelRequestParameter(Necessity.Required, "return_url")]
+ public string? ReturnUrl { get; set; }
+
+ ///
+ /// Used to configure the Customer Portal session.
+ ///
+ [TopLevelRequestParameter(Necessity.Optional, "metadata")]
+ public Dictionary? Metadata { get; set; }
+
+ #endregion
+ }
+}
diff --git a/EasyPost/Parameters/Embeddable/CreateSession.cs b/EasyPost/Parameters/Embeddable/CreateSession.cs
new file mode 100644
index 00000000..70b786d1
--- /dev/null
+++ b/EasyPost/Parameters/Embeddable/CreateSession.cs
@@ -0,0 +1 @@
+// TODO
diff --git a/EasyPost/Services/CustomerPortalService.cs b/EasyPost/Services/CustomerPortalService.cs
new file mode 100644
index 00000000..be090d7a
--- /dev/null
+++ b/EasyPost/Services/CustomerPortalService.cs
@@ -0,0 +1,39 @@
+using System.Threading;
+using System.Threading.Tasks;
+using EasyPost._base;
+using EasyPost.Exceptions.General;
+using EasyPost.Http;
+using EasyPost.Models.API;
+using EasyPost.Utilities.Internal.Attributes;
+
+namespace EasyPost.Services
+{
+ ///
+ /// Class representing a set of CustomerPortal-related functionality.
+ ///
+ // ReSharper disable once ClassNeverInstantiated.Global
+ public class CustomerPortalService : EasyPostService
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The to tie to this service and use for API calls.
+ internal CustomerPortalService(EasyPostClient client)
+ : base(client)
+ {
+ }
+
+ #region CRUD Operations
+
+ ///
+ /// Create a Portal Session.
+ ///
+ /// Data to use to create the Portal Session.
+ /// to use for the HTTP request.
+ /// A object.
+ [CrudOperations.Create]
+ public async Task CreateAccountLink(Parameters.CustomerPortal.CreateAccountLink parameters, CancellationToken cancellationToken = default) => await RequestAsync(Method.Post, "customer_portal/account_link", cancellationToken, parameters.ToDictionary());
+
+ #endregion
+ }
+}
diff --git a/EasyPost/Services/EmbeddableService.cs b/EasyPost/Services/EmbeddableService.cs
new file mode 100644
index 00000000..70b786d1
--- /dev/null
+++ b/EasyPost/Services/EmbeddableService.cs
@@ -0,0 +1 @@
+// TODO
From 80c5f5a0b935c331fa9638335bcbdfb21221089d Mon Sep 17 00:00:00 2001
From: Justintime50 <39606064+Justintime50@users.noreply.github.com>
Date: Fri, 21 Nov 2025 11:58:56 -0700
Subject: [PATCH 2/2] feat: session services and tests
---
EasyPost.Integration/TestUtils.cs | 4 +-
.../CustomerPortalServiceTest.cs | 51 ++++++++++
.../WithParameters/EmbeddableServiceTest.cs | 49 ++++++++++
EasyPost.Tests/TestUtils.cs | 4 +-
.../create_account_link.json | 97 +++++++++++++++++++
.../create_session.json | 97 +++++++++++++++++++
EasyPost/Client.cs | 10 ++
.../Models/API/CustomerPortalAccountLink.cs | 6 --
EasyPost/Models/API/EmbeddablesSession.cs | 6 --
.../CustomerPortal/CreateAccountLink.cs | 4 +-
.../Parameters/Embeddable/CreateSession.cs | 29 +++++-
EasyPost/Services/CustomerPortalService.cs | 1 -
EasyPost/Services/EmbeddableService.cs | 39 +++++++-
13 files changed, 374 insertions(+), 23 deletions(-)
create mode 100644 EasyPost.Tests/ServicesTests/WithParameters/CustomerPortalServiceTest.cs
create mode 100644 EasyPost.Tests/ServicesTests/WithParameters/EmbeddableServiceTest.cs
create mode 100644 EasyPost.Tests/cassettes/net/customer_portal_service_with_parameters/create_account_link.json
create mode 100644 EasyPost.Tests/cassettes/net/embeddable_service_with_parameters/create_session.json
diff --git a/EasyPost.Integration/TestUtils.cs b/EasyPost.Integration/TestUtils.cs
index 04e0c32f..ae1204d0 100644
--- a/EasyPost.Integration/TestUtils.cs
+++ b/EasyPost.Integration/TestUtils.cs
@@ -12,13 +12,11 @@ public class Utils
private static readonly List BodyCensors =
[
- "api_keys",
- "children",
"client_ip",
"credentials",
"email",
+ "fields",
"key",
- "keys",
"phone_number",
"phone",
"test_credentials"
diff --git a/EasyPost.Tests/ServicesTests/WithParameters/CustomerPortalServiceTest.cs b/EasyPost.Tests/ServicesTests/WithParameters/CustomerPortalServiceTest.cs
new file mode 100644
index 00000000..201e7800
--- /dev/null
+++ b/EasyPost.Tests/ServicesTests/WithParameters/CustomerPortalServiceTest.cs
@@ -0,0 +1,51 @@
+using System;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using EasyPost.Models.API;
+using EasyPost.Parameters.CustomerPortal;
+using EasyPost.Parameters.User;
+using EasyPost.Tests._Utilities;
+using EasyPost.Tests._Utilities.Attributes;
+using EasyPost.Utilities.Internal.Attributes;
+using Xunit;
+
+namespace EasyPost.Tests.ServicesTests.WithParameters
+{
+ public class CustomerPortalServiceTests : UnitTest
+ {
+ public CustomerPortalServiceTests() : base("customer_portal_service_with_parameters", TestUtils.ApiKey.Production)
+ {
+ }
+
+ #region Tests
+
+ #region Test CRUD Operations
+
+ [Fact]
+ [CrudOperations.Read]
+ [Testing.Function]
+ public async Task TestCreateAccountLink()
+ {
+ UseVCR("create_account_link");
+
+ Dictionary fixture = new Dictionary { { "page_size", Fixtures.PageSize } };
+ AllChildren childrenParameters = Fixtures.Parameters.Users.AllChildren(fixture);
+ ChildUserCollection childUserCollection = await Client.User.AllChildren(childrenParameters);
+
+ Parameters.CustomerPortal.CreateAccountLink parameters = new()
+ {
+ SessionType = "account_onboarding",
+ UserId = childUserCollection.Children[0].Id,
+ RefreshUrl = "https://example.com/refresh",
+ ReturnUrl = "https://example.com/return",
+ };
+ CustomerPortalAccountLink accountLink = await Client.CustomerPortal.CreateAccountLink(parameters);
+
+ Assert.IsType(accountLink);
+ }
+
+ #endregion
+
+ #endregion
+ }
+}
diff --git a/EasyPost.Tests/ServicesTests/WithParameters/EmbeddableServiceTest.cs b/EasyPost.Tests/ServicesTests/WithParameters/EmbeddableServiceTest.cs
new file mode 100644
index 00000000..18258c35
--- /dev/null
+++ b/EasyPost.Tests/ServicesTests/WithParameters/EmbeddableServiceTest.cs
@@ -0,0 +1,49 @@
+using System;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using EasyPost.Models.API;
+using EasyPost.Parameters.Embeddable;
+using EasyPost.Parameters.User;
+using EasyPost.Tests._Utilities;
+using EasyPost.Tests._Utilities.Attributes;
+using EasyPost.Utilities.Internal.Attributes;
+using Xunit;
+
+namespace EasyPost.Tests.ServicesTests.WithParameters
+{
+ public class EmbeddableServiceTests : UnitTest
+ {
+ public EmbeddableServiceTests() : base("embeddable_service_with_parameters", TestUtils.ApiKey.Production)
+ {
+ }
+
+ #region Tests
+
+ #region Test CRUD Operations
+
+ [Fact]
+ [CrudOperations.Read]
+ [Testing.Function]
+ public async Task TestCreateSession()
+ {
+ UseVCR("create_session");
+
+ Dictionary fixture = new Dictionary { { "page_size", Fixtures.PageSize } };
+ AllChildren childrenParameters = Fixtures.Parameters.Users.AllChildren(fixture);
+ ChildUserCollection childUserCollection = await Client.User.AllChildren(childrenParameters);
+
+ Parameters.Embeddable.CreateSession parameters = new()
+ {
+ OriginHost = "https://example.com",
+ UserId = childUserCollection.Children[0].Id,
+ };
+ EmbeddablesSession session = await Client.Embeddable.CreateSession(parameters);
+
+ Assert.IsType(session);
+ }
+
+ #endregion
+
+ #endregion
+ }
+}
diff --git a/EasyPost.Tests/TestUtils.cs b/EasyPost.Tests/TestUtils.cs
index dfef3eb6..32320752 100644
--- a/EasyPost.Tests/TestUtils.cs
+++ b/EasyPost.Tests/TestUtils.cs
@@ -23,13 +23,11 @@ public class TestUtils
private static readonly List BodyCensors =
[
- "api_keys",
- "children",
"client_ip",
"credentials",
"email",
+ "fields",
"key",
- "keys",
"phone_number",
"phone",
"test_credentials"
diff --git a/EasyPost.Tests/cassettes/net/customer_portal_service_with_parameters/create_account_link.json b/EasyPost.Tests/cassettes/net/customer_portal_service_with_parameters/create_account_link.json
new file mode 100644
index 00000000..87a51ec9
--- /dev/null
+++ b/EasyPost.Tests/cassettes/net/customer_portal_service_with_parameters/create_account_link.json
@@ -0,0 +1,97 @@
+[
+ {
+ "Duration": 355,
+ "RecordedAt": "2025-11-21T11:57:16.671831-07:00",
+ "Request": {
+ "Body": "",
+ "BodyContentType": "Text",
+ "ContentHeaders": {},
+ "Method": "GET",
+ "RequestHeaders": {
+ "Authorization": "",
+ "User-Agent": ""
+ },
+ "Uri": "https://api.easypost.com/v2/users/children?page_size=5"
+ },
+ "Response": {
+ "Body": "{\"children\":[{\"id\":\"user_4233cc5e2dd543a6bf5397e9594ecb68\",\"object\":\"User\",\"parent_id\":\"user_4d78588f2f744bf6886aa67ddb870865\",\"name\":\"Child User\",\"phone_number\":\"\",\"verified\":true,\"created_at\":\"2024-02-19T07:59:59Z\"},{\"id\":\"user_8796f6de77154885ab5044feb9c03f81\",\"object\":\"User\",\"parent_id\":\"user_4d78588f2f744bf6886aa67ddb870865\",\"name\":\"Child User\",\"phone_number\":\"\",\"verified\":true,\"created_at\":\"2024-02-19T08:00:00Z\"},{\"id\":\"user_844e0c84bd5b47e59bdb46eccb0f45f3\",\"object\":\"User\",\"parent_id\":\"user_4d78588f2f744bf6886aa67ddb870865\",\"name\":\"Child User\",\"phone_number\":\"\",\"verified\":true,\"created_at\":\"2024-02-19T08:11:29Z\"},{\"id\":\"user_db23a582d10547c7ab84212304407a5e\",\"object\":\"User\",\"parent_id\":\"user_4d78588f2f744bf6886aa67ddb870865\",\"name\":\"Test User\",\"phone_number\":\"\",\"verified\":true,\"created_at\":\"2025-11-21T18:30:36Z\"}],\"has_more\":false}",
+ "BodyContentType": "Json",
+ "ContentHeaders": {
+ "Expires": "0",
+ "Content-Type": "application/json; charset=utf-8",
+ "Content-Length": "890"
+ },
+ "HttpVersion": "1.1",
+ "ResponseHeaders": {
+ "X-Frame-Options": "SAMEORIGIN",
+ "X-XSS-Protection": "1; mode=block",
+ "X-Content-Type-Options": "nosniff",
+ "x-download-options": "noopen",
+ "x-permitted-cross-domain-policies": "none",
+ "Referrer-Policy": "strict-origin-when-cross-origin",
+ "x-ep-request-uuid": "12829f636920b60ce2b7d23300c47da7",
+ "Cache-Control": "no-store, no-cache, private",
+ "Pragma": "no-cache",
+ "x-runtime": "0.114642",
+ "x-node": "bigweb42nuq",
+ "x-version-label": "easypost-202511211422-7701450e91-master",
+ "x-backend": "easypost",
+ "x-proxied": "intlb3nuq c0061e0a2e,extlb2nuq cbbd141214",
+ "Strict-Transport-Security": "max-age=31536000; includeSubDomains; preload"
+ },
+ "Status": {
+ "Code": 200,
+ "Message": "OK"
+ }
+ }
+ },
+ {
+ "Duration": 161,
+ "RecordedAt": "2025-11-21T11:57:16.839838-07:00",
+ "Request": {
+ "Body": "{\"session_type\":\"account_onboarding\",\"user_id\":\"user_4233cc5e2dd543a6bf5397e9594ecb68\",\"refresh_url\":\"https://example.com/refresh\",\"return_url\":\"https://example.com/return\"}",
+ "BodyContentType": "Json",
+ "ContentHeaders": {
+ "Content-Type": "application/json; charset=utf-8",
+ "Content-Length": "173"
+ },
+ "Method": "POST",
+ "RequestHeaders": {
+ "Authorization": "",
+ "User-Agent": ""
+ },
+ "Uri": "https://api.easypost.com/v2/customer_portal/account_link"
+ },
+ "Response": {
+ "Body": "{\"link\":\"https://app.easypost.com/customer-portal/onboarding?session_id=bkHWIz8zP1OY7zPM\",\"object\":\"CustomerPortalAccountLink\",\"expires_at\":\"2025-11-21T19:02:16Z\",\"created_at\":\"2025-11-21T18:57:16Z\"}",
+ "BodyContentType": "Json",
+ "ContentHeaders": {
+ "Expires": "0",
+ "Content-Type": "application/json; charset=utf-8",
+ "Content-Length": "199"
+ },
+ "HttpVersion": "1.1",
+ "ResponseHeaders": {
+ "X-Frame-Options": "SAMEORIGIN",
+ "X-XSS-Protection": "1; mode=block",
+ "X-Content-Type-Options": "nosniff",
+ "x-download-options": "noopen",
+ "x-permitted-cross-domain-policies": "none",
+ "Referrer-Policy": "strict-origin-when-cross-origin",
+ "x-ep-request-uuid": "12829f636920b60ce2b7d23300c47de2",
+ "Cache-Control": "no-store, no-cache, private",
+ "Pragma": "no-cache",
+ "x-runtime": "0.124963",
+ "x-node": "bigweb64nuq",
+ "x-version-label": "easypost-202511211422-7701450e91-master",
+ "x-backend": "easypost",
+ "x-proxied": "intlb3nuq c0061e0a2e,extlb2nuq cbbd141214",
+ "Strict-Transport-Security": "max-age=31536000; includeSubDomains; preload"
+ },
+ "Status": {
+ "Code": 201,
+ "Message": "Created"
+ }
+ }
+ }
+]
diff --git a/EasyPost.Tests/cassettes/net/embeddable_service_with_parameters/create_session.json b/EasyPost.Tests/cassettes/net/embeddable_service_with_parameters/create_session.json
new file mode 100644
index 00000000..b7ac1565
--- /dev/null
+++ b/EasyPost.Tests/cassettes/net/embeddable_service_with_parameters/create_session.json
@@ -0,0 +1,97 @@
+[
+ {
+ "Duration": 401,
+ "RecordedAt": "2025-11-21T11:55:40.425-07:00",
+ "Request": {
+ "Body": "",
+ "BodyContentType": "Text",
+ "ContentHeaders": {},
+ "Method": "GET",
+ "RequestHeaders": {
+ "Authorization": "",
+ "User-Agent": ""
+ },
+ "Uri": "https://api.easypost.com/v2/users/children?page_size=5"
+ },
+ "Response": {
+ "Body": "{\"children\":[{\"id\":\"user_4233cc5e2dd543a6bf5397e9594ecb68\",\"object\":\"User\",\"parent_id\":\"user_4d78588f2f744bf6886aa67ddb870865\",\"name\":\"Child User\",\"phone_number\":\"\",\"verified\":true,\"created_at\":\"2024-02-19T07:59:59Z\"},{\"id\":\"user_8796f6de77154885ab5044feb9c03f81\",\"object\":\"User\",\"parent_id\":\"user_4d78588f2f744bf6886aa67ddb870865\",\"name\":\"Child User\",\"phone_number\":\"\",\"verified\":true,\"created_at\":\"2024-02-19T08:00:00Z\"},{\"id\":\"user_844e0c84bd5b47e59bdb46eccb0f45f3\",\"object\":\"User\",\"parent_id\":\"user_4d78588f2f744bf6886aa67ddb870865\",\"name\":\"Child User\",\"phone_number\":\"\",\"verified\":true,\"created_at\":\"2024-02-19T08:11:29Z\"},{\"id\":\"user_db23a582d10547c7ab84212304407a5e\",\"object\":\"User\",\"parent_id\":\"user_4d78588f2f744bf6886aa67ddb870865\",\"name\":\"Test User\",\"phone_number\":\"\",\"verified\":true,\"created_at\":\"2025-11-21T18:30:36Z\"}],\"has_more\":false}",
+ "BodyContentType": "Json",
+ "ContentHeaders": {
+ "Expires": "0",
+ "Content-Type": "application/json; charset=utf-8",
+ "Content-Length": "890"
+ },
+ "HttpVersion": "1.1",
+ "ResponseHeaders": {
+ "X-Frame-Options": "SAMEORIGIN",
+ "X-XSS-Protection": "1; mode=block",
+ "X-Content-Type-Options": "nosniff",
+ "x-download-options": "noopen",
+ "x-permitted-cross-domain-policies": "none",
+ "Referrer-Policy": "strict-origin-when-cross-origin",
+ "x-ep-request-uuid": "40a2aa286920b5ace2b7d210040dd7d1",
+ "Cache-Control": "no-store, no-cache, private",
+ "Pragma": "no-cache",
+ "x-runtime": "0.082476",
+ "x-node": "bigweb65nuq",
+ "x-version-label": "easypost-202511211422-7701450e91-master",
+ "x-backend": "easypost",
+ "x-proxied": "intlb6nuq c0061e0a2e,extlb1nuq cbbd141214",
+ "Strict-Transport-Security": "max-age=31536000; includeSubDomains; preload"
+ },
+ "Status": {
+ "Code": 200,
+ "Message": "OK"
+ }
+ }
+ },
+ {
+ "Duration": 219,
+ "RecordedAt": "2025-11-21T11:55:40.651018-07:00",
+ "Request": {
+ "Body": "{\"origin_host\":\"https://example.com\",\"user_id\":\"user_4233cc5e2dd543a6bf5397e9594ecb68\"}",
+ "BodyContentType": "Json",
+ "ContentHeaders": {
+ "Content-Type": "application/json; charset=utf-8",
+ "Content-Length": "87"
+ },
+ "Method": "POST",
+ "RequestHeaders": {
+ "Authorization": "",
+ "User-Agent": ""
+ },
+ "Uri": "https://api.easypost.com/v2/embeddables/session"
+ },
+ "Response": {
+ "Body": "{\"object\":\"EmbeddablesSession\",\"session_id\":\"CX4nUufTfiWiqgn1\",\"expires_at\":\"2025-11-21T19:10:40Z\",\"created_at\":\"2025-11-21T18:55:40Z\"}",
+ "BodyContentType": "Json",
+ "ContentHeaders": {
+ "Expires": "0",
+ "Content-Type": "application/json; charset=utf-8",
+ "Content-Length": "135"
+ },
+ "HttpVersion": "1.1",
+ "ResponseHeaders": {
+ "X-Frame-Options": "SAMEORIGIN",
+ "X-XSS-Protection": "1; mode=block",
+ "X-Content-Type-Options": "nosniff",
+ "x-download-options": "noopen",
+ "x-permitted-cross-domain-policies": "none",
+ "Referrer-Policy": "strict-origin-when-cross-origin",
+ "x-ep-request-uuid": "40a2aa286920b5ace2b7d210040dd801",
+ "Cache-Control": "no-store, no-cache, private",
+ "Pragma": "no-cache",
+ "x-runtime": "0.182859",
+ "x-node": "bigweb58nuq",
+ "x-version-label": "easypost-202511211422-7701450e91-master",
+ "x-backend": "easypost",
+ "x-proxied": "intlb6nuq c0061e0a2e,extlb1nuq cbbd141214",
+ "Strict-Transport-Security": "max-age=31536000; includeSubDomains; preload"
+ },
+ "Status": {
+ "Code": 201,
+ "Message": "Created"
+ }
+ }
+ }
+]
diff --git a/EasyPost/Client.cs b/EasyPost/Client.cs
index a6c1a83e..449532a4 100644
--- a/EasyPost/Client.cs
+++ b/EasyPost/Client.cs
@@ -53,6 +53,11 @@ public class Client : EasyPostClient
///
public ClaimService Claim => new ClaimService(this);
+ ///
+ /// Access CustomerPortal-related functionality.
+ ///
+ public CustomerPortalService CustomerPortal => new CustomerPortalService(this);
+
///
/// Access Customs Info-related functionality.
///
@@ -63,6 +68,11 @@ public class Client : EasyPostClient
///
public CustomsItemService CustomsItem => new CustomsItemService(this);
+ ///
+ /// Access Embeddable-related functionality.
+ ///
+ public EmbeddableService Embeddable => new EmbeddableService(this);
+
///
/// Access EndShipper-related functionality.
///
diff --git a/EasyPost/Models/API/CustomerPortalAccountLink.cs b/EasyPost/Models/API/CustomerPortalAccountLink.cs
index 7eff0032..adbf87d8 100644
--- a/EasyPost/Models/API/CustomerPortalAccountLink.cs
+++ b/EasyPost/Models/API/CustomerPortalAccountLink.cs
@@ -10,12 +10,6 @@ public class CustomerPortalAccountLink : EphemeralEasyPostObject
{
#region JSON Properties
- ///
- /// Always returns "CustomerPortalAccountLink".
- ///
- [JsonProperty("object")]
- public string? Object { get; set; }
-
///
/// One-time-use session URL for initiating the Customer Portal.
///
diff --git a/EasyPost/Models/API/EmbeddablesSession.cs b/EasyPost/Models/API/EmbeddablesSession.cs
index 51dc88ee..3eb4f652 100644
--- a/EasyPost/Models/API/EmbeddablesSession.cs
+++ b/EasyPost/Models/API/EmbeddablesSession.cs
@@ -10,12 +10,6 @@ public class EmbeddablesSession : EphemeralEasyPostObject
{
#region JSON Properties
- ///
- /// Always returns "EmbeddablesSession".
- ///
- [JsonProperty("object")]
- public string? Object { get; set; }
-
///
/// Short-lived, one-time-use token that authorizes an Embeddables Components session.
/// Must be provided to the client-side Embeddables script to initialize the component.
diff --git a/EasyPost/Parameters/CustomerPortal/CreateAccountLink.cs b/EasyPost/Parameters/CustomerPortal/CreateAccountLink.cs
index d11e1483..d5ee07ad 100644
--- a/EasyPost/Parameters/CustomerPortal/CreateAccountLink.cs
+++ b/EasyPost/Parameters/CustomerPortal/CreateAccountLink.cs
@@ -1,8 +1,8 @@
+using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
-using EasyPost.Models.API;
using EasyPost.Utilities.Internal.Attributes;
-namespace EasyPost.Parameters.Claim
+namespace EasyPost.Parameters.CustomerPortal
{
///
/// Parameters for API calls.
diff --git a/EasyPost/Parameters/Embeddable/CreateSession.cs b/EasyPost/Parameters/Embeddable/CreateSession.cs
index 70b786d1..32ca0ca7 100644
--- a/EasyPost/Parameters/Embeddable/CreateSession.cs
+++ b/EasyPost/Parameters/Embeddable/CreateSession.cs
@@ -1 +1,28 @@
-// TODO
+using System.Diagnostics.CodeAnalysis;
+using EasyPost.Utilities.Internal.Attributes;
+
+namespace EasyPost.Parameters.Embeddable
+{
+ ///
+ /// Parameters for API calls.
+ ///
+ [ExcludeFromCodeCoverage]
+ public class CreateSession : BaseParameters
+ {
+ #region Request Parameters
+
+ ///
+ /// The integrator’s domain in bare-host format (e.g., example.com), excluding protocol and subdomains.
+ ///
+ [TopLevelRequestParameter(Necessity.Required, "origin_host")]
+ public string? OriginHost { get; set; }
+
+ ///
+ /// The User ID of the sub account for which the embeddable session is being created.
+ ///
+ [TopLevelRequestParameter(Necessity.Required, "user_id")]
+ public string? UserId { get; set; }
+
+ #endregion
+ }
+}
diff --git a/EasyPost/Services/CustomerPortalService.cs b/EasyPost/Services/CustomerPortalService.cs
index be090d7a..a25042a4 100644
--- a/EasyPost/Services/CustomerPortalService.cs
+++ b/EasyPost/Services/CustomerPortalService.cs
@@ -1,7 +1,6 @@
using System.Threading;
using System.Threading.Tasks;
using EasyPost._base;
-using EasyPost.Exceptions.General;
using EasyPost.Http;
using EasyPost.Models.API;
using EasyPost.Utilities.Internal.Attributes;
diff --git a/EasyPost/Services/EmbeddableService.cs b/EasyPost/Services/EmbeddableService.cs
index 70b786d1..119819d4 100644
--- a/EasyPost/Services/EmbeddableService.cs
+++ b/EasyPost/Services/EmbeddableService.cs
@@ -1 +1,38 @@
-// TODO
+using System.Threading;
+using System.Threading.Tasks;
+using EasyPost._base;
+using EasyPost.Http;
+using EasyPost.Models.API;
+using EasyPost.Utilities.Internal.Attributes;
+
+namespace EasyPost.Services
+{
+ ///
+ /// Class representing a set of Embeddable-related functionality.
+ ///
+ // ReSharper disable once ClassNeverInstantiated.Global
+ public class EmbeddableService : EasyPostService
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The to tie to this service and use for API calls.
+ internal EmbeddableService(EasyPostClient client)
+ : base(client)
+ {
+ }
+
+ #region CRUD Operations
+
+ ///
+ /// Create an Embeddables Session.
+ ///
+ /// Data to use to create the Embeddables Session.
+ /// to use for the HTTP request.
+ /// A object.
+ [CrudOperations.Create]
+ public async Task CreateSession(Parameters.Embeddable.CreateSession parameters, CancellationToken cancellationToken = default) => await RequestAsync(Method.Post, "embeddables/session", cancellationToken, parameters.ToDictionary());
+
+ #endregion
+ }
+}