From f8002ec7576df8815941e21ec3ab2fc137c87d1a Mon Sep 17 00:00:00 2001 From: Justintime50 <39606064+Justintime50@users.noreply.github.com> Date: Tue, 18 Nov 2025 12:23:49 -0700 Subject: [PATCH] feat: customer portal and embeddable sessions --- CHANGELOG.md | 6 + .../model/CustomerPortalAccountLink.java | 12 ++ .../easypost/model/EmbeddablesSession.java | 12 ++ .../service/CustomerPortalService.java | 34 ++++ .../com/easypost/service/EasyPostClient.java | 93 ++++----- .../easypost/service/EmbeddableService.java | 34 ++++ .../customer_portal/create_account_link.json | 177 +++++++++++++++++ .../cassettes/embeddable/create_session.json | 180 ++++++++++++++++++ .../java/com/easypost/CustomerPortalTest.java | 48 +++++ .../java/com/easypost/EmbeddableTest.java | 46 +++++ 10 files changed, 582 insertions(+), 60 deletions(-) create mode 100644 src/main/java/com/easypost/model/CustomerPortalAccountLink.java create mode 100644 src/main/java/com/easypost/model/EmbeddablesSession.java create mode 100644 src/main/java/com/easypost/service/CustomerPortalService.java create mode 100644 src/main/java/com/easypost/service/EmbeddableService.java create mode 100644 src/test/cassettes/customer_portal/create_account_link.json create mode 100644 src/test/cassettes/embeddable/create_session.json create mode 100644 src/test/java/com/easypost/CustomerPortalTest.java create mode 100644 src/test/java/com/easypost/EmbeddableTest.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 2b032a15b..503a5236d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # CHANGELOG +## Next Release + +- Adds the following functions: + - `embeddable.createSession` + - `customerPortal.createAccountLink` + ## v8.3.0 (2025-11-10) - Adds support for `UspsShipAccount` diff --git a/src/main/java/com/easypost/model/CustomerPortalAccountLink.java b/src/main/java/com/easypost/model/CustomerPortalAccountLink.java new file mode 100644 index 000000000..73687d126 --- /dev/null +++ b/src/main/java/com/easypost/model/CustomerPortalAccountLink.java @@ -0,0 +1,12 @@ +package com.easypost.model; + +import java.util.Date; +import lombok.Getter; + +@Getter +public class CustomerPortalAccountLink { + private String object; + private String link; + private Date createdAt; + private Date expiresAt; +} diff --git a/src/main/java/com/easypost/model/EmbeddablesSession.java b/src/main/java/com/easypost/model/EmbeddablesSession.java new file mode 100644 index 000000000..40f77fc2d --- /dev/null +++ b/src/main/java/com/easypost/model/EmbeddablesSession.java @@ -0,0 +1,12 @@ +package com.easypost.model; + +import java.util.Date; +import lombok.Getter; + +@Getter +public class EmbeddablesSession { + private String object; + private String sessionId; + private Date createdAt; + private Date expiresAt; +} diff --git a/src/main/java/com/easypost/service/CustomerPortalService.java b/src/main/java/com/easypost/service/CustomerPortalService.java new file mode 100644 index 000000000..b5b5488a6 --- /dev/null +++ b/src/main/java/com/easypost/service/CustomerPortalService.java @@ -0,0 +1,34 @@ +package com.easypost.service; + +import java.util.Map; + +import com.easypost.exception.EasyPostException; +import com.easypost.http.Requestor; +import com.easypost.http.Requestor.RequestMethod; +import com.easypost.model.CustomerPortalAccountLink; + +public class CustomerPortalService { + private final EasyPostClient client; + + /** + * CustomerPortalService constructor. + * + * @param client The client object. + */ + CustomerPortalService(EasyPostClient client) { + this.client = client; + } + + /** + * Create a CustomerPortalAccountLink from the API. + * + * @param params Map of parameters. + * @return CustomerPortalAccountLink object + * @throws EasyPostException when the request fails. + */ + public CustomerPortalAccountLink createAccountLink(final Map params) throws EasyPostException { + String endpoint = "customer_portal/account_link"; + + return Requestor.request(RequestMethod.POST, endpoint, params, CustomerPortalAccountLink.class, client); + } +} diff --git a/src/main/java/com/easypost/service/EasyPostClient.java b/src/main/java/com/easypost/service/EasyPostClient.java index 1a7fca48a..6ca779057 100644 --- a/src/main/java/com/easypost/service/EasyPostClient.java +++ b/src/main/java/com/easypost/service/EasyPostClient.java @@ -17,36 +17,39 @@ public class EasyPostClient { private final String clientApiKey; // API key for all EasyPost API requests private final String apiVersion = "v2"; private final String apiBase; - public final AddressService address; - public final ApiKeyService apiKey; - public final BatchService batch; - public final BetaReferralCustomerService betaReferralCustomer; - public final BetaRateService betaRate; - public final BillingService billing; - public final CarrierAccountService carrierAccount; - public final CarrierMetadataService carrierMetadata; - public final CarrierTypeService carrierType; - public final ClaimService claim; - public final CustomsInfoService customsInfo; - public final CustomsItemService customsItem; - public final EndShipperService endShipper; - public final EventService event; - public final InsuranceService insurance; - public final LumaService luma; - public final OrderService order; - public final ParcelService parcel; - public final PaymentMethodService paymentMethod; - public final PickupService pickup; - public final RateService rate; - public final ReferralCustomerService referralCustomer; - public final RefundService refund; - public final ReportService report; - public final ScanformService scanForm; - public final ShipmentService shipment; - public final SmartRateService smartRate; - public final TrackerService tracker; - public final UserService user; - public final WebhookService webhook; + // Services + public final AddressService address = new AddressService(this); + public final ApiKeyService apiKey = new ApiKeyService(this); + public final BatchService batch = new BatchService(this); + public final BetaRateService betaRate = new BetaRateService(this); + public final BetaReferralCustomerService betaReferralCustomer = new BetaReferralCustomerService(this); + public final BillingService billing = new BillingService(this); + public final CarrierAccountService carrierAccount = new CarrierAccountService(this); + public final CarrierMetadataService carrierMetadata = new CarrierMetadataService(this); + public final CarrierTypeService carrierType = new CarrierTypeService(this); + public final ClaimService claim = new ClaimService(this); + public final CustomerPortalService customerPortal = new CustomerPortalService(this); + public final CustomsInfoService customsInfo = new CustomsInfoService(this); + public final CustomsItemService customsItem = new CustomsItemService(this); + public final EmbeddableService embeddable = new EmbeddableService(this); + public final EndShipperService endShipper = new EndShipperService(this); + public final EventService event = new EventService(this); + public final InsuranceService insurance = new InsuranceService(this); + public final LumaService luma = new LumaService(this); + public final OrderService order = new OrderService(this); + public final ParcelService parcel = new ParcelService(this); + public final PaymentMethodService paymentMethod = new PaymentMethodService(this); + public final PickupService pickup = new PickupService(this); + public final RateService rate = new RateService(this); + public final ReferralCustomerService referralCustomer = new ReferralCustomerService(this); + public final RefundService refund = new RefundService(this); + public final ReportService report = new ReportService(this); + public final ScanformService scanForm = new ScanformService(this); + public final ShipmentService shipment = new ShipmentService(this); + public final SmartRateService smartRate = new SmartRateService(this); + public final TrackerService tracker = new TrackerService(this); + public final UserService user = new UserService(this); + public final WebhookService webhook = new WebhookService(this); @Getter private RequestHook requestHooks = new RequestHook(); @Getter @@ -129,36 +132,6 @@ public EasyPostClient(String apiKey, int connectTimeoutMilliseconds, int readTim this.clientApiKey = apiKey; this.connectTimeoutMilliseconds = connectTimeoutMilliseconds; this.readTimeoutMilliseconds = readTimeoutMilliseconds; - this.address = new AddressService(this); - this.apiKey = new ApiKeyService(this); - this.batch = new BatchService(this); - this.betaReferralCustomer = new BetaReferralCustomerService(this); - this.betaRate = new BetaRateService(this); - this.billing = new BillingService(this); - this.carrierAccount = new CarrierAccountService(this); - this.carrierMetadata = new CarrierMetadataService(this); - this.carrierType = new CarrierTypeService(this); - this.claim = new ClaimService(this); - this.customsInfo = new CustomsInfoService(this); - this.customsItem = new CustomsItemService(this); - this.endShipper = new EndShipperService(this); - this.event = new EventService(this); - this.insurance = new InsuranceService(this); - this.luma = new LumaService(this); - this.order = new OrderService(this); - this.parcel = new ParcelService(this); - this.paymentMethod = new PaymentMethodService(this); - this.pickup = new PickupService(this); - this.rate = new RateService(this); - this.referralCustomer = new ReferralCustomerService(this); - this.refund = new RefundService(this); - this.report = new ReportService(this); - this.scanForm = new ScanformService(this); - this.shipment = new ShipmentService(this); - this.smartRate = new SmartRateService(this); - this.tracker = new TrackerService(this); - this.user = new UserService(this); - this.webhook = new WebhookService(this); } /** diff --git a/src/main/java/com/easypost/service/EmbeddableService.java b/src/main/java/com/easypost/service/EmbeddableService.java new file mode 100644 index 000000000..af04f5b83 --- /dev/null +++ b/src/main/java/com/easypost/service/EmbeddableService.java @@ -0,0 +1,34 @@ +package com.easypost.service; + +import java.util.Map; + +import com.easypost.exception.EasyPostException; +import com.easypost.http.Requestor; +import com.easypost.http.Requestor.RequestMethod; +import com.easypost.model.EmbeddablesSession; + +public class EmbeddableService { + private final EasyPostClient client; + + /** + * EmbeddableService constructor. + * + * @param client The client object. + */ + EmbeddableService(EasyPostClient client) { + this.client = client; + } + + /** + * Create an EmbeddablesSession from the API. + * + * @param params Map of parameters. + * @return EmbeddablesSession object + * @throws EasyPostException when the request fails. + */ + public EmbeddablesSession createSession(final Map params) throws EasyPostException { + String endpoint = "embeddables/session"; + + return Requestor.request(RequestMethod.POST, endpoint, params, EmbeddablesSession.class, client); + } +} diff --git a/src/test/cassettes/customer_portal/create_account_link.json b/src/test/cassettes/customer_portal/create_account_link.json new file mode 100644 index 000000000..9faf3b805 --- /dev/null +++ b/src/test/cassettes/customer_portal/create_account_link.json @@ -0,0 +1,177 @@ +[ + { + "recordedAt": 1763493497, + "request": { + "body": "", + "method": "GET", + "headers": { + "Accept-Charset": [ + "UTF-8" + ], + "User-Agent": [ + "REDACTED" + ] + }, + "uri": "https://api.easypost.com/v2/users/children?%70%61%67%65%5F%73%69%7A%65\u003d%35" + }, + "response": { + "body": "{\n \"children\": [\n {\n \"parent_id\": \"user_04ad194774a54f6c97d1385715721091\",\n \"name\": \"test user\",\n \"verified\": true,\n \"created_at\": \"2023-12-07T17:46:08Z\",\n \"phone_number\": \"REDACTED\",\n \"id\": \"user_af930e9bd27a4445bc2741fac37850cc\",\n \"object\": \"User\"\n }\n ],\n \"has_more\": false\n}", + "httpVersion": null, + "headers": { + "null": [ + "HTTP/1.1 200 OK" + ], + "content-length": [ + "245" + ], + "expires": [ + "0" + ], + "x-node": [ + "bigweb33nuq" + ], + "x-frame-options": [ + "SAMEORIGIN" + ], + "x-download-options": [ + "noopen" + ], + "x-permitted-cross-domain-policies": [ + "none" + ], + "x-backend": [ + "easypost" + ], + "pragma": [ + "no-cache" + ], + "strict-transport-security": [ + "max-age\u003d31536000; includeSubDomains; preload" + ], + "x-xss-protection": [ + "1; mode\u003dblock" + ], + "x-content-type-options": [ + "nosniff" + ], + "x-ep-request-uuid": [ + "57503b0a691cc678e2b9fe92014348ca" + ], + "x-proxied": [ + "intlb3nuq c0061e0a2e", + "extlb1nuq cbbd141214" + ], + "referrer-policy": [ + "strict-origin-when-cross-origin" + ], + "x-runtime": [ + "0.086392" + ], + "content-type": [ + "application/json; charset\u003dutf-8" + ], + "x-version-label": [ + "easypost-202511181852-613eda4497-master" + ], + "cache-control": [ + "private, no-cache, no-store" + ] + }, + "status": { + "code": 200, + "message": "OK" + }, + "uri": "https://api.easypost.com/v2/users/children?%70%61%67%65%5F%73%69%7A%65\u003d%35" + }, + "duration": 198 + }, + { + "recordedAt": 1763493497, + "request": { + "body": "{\n \"user_id\": \"user_af930e9bd27a4445bc2741fac37850cc\",\n \"return_url\": \"https://example.com/return\",\n \"session_type\": \"account_onboarding\",\n \"refresh_url\": \"https://example.com/refresh\"\n}", + "method": "POST", + "headers": { + "Accept-Charset": [ + "UTF-8" + ], + "User-Agent": [ + "REDACTED" + ], + "Content-Type": [ + "application/json" + ] + }, + "uri": "https://api.easypost.com/v2/customer_portal/account_link" + }, + "response": { + "body": "{\n \"expires_at\": \"2025-11-18T19:23:17Z\",\n \"link\": \"https://app.easypost.com/customer-portal/onboarding?session_id\\u003dZL1UeM2clfGFTa1a\",\n \"created_at\": \"2025-11-18T19:18:17Z\",\n \"object\": \"CustomerPortalAccountLink\"\n}", + "httpVersion": null, + "headers": { + "null": [ + "HTTP/1.1 201 Created" + ], + "content-length": [ + "199" + ], + "expires": [ + "0" + ], + "x-node": [ + "bigweb56nuq" + ], + "x-frame-options": [ + "SAMEORIGIN" + ], + "x-download-options": [ + "noopen" + ], + "x-permitted-cross-domain-policies": [ + "none" + ], + "x-backend": [ + "easypost" + ], + "pragma": [ + "no-cache" + ], + "strict-transport-security": [ + "max-age\u003d31536000; includeSubDomains; preload" + ], + "x-xss-protection": [ + "1; mode\u003dblock" + ], + "x-content-type-options": [ + "nosniff" + ], + "x-ep-request-uuid": [ + "57503b0e691cc679e2b9fe940143492f" + ], + "x-proxied": [ + "intlb6nuq c0061e0a2e", + "extlb1nuq cbbd141214" + ], + "referrer-policy": [ + "strict-origin-when-cross-origin" + ], + "x-runtime": [ + "0.184415" + ], + "content-type": [ + "application/json; charset\u003dutf-8" + ], + "x-version-label": [ + "easypost-202511181852-613eda4497-master" + ], + "cache-control": [ + "private, no-cache, no-store" + ] + }, + "status": { + "code": 201, + "message": "Created" + }, + "uri": "https://api.easypost.com/v2/customer_portal/account_link" + }, + "duration": 297 + } +] \ No newline at end of file diff --git a/src/test/cassettes/embeddable/create_session.json b/src/test/cassettes/embeddable/create_session.json new file mode 100644 index 000000000..0f89ce844 --- /dev/null +++ b/src/test/cassettes/embeddable/create_session.json @@ -0,0 +1,180 @@ +[ + { + "recordedAt": 1763493703, + "request": { + "body": "", + "method": "GET", + "headers": { + "Accept-Charset": [ + "UTF-8" + ], + "User-Agent": [ + "REDACTED" + ] + }, + "uri": "https://api.easypost.com/v2/users/children?%70%61%67%65%5F%73%69%7A%65\u003d%35" + }, + "response": { + "body": "{\n \"children\": [\n {\n \"parent_id\": \"user_04ad194774a54f6c97d1385715721091\",\n \"name\": \"test user\",\n \"verified\": true,\n \"created_at\": \"2023-12-07T17:46:08Z\",\n \"phone_number\": \"REDACTED\",\n \"id\": \"user_af930e9bd27a4445bc2741fac37850cc\",\n \"object\": \"User\"\n }\n ],\n \"has_more\": false\n}", + "httpVersion": null, + "headers": { + "null": [ + "HTTP/1.1 200 OK" + ], + "content-length": [ + "245" + ], + "expires": [ + "0" + ], + "x-node": [ + "bigweb58nuq" + ], + "x-frame-options": [ + "SAMEORIGIN" + ], + "x-download-options": [ + "noopen" + ], + "x-permitted-cross-domain-policies": [ + "none" + ], + "x-backend": [ + "easypost" + ], + "pragma": [ + "no-cache" + ], + "strict-transport-security": [ + "max-age\u003d31536000; includeSubDomains; preload" + ], + "x-xss-protection": [ + "1; mode\u003dblock" + ], + "x-content-type-options": [ + "nosniff" + ], + "x-ep-request-uuid": [ + "57503b0f691cc747e2ba0b99014471ce" + ], + "x-proxied": [ + "intlb3nuq c0061e0a2e", + "extlb1nuq cbbd141214" + ], + "referrer-policy": [ + "strict-origin-when-cross-origin" + ], + "x-runtime": [ + "0.028557" + ], + "content-type": [ + "application/json; charset\u003dutf-8" + ], + "x-version-label": [ + "easypost-202511181852-613eda4497-master" + ], + "cache-control": [ + "private, no-cache, no-store" + ] + }, + "status": { + "code": 200, + "message": "OK" + }, + "uri": "https://api.easypost.com/v2/users/children?%70%61%67%65%5F%73%69%7A%65\u003d%35" + }, + "duration": 130 + }, + { + "recordedAt": 1763493704, + "request": { + "body": "{\n \"user_id\": \"user_af930e9bd27a4445bc2741fac37850cc\",\n \"origin_host\": \"https://example.com\"\n}", + "method": "POST", + "headers": { + "Accept-Charset": [ + "UTF-8" + ], + "User-Agent": [ + "REDACTED" + ], + "Content-Type": [ + "application/json" + ] + }, + "uri": "https://api.easypost.com/v2/embeddables/session" + }, + "response": { + "body": "{\n \"expires_at\": \"2025-11-18T19:36:44Z\",\n \"session_id\": \"MlFxfifK1l4UDmPr\",\n \"created_at\": \"2025-11-18T19:21:44Z\",\n \"object\": \"EmbeddablesSession\"\n}", + "httpVersion": null, + "headers": { + "null": [ + "HTTP/1.1 201 Created" + ], + "content-length": [ + "135" + ], + "expires": [ + "0" + ], + "x-node": [ + "bigweb32nuq" + ], + "x-frame-options": [ + "SAMEORIGIN" + ], + "x-download-options": [ + "noopen" + ], + "x-permitted-cross-domain-policies": [ + "none" + ], + "x-backend": [ + "easypost" + ], + "pragma": [ + "no-cache" + ], + "strict-transport-security": [ + "max-age\u003d31536000; includeSubDomains; preload" + ], + "x-canary": [ + "direct" + ], + "x-xss-protection": [ + "1; mode\u003dblock" + ], + "x-content-type-options": [ + "nosniff" + ], + "x-ep-request-uuid": [ + "57503b11691cc748e2ba0bb201447214" + ], + "x-proxied": [ + "intlb4nuq c0061e0a2e", + "extlb1nuq cbbd141214" + ], + "referrer-policy": [ + "strict-origin-when-cross-origin" + ], + "x-runtime": [ + "0.121527" + ], + "content-type": [ + "application/json; charset\u003dutf-8" + ], + "x-version-label": [ + "easypost-202511181852-613eda4497-master" + ], + "cache-control": [ + "private, no-cache, no-store" + ] + }, + "status": { + "code": 201, + "message": "Created" + }, + "uri": "https://api.easypost.com/v2/embeddables/session" + }, + "duration": 222 + } +] \ No newline at end of file diff --git a/src/test/java/com/easypost/CustomerPortalTest.java b/src/test/java/com/easypost/CustomerPortalTest.java new file mode 100644 index 000000000..259eff0bf --- /dev/null +++ b/src/test/java/com/easypost/CustomerPortalTest.java @@ -0,0 +1,48 @@ +package com.easypost; + +import com.easypost.exception.EasyPostException; +import com.easypost.model.ChildUserCollection; +import com.easypost.model.CustomerPortalAccountLink; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +import java.util.HashMap; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public final class CustomerPortalTest { + private static TestUtils.VCR vcr; + + /** + * Set up the testing environment for this file. + * + * @throws EasyPostException when the request fails. + */ + @BeforeAll + public static void setup() throws EasyPostException { + vcr = new TestUtils.VCR("customer_portal", TestUtils.ApiKey.PRODUCTION); + } + + /** + * Test creating a Portal Session. + * + * @throws EasyPostException when the request fails. + */ + @Test + public void testCreateAccountLink() throws EasyPostException { + vcr.setUpTest("create_account_link"); + + HashMap userParams = new HashMap<>(); + userParams.put("page_size", Fixtures.pageSize()); + ChildUserCollection children = vcr.client.user.allChildren(userParams); + + HashMap params = new HashMap<>(); + params.put("session_type", "account_onboarding"); + params.put("user_id", children.getChildren().get(0).getId()); + params.put("refresh_url", "https://example.com/refresh"); + params.put("return_url", "https://example.com/return"); + CustomerPortalAccountLink accountLink = vcr.client.customerPortal.createAccountLink(params); + + assertEquals("CustomerPortalAccountLink", accountLink.getObject()); + } +} diff --git a/src/test/java/com/easypost/EmbeddableTest.java b/src/test/java/com/easypost/EmbeddableTest.java new file mode 100644 index 000000000..8a6ed18a9 --- /dev/null +++ b/src/test/java/com/easypost/EmbeddableTest.java @@ -0,0 +1,46 @@ +package com.easypost; + +import com.easypost.exception.EasyPostException; +import com.easypost.model.ChildUserCollection; +import com.easypost.model.EmbeddablesSession; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +import java.util.HashMap; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public final class EmbeddableTest { + private static TestUtils.VCR vcr; + + /** + * Set up the testing environment for this file. + * + * @throws EasyPostException when the request fails. + */ + @BeforeAll + public static void setup() throws EasyPostException { + vcr = new TestUtils.VCR("embeddable", TestUtils.ApiKey.PRODUCTION); + } + + /** + * Test creating an Embeddables Session. + * + * @throws EasyPostException when the request fails. + */ + @Test + public void testCreateSession() throws EasyPostException { + vcr.setUpTest("create_session"); + + HashMap userParams = new HashMap<>(); + userParams.put("page_size", Fixtures.pageSize()); + ChildUserCollection children = vcr.client.user.allChildren(userParams); + + HashMap params = new HashMap<>(); + params.put("origin_host", "https://example.com"); + params.put("user_id", children.getChildren().get(0).getId()); + EmbeddablesSession session = vcr.client.embeddable.createSession(params); + + assertEquals("EmbeddablesSession", session.getObject()); + } +}