Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# Changelog

## 0.3.0

- Add `createShipment(shipRequest, options)` — calls the FedEx Ship API to create a shipment (`POST /ship/v1/shipments`). Same passthrough pattern as the other methods: caller supplies the full request body, the package forwards it verbatim. Supports `options.customer_transaction_id` and `options.timeout`. Non-2xx responses and 200-with-`errors[]` envelopes both reject with `HttpError`.
- Add `cancelShipment(cancelRequest, options)` — calls the FedEx Ship API to cancel a shipment (`PUT /ship/v1/shipments/cancel`). Same passthrough pattern. Supports `options.customer_transaction_id` and `options.timeout`. Non-2xx responses and 200-with-`errors[]` envelopes both reject with `HttpError`.

## 0.2.0

- Add `validateAddress(addressValidationRequest, options)` — calls the FedEx Address Validation API (`POST /address/v1/addresses/resolve`). Same passthrough pattern as `rateAndTransitTimes`: caller supplies the full request body, the package forwards it verbatim. Supports `options.customer_transaction_id` and `options.timeout` like the other methods. Non-2xx responses and 200-with-`errors[]` envelopes both reject with `HttpError`.
Expand Down
72 changes: 71 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
[![npm version](https://img.shields.io/npm/v/@stores.com/fedex)](https://www.npmjs.com/package/@stores.com/fedex)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)

FedEx REST API client for OAuth tokens, Rates and Transit Times, and Address Validation.
FedEx REST API client for Address Validation, OAuth tokens, Rates and Transit Times, Shipment Cancellation, and Shipment Creation.

## Installation

Expand Down Expand Up @@ -40,6 +40,76 @@ const fedex = new FedEx({

## Methods

### cancelShipment(cancelRequest, options)

Cancel a FedEx shipment via the Ship API. The caller supplies the full request body — `accountNumber`, `trackingNumber`, `senderCountryCode`, `deletionControl` — and the package forwards it verbatim.

See: https://developer.fedex.com/api/en-us/catalog/ship/v1/docs.html

```javascript
const json = await fedex.cancelShipment({
accountNumber: { value: 'your_account_number' },
deletionControl: 'DELETE_ALL_PACKAGES',
senderCountryCode: 'US',
trackingNumber: '794644790138'
});
```

Non-2xx responses reject with `HttpError`. If FedEx returns a 200 response carrying a non-empty `errors[]` envelope, the call rejects with an `HttpError` whose message is every `message` joined by `; ` and whose `.json` is the full response body (with the `errors[]` array, codes, and any other fields).

### createShipment(shipRequest, options)

Create a FedEx shipment via the Ship API. The caller supplies the full request body — `accountNumber`, `labelResponseOptions`, `requestedShipment` — and the package forwards it verbatim.

See: https://developer.fedex.com/api/en-us/catalog/ship/v1/docs.html

```javascript
const json = await fedex.createShipment({
accountNumber: { value: 'your_account_number' },
labelResponseOptions: 'URL_ONLY',
requestedShipment: {
packagingType: 'YOUR_PACKAGING',
pickupType: 'USE_SCHEDULED_PICKUP',
recipients: [{
address: {
city: 'New York',
countryCode: 'US',
postalCode: '10001',
stateOrProvinceCode: 'NY',
streetLines: ['10 FedEx Pkwy']
},
contact: {
personName: 'Test Recipient',
phoneNumber: '0000000000'
}
}],
requestedPackageLineItems: [{ weight: { units: 'LB', value: 5 } }],
serviceType: 'FEDEX_GROUND',
shipper: {
address: {
city: 'Memphis',
countryCode: 'US',
postalCode: '38116',
stateOrProvinceCode: 'TN',
streetLines: ['10 FedEx Pkwy']
},
contact: {
companyName: 'Test Shipper',
phoneNumber: '0000000000'
}
},
shippingChargesPayment: { paymentType: 'SENDER' }
}
});

const trackingNumber = json.output.transactionShipments[0].masterTrackingNumber;

console.log(trackingNumber);
// '794644790138'
```

Non-2xx responses reject with `HttpError`. If FedEx returns a 200 response carrying a non-empty `errors[]` envelope, the call rejects with an `HttpError` whose message is every `message` joined by `; ` and whose `.json` is the full response body (with the `errors[]` array, codes, and any other fields).

### getAccessToken()

FedEx APIs use the OAuth 2.0 protocol for authentication and authorization using the `client_credentials` grant type. Tokens are cached in-process per API key until shortly before they expire.
Expand Down
90 changes: 90 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,96 @@ function FedEx(args) {
...args
};

/**
* Cancel a FedEx shipment via the Ship API. The caller supplies the full
* request body — `accountNumber`, `trackingNumber`, `senderCountryCode`,
* `deletionControl` — and the package forwards it verbatim.
*
* @param {object} cancelRequest - Full Cancel Shipment request body.
* @param {object} [options]
* @param {string} [options.customer_transaction_id] - Sent as the `x-customer-transaction-id`
* request header. FedEx echoes this back so callers can correlate requests with responses.
* @param {number} [options.timeout=30000] - Request timeout in milliseconds.
* @returns {Promise<object>} The parsed response body.
* @see https://developer.fedex.com/api/en-us/catalog/ship/v1/docs.html
*/
this.cancelShipment = async (cancelRequest, options = {}) => {
const accessToken = await this.getAccessToken();

const headers = {
Authorization: `Bearer ${accessToken.access_token}`,
'Content-Type': 'application/json'
};

if (options.customer_transaction_id) {
headers['x-customer-transaction-id'] = options.customer_transaction_id;
}

const response = await fetch(`${_options.url}/ship/v1/shipments/cancel`, {
body: JSON.stringify(cancelRequest),
headers,
method: 'PUT',
signal: AbortSignal.timeout(options.timeout || 30000)
});

if (!response.ok) {
throw await HttpError.from(response);
}

const json = await response.json();

if (json.errors?.length) {
throw await HttpError.from(response);
}

return json;
};

/**
* Create a FedEx shipment via the Ship API. The caller supplies the full
* request body — `accountNumber`, `labelResponseOptions`, `requestedShipment`
* — and the package forwards it verbatim.
*
* @param {object} shipRequest - Full Create Shipment request body.
* @param {object} [options]
* @param {string} [options.customer_transaction_id] - Sent as the `x-customer-transaction-id`
* request header. FedEx echoes this back so callers can correlate requests with responses.
* @param {number} [options.timeout=30000] - Request timeout in milliseconds.
* @returns {Promise<object>} The parsed response body, including `output.transactionShipments[]`.
* @see https://developer.fedex.com/api/en-us/catalog/ship/v1/docs.html
*/
this.createShipment = async (shipRequest, options = {}) => {
const accessToken = await this.getAccessToken();

const headers = {
Authorization: `Bearer ${accessToken.access_token}`,
'Content-Type': 'application/json'
};

if (options.customer_transaction_id) {
headers['x-customer-transaction-id'] = options.customer_transaction_id;
}

const response = await fetch(`${_options.url}/ship/v1/shipments`, {
body: JSON.stringify(shipRequest),
headers,
method: 'POST',
signal: AbortSignal.timeout(options.timeout || 30000)
});

if (!response.ok) {
throw await HttpError.from(response);
}

const json = await response.json();

if (json.errors?.length) {
throw await HttpError.from(response);
}

return json;
};

/**
* Request an OAuth access token from FedEx using the `client_credentials` grant. Tokens
* are cached in memory per API key for half their lifetime, so repeat calls return the
Expand Down
7 changes: 5 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,20 @@
"@stores.com/http-error": "~1.1.0",
"memory-cache": "~0.2.0"
},
"description": "FedEx REST API client for OAuth tokens, rate quotes, and address validation.",
"description": "FedEx REST API client for address validation, OAuth tokens, rate quotes, shipment cancellation, and shipment creation.",
"devDependencies": {
"@eslint/js": "*",
"async": "~3.2.0",
"globals": "*"
},
"keywords": [
"address-validation",
"cancel",
"create",
"fedex",
"logistics",
"rates",
"ship",
"shipping"
],
"license": "MIT",
Expand All @@ -30,5 +33,5 @@
"test": "node --test --test-force-exit --test-reporter=spec",
"test:only": "node --test --test-force-exit --test-only --test-reporter=spec"
},
"version": "0.2.0"
"version": "0.3.0"
}
Loading