diff --git a/.gitattributes b/.gitattributes index f0bdf96..65e7544 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,4 +1,4 @@ * text=auto -tests/cassettes/* -diff -tests/cassettes/* linguist-generated +cassettes/* -diff +cassettes/* linguist-generated diff --git a/CHANGELOG.md b/CHANGELOG.md index 74bd583..d06aa6f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # CHANGELOG +## Next Release + +- Adds the following functions: + - `CreateCustomerPortalAccountLink` + - `CreateEmbeddablesSession` + ## v5.4.0 (2025-11-10) - Adds support for `UspsShipAccount` diff --git a/cassettes/TestCreateCustomerPortalAccountLink.yaml b/cassettes/TestCreateCustomerPortalAccountLink.yaml new file mode 100644 index 0000000..7ced7dc --- /dev/null +++ b/cassettes/TestCreateCustomerPortalAccountLink.yaml @@ -0,0 +1,112 @@ +--- +version: 1 +interactions: +- request: + body: "" + form: {} + headers: + Authorization: + - REDACTED + User-Agent: + - REDACTED + url: https://api.easypost.com/v2/users/children?page_size=5 + method: GET + response: + body: '{"children":[{"created_at":"2023-09-20T18:01:26Z","id":"user_5f0c48e7a66b42398740b0149b1bb24c","name":"Test + User","object":"User","parent_id":"user_a76997d126dd488f8ad22d52301300b0","phone_number":"REDACTED","verified":true},{"created_at":"2023-09-20T18:09:24Z","id":"user_97f56192c53d490aa7851087b88618a4","name":"Test + User","object":"User","parent_id":"user_a76997d126dd488f8ad22d52301300b0","phone_number":"REDACTED","verified":true},{"created_at":"2023-11-30T20:12:09Z","id":"user_3d8dac28f4ba42729036133637356d40","name":"Test + User","object":"User","parent_id":"user_a76997d126dd488f8ad22d52301300b0","phone_number":"REDACTED","verified":true},{"created_at":"2024-07-26T19:35:11Z","id":"user_f81b29477fec4243a7de2ecc3c4f4907","name":"Test + User","object":"User","parent_id":"user_a76997d126dd488f8ad22d52301300b0","phone_number":"REDACTED","verified":true},{"created_at":"2024-07-26T20:01:28Z","id":"user_181e86f095d64d028676afb1bfdb9774","name":"Test + User","object":"User","parent_id":"user_a76997d126dd488f8ad22d52301300b0","phone_number":"REDACTED","verified":true}],"has_more":true}' + headers: + Cache-Control: + - private, no-cache, no-store + Content-Type: + - application/json; charset=utf-8 + Expires: + - "0" + Pragma: + - no-cache + Referrer-Policy: + - strict-origin-when-cross-origin + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + X-Backend: + - easypost + X-Content-Type-Options: + - nosniff + X-Download-Options: + - noopen + X-Ep-Request-Uuid: + - 57503b0f691ce13ae2ba8732016c6755 + X-Frame-Options: + - SAMEORIGIN + X-Node: + - bigweb63nuq + X-Permitted-Cross-Domain-Policies: + - none + X-Proxied: + - intlb4nuq c0061e0a2e + - extlb1nuq cbbd141214 + X-Runtime: + - "0.086061" + X-Version-Label: + - easypost-202511181852-613eda4497-master + X-Xss-Protection: + - 1; mode=block + status: 200 OK + code: 200 + duration: "" +- request: + body: '{"refresh_url":"https://example.com/refresh","return_url":"https://example.com/return","session_type":"account_onboarding","user_id":"user_5f0c48e7a66b42398740b0149b1bb24c"}' + form: {} + headers: + Authorization: + - REDACTED + Content-Type: + - application/json + User-Agent: + - REDACTED + url: https://api.easypost.com/v2/customer_portal/account_link + method: POST + response: + body: '{"created_at":"2025-11-18T21:12:27Z","expires_at":"2025-11-18T21:17:27Z","link":"https://app.easypost.com/customer-portal/onboarding?session_id=-vvKK5uJizPoC95q","object":"CustomerPortalAccountLink"}' + headers: + Cache-Control: + - private, no-cache, no-store + Content-Type: + - application/json; charset=utf-8 + Expires: + - "0" + Pragma: + - no-cache + Referrer-Policy: + - strict-origin-when-cross-origin + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + X-Backend: + - easypost + X-Content-Type-Options: + - nosniff + X-Download-Options: + - noopen + X-Ep-Request-Uuid: + - 57503b0f691ce13ae2ba8732016c677c + X-Frame-Options: + - SAMEORIGIN + X-Node: + - bigweb55nuq + X-Permitted-Cross-Domain-Policies: + - none + X-Proxied: + - intlb5nuq c0061e0a2e + - extlb1nuq cbbd141214 + X-Runtime: + - "0.326103" + X-Version-Label: + - easypost-202511181852-613eda4497-master + X-Xss-Protection: + - 1; mode=block + status: 201 Created + code: 201 + duration: "" diff --git a/cassettes/TestCreateEmbeddablesSession.yaml b/cassettes/TestCreateEmbeddablesSession.yaml new file mode 100644 index 0000000..3981a37 --- /dev/null +++ b/cassettes/TestCreateEmbeddablesSession.yaml @@ -0,0 +1,112 @@ +--- +version: 1 +interactions: +- request: + body: "" + form: {} + headers: + Authorization: + - REDACTED + User-Agent: + - REDACTED + url: https://api.easypost.com/v2/users/children?page_size=5 + method: GET + response: + body: '{"children":[{"created_at":"2023-09-20T18:01:26Z","id":"user_5f0c48e7a66b42398740b0149b1bb24c","name":"Test + User","object":"User","parent_id":"user_a76997d126dd488f8ad22d52301300b0","phone_number":"REDACTED","verified":true},{"created_at":"2023-09-20T18:09:24Z","id":"user_97f56192c53d490aa7851087b88618a4","name":"Test + User","object":"User","parent_id":"user_a76997d126dd488f8ad22d52301300b0","phone_number":"REDACTED","verified":true},{"created_at":"2023-11-30T20:12:09Z","id":"user_3d8dac28f4ba42729036133637356d40","name":"Test + User","object":"User","parent_id":"user_a76997d126dd488f8ad22d52301300b0","phone_number":"REDACTED","verified":true},{"created_at":"2024-07-26T19:35:11Z","id":"user_f81b29477fec4243a7de2ecc3c4f4907","name":"Test + User","object":"User","parent_id":"user_a76997d126dd488f8ad22d52301300b0","phone_number":"REDACTED","verified":true},{"created_at":"2024-07-26T20:01:28Z","id":"user_181e86f095d64d028676afb1bfdb9774","name":"Test + User","object":"User","parent_id":"user_a76997d126dd488f8ad22d52301300b0","phone_number":"REDACTED","verified":true}],"has_more":true}' + headers: + Cache-Control: + - private, no-cache, no-store + Content-Type: + - application/json; charset=utf-8 + Expires: + - "0" + Pragma: + - no-cache + Referrer-Policy: + - strict-origin-when-cross-origin + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + X-Backend: + - easypost + X-Content-Type-Options: + - nosniff + X-Download-Options: + - noopen + X-Ep-Request-Uuid: + - 57503b11691ce255e2ba8778016e1295 + X-Frame-Options: + - SAMEORIGIN + X-Node: + - bigweb54nuq + X-Permitted-Cross-Domain-Policies: + - none + X-Proxied: + - intlb3nuq c0061e0a2e + - extlb1nuq cbbd141214 + X-Runtime: + - "0.101046" + X-Version-Label: + - easypost-202511181852-613eda4497-master + X-Xss-Protection: + - 1; mode=block + status: 200 OK + code: 200 + duration: "" +- request: + body: '{"origin_host":"https://example.com","user_id":"user_5f0c48e7a66b42398740b0149b1bb24c"}' + form: {} + headers: + Authorization: + - REDACTED + Content-Type: + - application/json + User-Agent: + - REDACTED + url: https://api.easypost.com/v2/embeddables/session + method: POST + response: + body: '{"created_at":"2025-11-18T21:17:09Z","expires_at":"2025-11-18T21:32:09Z","object":"EmbeddablesSession","session_id":"-TWagZkAbtmjHl8d"}' + headers: + Cache-Control: + - private, no-cache, no-store + Content-Type: + - application/json; charset=utf-8 + Expires: + - "0" + Pragma: + - no-cache + Referrer-Policy: + - strict-origin-when-cross-origin + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + X-Backend: + - easypost + X-Content-Type-Options: + - nosniff + X-Download-Options: + - noopen + X-Ep-Request-Uuid: + - 57503b11691ce255e2ba8778016e12bc + X-Frame-Options: + - SAMEORIGIN + X-Node: + - bigweb53nuq + X-Permitted-Cross-Domain-Policies: + - none + X-Proxied: + - intlb3nuq c0061e0a2e + - extlb1nuq cbbd141214 + X-Runtime: + - "0.121376" + X-Version-Label: + - easypost-202511181852-613eda4497-master + X-Xss-Protection: + - 1; mode=block + status: 201 Created + code: 201 + duration: "" diff --git a/customer_portal.go b/customer_portal.go new file mode 100644 index 0000000..0f71d77 --- /dev/null +++ b/customer_portal.go @@ -0,0 +1,34 @@ +package easypost + +import ( + "context" + "net/http" +) + +// A CustomerPortalAccountLink object represents an object containing an AccountLink. +type CustomerPortalAccountLink struct { + Object string `json:"object,omitempty" url:"object,omitempty"` + Link string `json:"link,omitempty" url:"link,omitempty"` + CreatedAt *DateTime `json:"created_at,omitempty" url:"created_at,omitempty"` + ExpiresAt *DateTime `json:"expires_at,omitempty" url:"expires_at,omitempty"` +} + +// CustomerPortalAccountLinkParameters is used to specify parameters for creating an AccountLink. +type CustomerPortalAccountLinkParameters struct { + SessionType string `json:"session_type,omitempty" url:"session_type,omitempty"` + UserId string `json:"user_id,omitempty" url:"user_id,omitempty"` + RefreshUrl string `json:"refresh_url,omitempty" url:"refresh_url,omitempty"` + ReturnUrl string `json:"return_url,omitempty" url:"return_url,omitempty"` + Metadata map[string]interface{} `json:"metadata,omitempty" url:"metadata,omitempty"` +} + +// CreateCustomerPortalAccountLink generates a one-time Customer Portal URL. +func (c *Client) CreateCustomerPortalAccountLink(in *CustomerPortalAccountLinkParameters) (out *CustomerPortalAccountLink, err error) { + return c.CreateCustomerPortalAccountLinkWithContext(context.Background(), in) +} + +// CreateCustomerPortalAccountLinkWithContext performs the same operation as CreateCustomerPortalAccountLink, but allows specifying a context that can interrupt the request. +func (c *Client) CreateCustomerPortalAccountLinkWithContext(ctx context.Context, in *CustomerPortalAccountLinkParameters) (out *CustomerPortalAccountLink, err error) { + err = c.do(ctx, http.MethodPost, "customer_portal/account_link", in, &out) + return +} diff --git a/customer_portal_test.go b/customer_portal_test.go new file mode 100644 index 0000000..1494209 --- /dev/null +++ b/customer_portal_test.go @@ -0,0 +1,25 @@ +package easypost + +func (c *ClientTests) TestCreateCustomerPortalAccountLink() { + client := c.ProdClient() + assert, require := c.Assert(), c.Require() + + childUsers, err := client.ListChildUsers( + &ListOptions{ + PageSize: c.fixture.pageSize(), + }, + ) + require.NoError(err) + + accountLink, err := client.CreateCustomerPortalAccountLink( + &CustomerPortalAccountLinkParameters{ + SessionType: "account_onboarding", + UserId: childUsers.Children[0].ID, + RefreshUrl: "https://example.com/refresh", + ReturnUrl: "https://example.com/return", + }, + ) + require.NoError(err) + + assert.Equal("CustomerPortalAccountLink", accountLink.Object) +} diff --git a/embeddable.go b/embeddable.go new file mode 100644 index 0000000..4d2ebe1 --- /dev/null +++ b/embeddable.go @@ -0,0 +1,31 @@ +package easypost + +import ( + "context" + "net/http" +) + +// A EmbeddablesSession object represents an object containing an AccountLink. +type EmbeddablesSession struct { + Object string `json:"object,omitempty" url:"object,omitempty"` + SessionId string `json:"session_id,omitempty" url:"session_id,omitempty"` + CreatedAt *DateTime `json:"created_at,omitempty" url:"created_at,omitempty"` + ExpiresAt *DateTime `json:"expires_at,omitempty" url:"expires_at,omitempty"` +} + +// EmbeddablesSessionParameters is used to specify parameters for creating an AccountLink. +type EmbeddablesSessionParameters struct { + OriginHost string `json:"origin_host,omitempty" url:"origin_host,omitempty"` + UserId string `json:"user_id,omitempty" url:"user_id,omitempty"` +} + +// CreateEmbeddablesSession creates a temporary session for initializing embeddable components. +func (c *Client) CreateEmbeddablesSession(in *EmbeddablesSessionParameters) (out *EmbeddablesSession, err error) { + return c.CreateEmbeddablesSessionWithContext(context.Background(), in) +} + +// CreateEmbeddablesSessionWithContext performs the same operation as CreateEmbeddablesSession, but allows specifying a context that can interrupt the request. +func (c *Client) CreateEmbeddablesSessionWithContext(ctx context.Context, in *EmbeddablesSessionParameters) (out *EmbeddablesSession, err error) { + err = c.do(ctx, http.MethodPost, "embeddables/session", in, &out) + return +} diff --git a/embeddable_test.go b/embeddable_test.go new file mode 100644 index 0000000..f5ed0a4 --- /dev/null +++ b/embeddable_test.go @@ -0,0 +1,23 @@ +package easypost + +func (c *ClientTests) TestCreateEmbeddablesSession() { + client := c.ProdClient() + assert, require := c.Assert(), c.Require() + + childUsers, err := client.ListChildUsers( + &ListOptions{ + PageSize: c.fixture.pageSize(), + }, + ) + require.NoError(err) + + session, err := client.CreateEmbeddablesSession( + &EmbeddablesSessionParameters{ + OriginHost: "https://example.com", + UserId: childUsers.Children[0].ID, + }, + ) + require.NoError(err) + + assert.Equal("EmbeddablesSession", session.Object) +}