@aftership/carrier-account-sdk
v0.1.0
Published
This SDK enables your application to open an AfterShip-hosted popup window for carrier account creation or editing.
Readme
@aftership/carrier-account-sdk
This SDK enables your application to open an AfterShip-hosted popup window for carrier account creation or editing.
It is intended for customer integration. This document focuses on the integration contract, implementation responsibilities, and SDK usage, while keeping internal implementation details to a minimum.
1. Overview
This integration allows your application to start an AfterShip-hosted carrier account flow without redirecting the user away from your page.
The typical flow is:
- Your backend prepares a Signed URL for the requested action.
- Your frontend passes that Signed URL into
sdk.open(...). - The SDK opens the popup window and manages the browser-side flow.
- Your frontend receives the final result through callbacks such as
onSuccess,onError, oronClose.
This SDK is designed to keep the frontend integration simple. Your application does not need to implement popup lifecycle management or cross-window message handling by itself.
2. Glossary
| Term | Description |
| --- | --- |
| Signed URL | A temporary absolute URL used to open the AfterShip-hosted popup flow. |
| request_id | A request identifier used to correlate a specific create flow. |
| shipper_account_id | The final carrier account identifier returned after a successful flow. |
| Popup Window | A separate browser window opened by the SDK to host the AfterShip UI. |
| Host Application | Your frontend application that integrates this SDK. |
| AfterShip Hosted UI | The popup page hosted by AfterShip where the user completes the flow. |
3. Integration Flow Design
3.1 Flowchart and Interaction Description
The integration flow is shown below:
flowchart TD
A["User initiates Create or Edit"] --> B["Host frontend requests Signed URL from backend"]
B --> C["Backend returns Signed URL"]
C --> D["Frontend calls sdk.open({ url: signedUrl, ... })"]
D --> E["SDK opens AfterShip Hosted UI in a popup window"]
E --> F["User completes the carrier account flow"]
F --> G{"Final popup result"}
G -->|Success| H["onSuccess({ request_id?, shipper_account_id, action })"]
G -->|Runtime error| I["onError({ request_id?, code, message })"]
G -->|Closed| J["onClose({ request_id?, reason })"]Typical user interaction:
- The user clicks a button or toggles a control in your application.
- Your frontend asks your backend for a Signed URL.
- Your frontend calls the SDK with that Signed URL.
- The SDK opens the popup window and waits for the hosted flow to finish.
- Your page updates its state according to the returned callback result.
3.2 How the Signed URL and Popup Flow Work
This SDK assumes that your frontend receives a Signed URL from your backend or another trusted integration layer.
Why this design:
- The popup is opened with a request-specific URL instead of static credentials.
- The frontend only needs to pass the URL into the SDK.
- The SDK isolates popup lifecycle handling from your application code.
What the SDK handles on your behalf:
- Validating the Signed URL format and protocol.
- Opening and closing the popup window.
- Listening for messages returned from the popup window.
- Matching messages by
request_idwhen available. - Normalizing the final browser-side result into
onSuccess,onError, oronClose.
What remains outside the SDK scope:
- generating the Signed URL
- deciding when to start Create or Edit
- updating your own business state after the callback returns
- persisting any mapping between your entities and
shipper_account_id
4. What the Client Needs to Implement
The integration normally involves both frontend and backend work. The sections below outline the responsibilities for each side.
4.1 Backend Responsibilities
Your backend should:
- Prepare a Signed URL for the requested action.
- Return that Signed URL to the frontend.
- Provide the frontend with the correct business context for Create or Edit.
Common patterns:
- Create flow: prepare a Signed URL associated with a new connection attempt, often including a new
request_id. - Edit flow: prepare a Signed URL associated with an existing
shipper_account_id.
4.2 Frontend Responsibilities
Your frontend should:
- Initialize the SDK on the page where the user starts the carrier account flow.
- Request a Signed URL before calling
sdk.open(...). - Call the SDK from a user-triggered action whenever possible.
- Update the page state according to the callback result.
- Call
sdk.destroy()when the page or integration surface is unloaded.
4.3 Suggested Create and Edit Sequences
Create flow:
sequenceDiagram
participant Frontend as Host Frontend
participant Backend as Host Backend
participant SDK as AfterShip SDK
participant AfterShip as AfterShip Hosted UI
Frontend->>Backend: Request Signed URL for create
Backend-->>Frontend: Return Signed URL
Frontend->>SDK: sdk.open({ url: signedUrl, ... })
SDK->>AfterShip: Open popup with Signed URL
AfterShip-->>SDK: Return success / error / close result
SDK-->>Frontend: Trigger callback
Frontend->>Frontend: Update UI stateEdit flow:
sequenceDiagram
participant Frontend as Host Frontend
participant Backend as Host Backend
participant SDK as AfterShip SDK
participant AfterShip as AfterShip Hosted UI
Frontend->>Backend: Request Signed URL for edit
Backend-->>Frontend: Return Signed URL
Frontend->>SDK: sdk.open({ url: signedUrl, ... })
SDK->>AfterShip: Open popup with Signed URL
AfterShip-->>SDK: Return success / error / close result
SDK-->>Frontend: Trigger callback
Frontend->>Frontend: Update UI state5. SDK Reference
5.1 Installation
pnpm add @aftership/carrier-account-sdk5.2 Initialization
import { init } from "@aftership/carrier-account-sdk";
const sdk = init();5.3 sdk.open(...)
sdk.open({
url,
onSuccess(payload) {},
onError(payload) {},
onClose(payload) {},
});Parameter reference:
| Field | Type | Description |
| --- | --- | --- |
| url | string | A Signed URL. It must be a valid absolute URL. |
| onSuccess | (payload) => void | Called when the user completes the flow successfully. |
| onError | (payload) => void | Called when the flow cannot continue because of invalid URLs or runtime errors. |
| onClose | (payload) => void | Called when a popup that was opened is later closed. |
5.4 Minimal Integration Example
import { init } from "@aftership/carrier-account-sdk";
const sdk = init();
async function connectCarrier() {
const signedUrl = await getSignedUrlFromBackend();
sdk.open({
url: signedUrl,
onSuccess(payload) {
console.log("connect success", payload);
},
onError(payload) {
console.error("connect error", payload);
},
onClose(payload) {
console.log("popup closed", payload);
},
});
}
window.addEventListener("beforeunload", () => {
sdk.destroy();
});5.5 Callback Payloads
onSuccess
Called when the user completes the flow successfully.
{
request_id?: string;
shipper_account_id: string;
action: "create" | "edit";
}Field reference:
| Field | Type | Description |
| --- | --- | --- |
| request_id | string \| undefined | The request identifier when available. |
| shipper_account_id | string | The resulting carrier account identifier. |
| action | "create" \| "edit" | The final completed action. |
onError
Called when the flow cannot continue before completion.
{
request_id?: string;
code: string;
message: string;
}Field reference:
| Field | Type | Description |
| --- | --- | --- |
| request_id | string \| undefined | The request identifier when available. |
| code | string | A normalized error code. |
| message | string | A normalized human-readable error message. |
Common error codes:
INVALID_URL: the Signed URL is not a valid absolute URLINVALID_PROTOCOL: the Signed URL does not use an allowed protocol
onClose
Called when the popup window is closed.
{
request_id?: string;
reason: "user_closed" | "unknown";
}Field reference:
| Field | Type | Description |
| --- | --- | --- |
| request_id | string \| undefined | The request identifier when available. |
| reason | "user_closed" \| "unknown" | The normalized close reason. |
Close reasons:
user_closed: the user closed the popup manuallyunknown: the popup closed without a more specific reason
5.6 URL Requirements
The SDK requires the url passed to sdk.open(...) to be a valid Signed URL.
Allowed protocols:
Production:
https://
Local development:
http://localhost
http://127.0.0.1
http://[::1]
http://::1If the URL is invalid, the SDK will trigger onError immediately.
Validation behavior:
- invalid absolute URL ->
INVALID_URL - unsupported protocol ->
INVALID_PROTOCOL
6. Troubleshooting and FAQ
6.1 Why did I not receive onSuccess?
Check in this order:
- Confirm the Signed URL is valid.
- Confirm the popup flow actually reached a successful end state.
- Confirm the
request_idstill matches the current request when applicable. - Confirm your page did not destroy the SDK instance too early.
6.2 What should I do if the popup does not open?
Recommended practice:
- call
sdk.open(...)directly from a user click or similar user-triggered action - use
request_idfrom the payload when it is available
6.3 What should I do when the page is unloaded?
Call:
sdk.destroy();This closes the popup if it is still open and removes related listeners.
6.4 What is the simplest mental model for this SDK?
flowchart LR
A["Prepare Signed URL"] --> B["Call sdk.open(...)"]
B --> C["Handle callback result"]In most integrations, you only need to do these three things:
- Prepare the Signed URL.
- Call
sdk.open(...). - Update your business state according to the callback result.
7. Debugging Tips
If you want to verify the flow quickly, you can refer to the example in the repository:
apps/examplePlease note:
- the example is mainly used to verify popup behavior and callback handling
- you should not treat the example integration as your production implementation directly
