├── .gitattributes ├── .github ├── CODEOWNERS ├── ISSUE_TEMPLATE │ ├── bug_report.yml │ └── feature_request.yml ├── PULL_REQUEST_TEMPLATE.md └── workflows │ └── ci.yml ├── .gitignore ├── .gitmodules ├── CHANGELOG.md ├── LICENSE ├── Makefile ├── README.md ├── UPGRADE_GUIDE.md ├── composer.json ├── lib ├── EasyPost │ ├── Address.php │ ├── AddressVerificationFieldError.php │ ├── ApiKey.php │ ├── Batch.php │ ├── Billing.php │ ├── Brand.php │ ├── CarrierAccount.php │ ├── CarrierDetail.php │ ├── Claim.php │ ├── Constant │ │ └── Constants.php │ ├── CustomsInfo.php │ ├── CustomsItem.php │ ├── EasyPostClient.php │ ├── EasyPostObject.php │ ├── EndShipper.php │ ├── Event.php │ ├── Exception │ │ ├── Api │ │ │ ├── ApiException.php │ │ │ ├── BadRequestException.php │ │ │ ├── EncodingException.php │ │ │ ├── ExternalApiException.php │ │ │ ├── ForbiddenException.php │ │ │ ├── GatewayTimeoutException.php │ │ │ ├── HttpException.php │ │ │ ├── InternalServerException.php │ │ │ ├── InvalidRequestException.php │ │ │ ├── JsonException.php │ │ │ ├── MethodNotAllowedException.php │ │ │ ├── NotFoundException.php │ │ │ ├── PaymentException.php │ │ │ ├── RateLimitException.php │ │ │ ├── RedirectException.php │ │ │ ├── ServiceUnavailableException.php │ │ │ ├── TimeoutException.php │ │ │ ├── UnauthorizedException.php │ │ │ └── UnknownApiException.php │ │ └── General │ │ │ ├── EasyPostException.php │ │ │ ├── EndOfPaginationException.php │ │ │ ├── FilteringException.php │ │ │ ├── InvalidObjectException.php │ │ │ ├── InvalidParameterException.php │ │ │ ├── MissingParameterException.php │ │ │ └── SignatureVerificationException.php │ ├── Fee.php │ ├── FieldError.php │ ├── Hook │ │ ├── EventHook.php │ │ ├── RequestHook.php │ │ └── ResponseHook.php │ ├── Http │ │ └── Requestor.php │ ├── Insurance.php │ ├── Message.php │ ├── Order.php │ ├── Parcel.php │ ├── Payload.php │ ├── Pickup.php │ ├── PickupRate.php │ ├── PostageLabel.php │ ├── Rate.php │ ├── ReferralCustomer.php │ ├── Refund.php │ ├── Report.php │ ├── ScanForm.php │ ├── Service │ │ ├── AddressService.php │ │ ├── ApiKeyService.php │ │ ├── BaseService.php │ │ ├── BatchService.php │ │ ├── BetaRateService.php │ │ ├── BetaReferralCustomerService.php │ │ ├── BillingService.php │ │ ├── CarrierAccountService.php │ │ ├── CarrierMetadataService.php │ │ ├── ClaimService.php │ │ ├── CustomsInfoService.php │ │ ├── CustomsItemService.php │ │ ├── EndShipperService.php │ │ ├── EventService.php │ │ ├── InsuranceService.php │ │ ├── OrderService.php │ │ ├── ParcelService.php │ │ ├── PickupService.php │ │ ├── RateService.php │ │ ├── ReferralCustomerService.php │ │ ├── RefundService.php │ │ ├── ReportService.php │ │ ├── ScanFormService.php │ │ ├── ShipmentService.php │ │ ├── SmartRateService.php │ │ ├── TrackerService.php │ │ ├── UserService.php │ │ └── WebhookService.php │ ├── Shipment.php │ ├── TaxIdentifier.php │ ├── Tracker.php │ ├── TrackingDetail.php │ ├── TrackingLocation.php │ ├── User.php │ ├── Util │ │ ├── InternalUtil.php │ │ └── Util.php │ ├── Verification.php │ ├── VerificationDetails.php │ ├── Verifications.php │ └── Webhook.php └── easypost.php ├── phpstan.neon ├── phpunit.xml.dist └── test ├── EasyPost ├── AddressTest.php ├── ApiKeyTest.php ├── BatchTest.php ├── BetaRateTest.php ├── BetaReferralCustomerTest.php ├── BillingTest.php ├── CarrierAccountTest.php ├── CarrierMetadataTest.php ├── ClaimTest.php ├── CustomsInfoTest.php ├── CustomsItemTest.php ├── EasyPostClientTest.php ├── EasyPostObjectTest.php ├── EndShipperTest.php ├── ErrorTest.php ├── EventTest.php ├── Fixture.php ├── HookTest.php ├── InsuranceTest.php ├── Mocking │ ├── MockRequest.php │ ├── MockRequestMatchRule.php │ ├── MockRequestResponseInfo.php │ └── MockingUtility.php ├── OrderTest.php ├── ParcelTest.php ├── PickupTest.php ├── RateTest.php ├── ReferralCustomerTest.php ├── RefundTest.php ├── ReportTest.php ├── RequireTest.php ├── ScanFormTest.php ├── ShipmentTest.php ├── SmartRateTest.php ├── TestUtil.php ├── TrackerTest.php ├── UserTest.php ├── UtilTest.php └── WebhookTest.php ├── bootstrap.php └── cassettes ├── addresses ├── all.yml ├── create.yml ├── createAndVerify.yml ├── createVerify.yml ├── createVerifyArray.yml ├── createVerifyStrict.yml ├── getNextPage.yml ├── retrieve.yml ├── verify.yml └── verifyInvalid.yml ├── apiKeys ├── allApiKeys.yml ├── authenticatedUserApiKeys.yml └── childUserApiKeys.yml ├── batches ├── addRemoveShipment.yml ├── all.yml ├── buy.yml ├── create.yml ├── createScanForm.yml ├── label.yml └── retrieve.yml ├── beta ├── rate │ ├── retrieveLowestStatelessRates.yml │ └── retrieveStatelessRates.yml └── referral_customers │ ├── addPaymentMethod.yml │ ├── refundByAmount.yml │ ├── refundByPaymentLog.yml │ ├── testCreateBankAccountClientSecret.yml │ └── testCreateCreditCardClientSecret.yml ├── carrier_accounts ├── all.yml ├── create.yml ├── createWithCustomWorkflow.yml ├── create_amazon.yml ├── create_ups.yml ├── delete.yml ├── retrieve.yml ├── types.yml ├── update.yml └── update_ups.yml ├── carrier_metadata ├── retrieveCarrierMetadata.yml └── retrieveCarrierMetadataWithFilters.yml ├── claim ├── all.yml ├── cancel.yml ├── create.yml ├── getNextPage.yml └── retrieve.yml ├── customs_info ├── create.yml └── retrieve.yml ├── customs_items ├── create.yml └── retrieve.yml ├── end_shipper ├── all.yml ├── create.yml ├── retrieve.yml └── update.yml ├── errors ├── errors.yml └── errorsAlternativeFormat.yml ├── events ├── all.yml ├── getNextPage.yml ├── retrieve.yml ├── retrieve_all_payloads.yml └── retrieve_payload.yml ├── hooks ├── request.yml ├── response.yml └── unsubscribe.yml ├── insurance ├── all.yml ├── create.yml ├── getNextPage.yml ├── refund.yml └── retrieve.yml ├── orders ├── buy.yml ├── buyRateObject.yml ├── create.yml ├── getRates.yml ├── lowestRate.yml └── retrieve.yml ├── parcels ├── create.yml └── retrieve.yml ├── pickups ├── all.yml ├── buy.yml ├── cancel.yml ├── create.yml ├── getNextPage.yml ├── lowestRate.yml └── retrieve.yml ├── rates └── retrieve.yml ├── referral_customers ├── addBankAccountFromStripe.yml ├── addCreditCard.yml ├── addCreditCardFromStripe.yml ├── all.yml ├── create.yml ├── getNextPage.yml └── updateEmail.yml ├── refunds ├── all.yml ├── create.yml ├── getNextPage.yml └── retrieve.yml ├── reports ├── all.yml ├── createCustomAdditionalColumnReport.yml ├── createCustomColumnReport.yml ├── createReport.yml ├── getNextPage.yml └── retrieveReport.yml ├── scanForms ├── all.yml ├── create.yml ├── getNextPage.yml └── retrieve.yml ├── shipments ├── all.yml ├── buy.yml ├── buyRateObject.yml ├── buyShipmentWithEndShipper.yml ├── convertLabel.yml ├── convertLabelUnwrappedParam.yml ├── create.yml ├── createEmptyObjects.yml ├── createTaxIdentifiers.yml ├── createWithIds.yml ├── generateForm.yml ├── getNextPage.yml ├── insure.yml ├── insureUnwrappedParam.yml ├── lowestRate.yml ├── lowestRateExclusions.yml ├── lowestSmartRateVariations.yml ├── recommendShipDate.yml ├── refund.yml ├── regenerateRates.yml ├── retrieve.yml ├── retrieveEstimatedDeliveryDate.yml └── smartrates.yml ├── smartrate ├── estimatedDeliveryDate.yml └── recommendShipDate.yml ├── trackers ├── all.yml ├── create.yml ├── createUnwrappedParam.yml ├── getNextPage.yml └── retrieve.yml ├── users ├── allChildren.yml ├── brand.yml ├── create.yml ├── delete.yml ├── getNextPageOfChildren.yml ├── retrieve.yml ├── retrieveMe.yml └── update.yml └── webhooks ├── all.yml ├── create.yml ├── delete.yml ├── retrieve.yml └── update.yml /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | 3 | # Cassettes 4 | test/cassettes/**/* -diff 5 | test/cassettes/**/* linguist-generated 6 | 7 | # Docs 8 | docs/**/* -diff 9 | docs/**/* linguist-generated 10 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | # Ping the Shippers team for reviews on every PR 2 | * @EasyPost/team-shippers 3 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.yml: -------------------------------------------------------------------------------- 1 | name: Bug Report 2 | description: File a bug report 3 | title: "[Bug]: " 4 | labels: [ "triage" ] 5 | body: 6 | - type: markdown 7 | attributes: 8 | value: | 9 | Thank you for taking the time to report an issue in this repository. Please fill out the form below. 10 | - type: input 11 | id: software-version 12 | attributes: 13 | label: Software Version 14 | # change this description for the specific repo 15 | description: | 16 | What version of our software are you running? 17 | TIP: [Available versions](https://github.com/EasyPost/easypost-php/releases) 18 | validations: 19 | required: true 20 | - type: input 21 | id: language-version 22 | attributes: 23 | label: Language Version 24 | # change this description for the specific language of the repo 25 | description: | 26 | What language version and/or framework are you using? 27 | TIP: [How to find your PHP version](https://www.php.net/manual/en/function.phpversion.php) 28 | validations: 29 | required: true 30 | - type: input 31 | id: os 32 | attributes: 33 | label: Operating System 34 | description: What operating system are you running the software on? 35 | validations: 36 | required: true 37 | - type: textarea 38 | id: behavior 39 | attributes: 40 | label: What happened? 41 | description: | 42 | Please describe what happened in reproducible steps. 43 | Include how often you see this issue, and any relevant links (i.e. GitHub issue, Stack Overflow, etc.). 44 | value: | 45 | 1. 46 | 2. 47 | 3. 48 | ... 49 | validations: 50 | required: true 51 | - type: textarea 52 | id: expected-behavior 53 | attributes: 54 | label: What was expected? 55 | description: Please describe what was expected to happen instead. 56 | validations: 57 | required: true 58 | - type: textarea 59 | id: sample-code 60 | attributes: 61 | label: Sample Code 62 | description: | 63 | Please provide any sample code that demonstrates the behavior. 64 | This will be automatically formatted into the appropriate language, so no need for backticks. 65 | **Do not include any private information such as API keys or passwords.** 66 | # change this render to the appropriate language: https://github.com/github/linguist/blob/master/lib/linguist/languages.yml 67 | render: inc 68 | validations: 69 | required: false 70 | - type: textarea 71 | id: logs 72 | attributes: 73 | label: Relevant logs 74 | description: | 75 | Please copy and paste any relevant log output. 76 | This will be automatically formatted into shell output, so no need for backticks. 77 | If you have screenshots instead, please paste them below. 78 | **Do not include any private information such as API keys or passwords.** 79 | render: sh 80 | validations: 81 | required: false 82 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.yml: -------------------------------------------------------------------------------- 1 | name: Feature Request 2 | description: Request a new feature 3 | title: "[Feat]: " 4 | labels: [ "triage" ] 5 | body: 6 | - type: markdown 7 | attributes: 8 | value: | 9 | Thank you for taking the time to request a new feature. 10 | Please note, all feature requests are subject to review and approval. 11 | We welcome all suggestions and ideas, but we cannot guarantee when or if we will implement them. 12 | 13 | We also welcome pull requests, if you would like to implement the feature yourself. 14 | Doing so will likely accelerate the process of implementing the requested feature. 15 | - type: checkboxes 16 | id: searched 17 | attributes: 18 | label: Feature Request Is New 19 | # change issue link below for the specific repo 20 | description: | 21 | Before we begin, please confirm that the requested feature does not already exist or has not [already been requested](https://github.com/EasyPost/easypost-php/issues). 22 | options: 23 | - label: I have verified that the requested feature does not already exist or has not already been requested. 24 | required: true 25 | - type: textarea 26 | id: description 27 | attributes: 28 | label: Description of the feature 29 | description: | 30 | Please provide a detailed description of the feature, including: 31 | - What the feature is 32 | - What value it adds to the application 33 | - How it should be implemented (i.e. pseudo-code, or a high-level description of the user experience) 34 | - Any other relevant information 35 | validations: 36 | required: true 37 | 38 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | # Description 2 | 3 | 4 | 5 | # Testing 6 | 7 | 14 | 15 | # Pull Request Type 16 | 17 | Please select the option(s) that are relevant to this PR. 18 | 19 | - [ ] Bug fix (non-breaking change which fixes an issue) 20 | - [ ] New feature (non-breaking change which adds functionality) 21 | - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) 22 | - [ ] Improvement (fixing a typo, updating readme, renaming a variable name, etc) 23 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: 'CI' 2 | 3 | on: 4 | push: 5 | branches: [master] 6 | pull_request: ~ 7 | workflow_dispatch: ~ 8 | 9 | jobs: 10 | lint: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@v4 14 | - uses: shivammathur/setup-php@v2 15 | with: 16 | php-version: '8.3' 17 | - name: install dependencies 18 | run: make install 19 | - name: lint 20 | run: make lint 21 | run-tests: 22 | runs-on: ubuntu-latest 23 | strategy: 24 | matrix: 25 | # TODO: Add 8.4 when VCR releases a version compatible with it 26 | phpversion: ['8.1', '8.2', '8.3'] 27 | steps: 28 | - uses: actions/checkout@v4 29 | - uses: shivammathur/setup-php@v2 30 | with: 31 | php-version: ${{ matrix.phpversion }} 32 | coverage: xdebug 33 | - name: get composer cache directory 34 | id: composer-cache 35 | run: echo "::set-output name=dir::$(composer config cache-files-dir)" 36 | - name: cache dependencies 37 | uses: actions/cache@v3 38 | with: 39 | path: ${{ steps.composer-cache.outputs.dir }} 40 | key: ${{ runner.os }}-${{ matrix.phpversion }}-composer-${{ hashFiles('**/composer.lock') }} 41 | restore-keys: ${{ runner.os }}-${{ matrix.phpversion }}-composer- 42 | - name: install dependencies 43 | run: make install 44 | - name: test with phpunit on ${{ matrix.phpversion }} 45 | run: EASYPOST_TEST_API_KEY=123 EASYPOST_PROD_API_KEY=123 make coverage 46 | - name: Coveralls 47 | if: github.ref == 'refs/heads/master' 48 | env: 49 | COVERALLS_REPO_TOKEN: ${{ secrets.GITHUB_TOKEN }} 50 | run: ./bin/php-coveralls --coverage_clover=build/logs/clover.xml -v 51 | docs: 52 | if: github.ref == 'refs/heads/master' 53 | runs-on: ubuntu-latest 54 | steps: 55 | - uses: actions/checkout@v4 56 | - uses: shivammathur/setup-php@v2 57 | with: 58 | php-version: '8.3' 59 | - name: Install Dependencies 60 | run: make install 61 | - name: Generate Docs 62 | run: make docs 63 | - name: Deploy Docs 64 | uses: peaceiris/actions-gh-pages@v3 65 | with: 66 | github_token: ${{ secrets.GITHUB_TOKEN }} 67 | publish_dir: docs 68 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ._* 2 | .AppleDouble 3 | .DS_Store 4 | .env 5 | .idea/ 6 | .LSOverride 7 | .phpdoc 8 | .Spotlight-V100 9 | .Trashes 10 | *.cache 11 | *.phar 12 | *.sublime-* 13 | bin 14 | clover.html 15 | clover.xml 16 | composer.lock 17 | docs 18 | easypost-php 19 | Icon 20 | vendor 21 | /phpcs.xml -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "examples"] 2 | path = examples 3 | url = https://github.com/EasyPost/examples 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (c) 2013 EasyPost (Simpler Postage, Inc) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | ## help - Display help about make targets for this Makefile 2 | help: 3 | @cat Makefile | grep '^## ' --color=never | cut -c4- | sed -e "`printf 's/ - /\t- /;'`" | column -s "`printf '\t'`" -t 4 | 5 | ## clean - Cleans the project 6 | clean: 7 | rm -rf vendor clover.xml clover.html bin .phpunit.cache 8 | 9 | ## codesniffer - Run linting on the PHP files 10 | codesniffer: 11 | composer lint 12 | 13 | ## codesniffer-fix- Fix lint errors on PHP files 14 | codesniffer-fix: 15 | composer fix 16 | 17 | ## coverage - Runs the test suite and generates a coverage report 18 | coverage: 19 | composer coverage 20 | 21 | ## docs - Generate documentation for the library 22 | docs: 23 | curl -LJs https://github.com/phpDocumentor/phpDocumentor/releases/download/v3.3.1/phpDocumentor.phar -o phpDocumentor.phar 24 | php phpDocumentor.phar -d lib -t docs 25 | 26 | ## init-examples-submodule - Initialize the examples submodule 27 | init-examples-submodule: 28 | git submodule init 29 | git submodule update 30 | 31 | ## install - Install dependencies 32 | install: | init-examples-submodule 33 | composer install --no-ansi --no-interaction --no-scripts --no-progress --prefer-dist 34 | 35 | ## lint - Lint the project 36 | lint: codesniffer phpstan scan 37 | 38 | ## lint-fix - Fix linting errors 39 | lint-fix: codesniffer-fix 40 | 41 | ## phpstan - Scan for static analysis errors 42 | phpstan: 43 | composer phpstan 44 | 45 | ## release - Cuts a release for the project on GitHub (requires GitHub CLI) 46 | # tag = The associated tag title of the release 47 | # target = Target branch or full commit SHA 48 | release: 49 | gh release create ${tag} --target ${target} 50 | 51 | ## scan - Runs security analysis on the project 52 | scan: 53 | composer scan 54 | 55 | ## test - Test the project 56 | test: 57 | composer test 58 | 59 | ## update - Update dependencies 60 | update: | update-examples-submodule 61 | composer update 62 | 63 | ## update-examples-submodule - Update the examples submodule 64 | update-examples-submodule: 65 | git submodule init 66 | git submodule update --remote 67 | 68 | .PHONY: help clean codesniffer codesniffer-fix coverage docs install lint lint-fix release scan test update update-examples-submodule 69 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "easypost/easypost-php", 3 | "description": "EasyPost Shipping API Client Library for PHP", 4 | "version": "8.1.0", 5 | "keywords": [ 6 | "shipping", 7 | "api", 8 | "easypost" 9 | ], 10 | "homepage": "https://github.com/EasyPost/easypost-php", 11 | "type": "library", 12 | "license": "MIT", 13 | "authors": [ 14 | { 15 | "name": "EasyPost Developers", 16 | "email": "oss@easypost.com", 17 | "homepage": "https://www.easypost.com" 18 | } 19 | ], 20 | "require": { 21 | "ext-json": "*", 22 | "php": ">=8.1", 23 | "guzzlehttp/guzzle": "^7.9" 24 | }, 25 | "require-dev": { 26 | "allejo/php-vcr-sanitizer": "^1.1", 27 | "php-coveralls/php-coveralls": "^2.7", 28 | "php-vcr/php-vcr": "^1.8", 29 | "phpunit/phpunit": "^10", 30 | "squizlabs/php_codesniffer": "^3.11", 31 | "roave/security-advisories": "dev-latest", 32 | "rregeer/phpunit-coverage-check": "^0.3.1", 33 | "phpstan/phpstan": "^2.1" 34 | }, 35 | "scripts": { 36 | "coverage": "XDEBUG_MODE=coverage ./bin/phpunit --coverage-html clover.html --coverage-clover build/logs/clover.xml && ./bin/coverage-check build/logs/clover.xml 85 --only-percentage", 37 | "fix": "./bin/phpcbf --standard=examples/style_guides/php/phpcs.xml lib test", 38 | "lint": "./bin/phpcs --standard=examples/style_guides/php/phpcs.xml lib test", 39 | "phpstan": "./bin/phpstan analyse --memory-limit 4G", 40 | "scan": "composer update --dry-run roave/security-advisories", 41 | "test": "./bin/phpunit" 42 | }, 43 | "config": { 44 | "bin-dir": "bin" 45 | }, 46 | "autoload": { 47 | "psr-4": { 48 | "EasyPost\\": "lib/EasyPost/" 49 | } 50 | }, 51 | "autoload-dev": { 52 | "psr-4": { 53 | "EasyPost\\Test\\": "test/EasyPost/" 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /lib/EasyPost/Address.php: -------------------------------------------------------------------------------- 1 | $pending_urls 15 | * @property array $completed_urls 16 | * @property string $created_at 17 | * @property string $updated_at 18 | */ 19 | class Event extends EasyPostObject 20 | { 21 | } 22 | -------------------------------------------------------------------------------- /lib/EasyPost/Exception/Api/ApiException.php: -------------------------------------------------------------------------------- 1 | > $errors 13 | * @property string $message 14 | * @property string|null $httpBody 15 | * @property int|null $httpStatus 16 | * @property mixed $jsonBody 17 | */ 18 | class ApiException extends EasyPostException 19 | { 20 | public $code; // @phpstan-ignore-line 21 | public $errors; // @phpstan-ignore-line 22 | protected $message; // @phpstan-ignore-line 23 | private ?string $httpBody; 24 | private ?int $httpStatus; 25 | private mixed $jsonBody; 26 | 27 | /** 28 | * ApiException constructor. 29 | * 30 | * @param string $message 31 | * @param int|null $httpStatus 32 | * @param string|null $httpBody 33 | */ 34 | public function __construct(string $message = '', ?int $httpStatus = null, ?string $httpBody = null) 35 | { 36 | parent::__construct($message); 37 | $this->httpStatus = $httpStatus; 38 | $this->httpBody = $httpBody; 39 | $this->errors = []; 40 | $this->code = null; 41 | 42 | $this->jsonBody = isset($httpBody) ? json_decode($httpBody, true) : null; 43 | 44 | // Set `errors` property 45 | if (isset($this->jsonBody) && !empty($this->jsonBody['error']['errors'])) { 46 | $this->errors = $this->jsonBody['error']['errors']; 47 | } 48 | 49 | // Set `code` property 50 | if (isset($this->jsonBody) && !empty($this->jsonBody['error']['code'])) { 51 | $this->code = $this->jsonBody['error']['code']; 52 | } 53 | } 54 | 55 | /** 56 | * Get the HTTP status code. 57 | * 58 | * @return int|null 59 | */ 60 | public function getHttpStatus(): ?int 61 | { 62 | return $this->httpStatus; 63 | } 64 | 65 | /** 66 | * Get the HTTP body. 67 | * 68 | * @return string|null 69 | */ 70 | public function getHttpBody(): ?string 71 | { 72 | return $this->httpBody; 73 | } 74 | 75 | /** 76 | * Pretty print the error. 77 | * 78 | * @return void 79 | */ 80 | public function prettyPrint(): void 81 | { 82 | print($this->code . ' (' . $this->getHttpStatus() . '): ' . 83 | $this->getMessage() . "\n"); 84 | if (!empty($this->errors) && is_array($this->errors[0])) { 85 | print("Field errors:\n"); 86 | foreach ($this->errors as $fieldError) { 87 | foreach ($fieldError as $k => $v) { 88 | print(' ' . $k . ': ' . $v . "\n"); 89 | } 90 | print("\n"); 91 | } 92 | } 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /lib/EasyPost/Exception/Api/BadRequestException.php: -------------------------------------------------------------------------------- 1 | 12 | */ 13 | private array $eventHandlers = []; 14 | 15 | /** 16 | * Fires when the class is invoked. 17 | * 18 | * @param array ...$args 19 | * @return void 20 | */ 21 | public function __invoke(array ...$args): void 22 | { 23 | foreach ($this->eventHandlers as $eventHandler) { 24 | $eventHandler(...$args); 25 | } 26 | } 27 | 28 | /** 29 | * Add an HTTP handler to the list of handlers. 30 | * 31 | * @param callable $handler 32 | * @return EventHook 33 | */ 34 | public function addHandler(callable $handler) 35 | { 36 | $this->eventHandlers[] = $handler; 37 | return $this; 38 | } 39 | 40 | /** 41 | * Remove an HTTP handler from the list of handlers. 42 | * 43 | * @param callable $handler 44 | * @return EventHook 45 | */ 46 | public function removeHandler(callable $handler) 47 | { 48 | $index = array_search($handler, $this->eventHandlers, true); 49 | if ($index !== false) { 50 | array_splice($this->eventHandlers, (int)$index, 1); 51 | } 52 | return $this; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /lib/EasyPost/Hook/RequestHook.php: -------------------------------------------------------------------------------- 1 | $messages 22 | * @property string $created_at 23 | * @property string $updated_at 24 | */ 25 | class Insurance extends EasyPostObject 26 | { 27 | } 28 | -------------------------------------------------------------------------------- /lib/EasyPost/Message.php: -------------------------------------------------------------------------------- 1 | |null $carriers 32 | * @param array|null $services 33 | * @return Rate 34 | */ 35 | public function lowestRate(?array $carriers = [], ?array $services = []): Rate 36 | { 37 | /** @var Rate $lowestRate */ 38 | $lowestRate = InternalUtil::getLowestObjectRate($this, $carriers, $services); 39 | 40 | return $lowestRate; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /lib/EasyPost/Parcel.php: -------------------------------------------------------------------------------- 1 | |null $carriers 35 | * @param array|null $services 36 | * @return PickupRate 37 | */ 38 | public function lowestRate(?array $carriers = [], ?array $services = []): PickupRate 39 | { 40 | /** @var PickupRate $lowestRate */ 41 | $lowestRate = InternalUtil::getLowestObjectRate($this, $carriers, $services, 'pickup_rates'); 42 | 43 | return $lowestRate; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /lib/EasyPost/PickupRate.php: -------------------------------------------------------------------------------- 1 | $tracking_codes 13 | * @property string $form_url 14 | * @property string $form_file_type 15 | * @property string $batch_id 16 | * @property string $created_at 17 | * @property string $updated_at 18 | */ 19 | class ScanForm extends EasyPostObject 20 | { 21 | } 22 | -------------------------------------------------------------------------------- /lib/EasyPost/Service/AddressService.php: -------------------------------------------------------------------------------- 1 | getNextPageResources(self::serviceModelClassName(self::class), $addresses, $pageSize); 45 | } 46 | 47 | /** 48 | * Create an address. 49 | * 50 | * @param mixed $params 51 | * @return mixed 52 | */ 53 | public function create(mixed $params = null): mixed 54 | { 55 | $wrappedParams = []; 56 | 57 | if (isset($params['verify'])) { 58 | $verify = $params['verify']; 59 | unset($params['verify']); 60 | $wrappedParams['verify'] = $verify; 61 | } 62 | 63 | if (isset($params['verify_strict'])) { 64 | $verifyStrict = $params['verify_strict']; 65 | unset($params['verify_strict']); 66 | $wrappedParams['verify_strict'] = $verifyStrict; 67 | } 68 | 69 | $wrappedParams['address'] = $params; 70 | 71 | return self::createResource(self::serviceModelClassName(self::class), $wrappedParams); 72 | } 73 | 74 | /** 75 | * Create and verify an address. 76 | * 77 | * @param mixed $params 78 | * @return mixed 79 | */ 80 | public function createAndVerify(mixed $params = null): mixed 81 | { 82 | if (!isset($params['address']) || !is_array($params['address'])) { 83 | $clone = $params; 84 | unset($params); 85 | $params['address'] = $clone; 86 | } 87 | 88 | $url = self::classUrl(self::serviceModelClassName(self::class)); 89 | $response = Requestor::request($this->client, 'post', $url . '/create_and_verify', $params); 90 | 91 | return InternalUtil::convertToEasyPostObject($this->client, $response['address']); 92 | } 93 | 94 | /** 95 | * Verify an address. 96 | * 97 | * @param string $id 98 | * @return mixed 99 | */ 100 | public function verify(string $id): mixed 101 | { 102 | $url = $this->instanceUrl(self::serviceModelClassName(self::class), $id) . '/verify'; 103 | $response = Requestor::request($this->client, 'get', $url, null); 104 | 105 | return InternalUtil::convertToEasyPostObject($this->client, $response['address']); 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /lib/EasyPost/Service/ApiKeyService.php: -------------------------------------------------------------------------------- 1 | client, 'get', '/api_keys'); 23 | 24 | return InternalUtil::convertToEasyPostObject($this->client, $response); 25 | } 26 | 27 | /** 28 | * Retrieve a list of API keys (works for the authenticated user or a child user). 29 | * 30 | * @param string $id The user ID to retrieve API keys for 31 | * @return mixed 32 | * @throws FilteringException If no user is found with the given ID 33 | */ 34 | public function retrieveApiKeysForUser(string $id): mixed 35 | { 36 | $apiKeys = self::all(); 37 | 38 | if ($apiKeys->id == $id) { 39 | // This function was called on the authenticated user 40 | return $apiKeys->keys; 41 | } 42 | 43 | 44 | // This function was called on a child user, authenticated as parent, only return this child user's details 45 | foreach ($apiKeys->children as $childrenKeys) { 46 | if ($childrenKeys->id == $id) { 47 | return $childrenKeys->keys; 48 | } 49 | } 50 | 51 | throw new FilteringException(Constants::NO_USER_FOUND_ERROR); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /lib/EasyPost/Service/BetaRateService.php: -------------------------------------------------------------------------------- 1 | $params, 23 | ]; 24 | 25 | $response = Requestor::request($this->client, 'post', '/rates', $wrappedParams, true); 26 | 27 | return InternalUtil::convertToEasyPostObject($this->client, $response['rates']); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /lib/EasyPost/Service/BetaReferralCustomerService.php: -------------------------------------------------------------------------------- 1 | [ 33 | 'stripe_customer_id' => $stripeCustomerId, 34 | 'payment_method_reference' => $paymentMethodReference, 35 | 'priority' => $priority 36 | ] 37 | ]; 38 | 39 | $response = Requestor::request($this->client, 'post', '/referral_customers/payment_method', $params, true); 40 | 41 | return InternalUtil::convertToEasyPostObject($this->client, $response); 42 | } 43 | 44 | /** 45 | * Refund a ReferralCustomer wallet by specifying an amount. 46 | * 47 | * @param int $refundAmount 48 | * @return mixed 49 | */ 50 | public function refundByAmount(int $refundAmount): mixed 51 | { 52 | $params = ['refund_amount' => $refundAmount]; 53 | 54 | $response = Requestor::request($this->client, 'post', '/referral_customers/refunds', $params, true); 55 | 56 | return InternalUtil::convertToEasyPostObject($this->client, $response); 57 | } 58 | 59 | /** 60 | * Refund a ReferralCustomer wallet by specifying a payment log ID to completely refund. 61 | * 62 | * @param string $paymentLogId 63 | * @return mixed 64 | */ 65 | public function refundByPaymentLog(string $paymentLogId): mixed 66 | { 67 | $params = ['payment_log_id' => $paymentLogId]; 68 | 69 | $response = Requestor::request($this->client, 'post', '/referral_customers/refunds', $params, true); 70 | 71 | return InternalUtil::convertToEasyPostObject($this->client, $response); 72 | } 73 | 74 | /** 75 | * Creates a client secret to use with Stripe when adding a credit card. 76 | * 77 | * @return mixed 78 | */ 79 | public function createCreditCardClientSecret(): mixed 80 | { 81 | $response = Requestor::request($this->client, 'post', '/setup_intents', null, true); 82 | 83 | return InternalUtil::convertToEasyPostObject($this->client, $response); 84 | } 85 | 86 | /** 87 | * Creates a client secret to use with Stripe when adding a bank account. 88 | * 89 | * @param string|null $returnUrl 90 | * @return mixed 91 | */ 92 | public function createBankAccountClientSecret(?string $returnUrl = null): mixed 93 | { 94 | $params = $returnUrl ? ['return_url' => $returnUrl] : null; 95 | $response = Requestor::request($this->client, 'post', '/financial_connections_sessions', $params, true); 96 | 97 | return InternalUtil::convertToEasyPostObject($this->client, $response); 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /lib/EasyPost/Service/BillingService.php: -------------------------------------------------------------------------------- 1 | id == null) { 30 | throw new PaymentException(Constants::NO_BILLING_ERROR); 31 | } 32 | 33 | return InternalUtil::convertToEasyPostObject($this->client, $paymentMethods); 34 | } 35 | 36 | /** 37 | * Fund your EasyPost wallet by charging your primary or secondary payment method. 38 | * 39 | * @param string $amount 40 | * @param string $priority 41 | * @return void 42 | */ 43 | public function fundWallet(string $amount, string $priority = 'primary'): void 44 | { 45 | [$paymentMethodEndpoint, $paymentMethodId] = self::getPaymentInfo(strtolower($priority)); 46 | 47 | $url = $paymentMethodEndpoint . "/$paymentMethodId/charges"; 48 | $wrappedParams = ['amount' => $amount]; 49 | 50 | Requestor::request($this->client, 'post', $url, $wrappedParams); 51 | } 52 | 53 | /** 54 | * Delete a payment method. 55 | * 56 | * @param string $priority 57 | * @return void 58 | */ 59 | public function deletePaymentMethod(string $priority): void 60 | { 61 | [$paymentMethodEndpoint, $paymentMethodId] = self::getPaymentInfo(strtolower($priority)); 62 | $url = $paymentMethodEndpoint . "/$paymentMethodId"; 63 | 64 | Requestor::request($this->client, 'delete', $url); 65 | } 66 | 67 | /** 68 | * Get payment info (type of the payment method and ID of the payment method) 69 | * 70 | * @param string $priority 71 | * @return array 72 | * @throws PaymentException 73 | */ 74 | private function getPaymentInfo(string $priority = 'primary'): array 75 | { 76 | $paymentMethods = self::retrievePaymentMethods(); 77 | $paymentMethodMap = [ 78 | 'primary' => 'primary_payment_method', 79 | 'secondary' => 'secondary_payment_method' 80 | ]; 81 | $paymentMethodToUse = $paymentMethodMap[$priority] ?? null; 82 | 83 | if ($paymentMethodToUse != null && $paymentMethods->$paymentMethodToUse->id != null) { 84 | $paymentMethodId = $paymentMethods->$paymentMethodToUse->id; 85 | $paymentMethodObjectType = $paymentMethods->$paymentMethodToUse->object; 86 | if ($paymentMethodObjectType == 'CreditCard') { 87 | $endpoint = '/credit_cards'; 88 | } else if ($paymentMethodObjectType == 'BankAccount') { 89 | $endpoint = '/bank_accounts'; 90 | } else { 91 | throw new PaymentException(Constants::INVALID_PAYMENT_METHOD_ERROR); 92 | } 93 | } else { 94 | throw new PaymentException(Constants::INVALID_PAYMENT_METHOD_ERROR); 95 | } 96 | 97 | return [$endpoint, $paymentMethodId]; 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /lib/EasyPost/Service/CarrierMetadataService.php: -------------------------------------------------------------------------------- 1 | |null $carriers 17 | * @param array|null $types 18 | * @return mixed 19 | */ 20 | public function retrieve(?array $carriers = null, ?array $types = null): mixed 21 | { 22 | $url = '/metadata/carriers'; 23 | if (isset($carriers) || isset($types)) { 24 | $url = "{$url}?"; 25 | } 26 | if (isset($carriers)) { 27 | $url = "{$url}carriers=" . join(',', $carriers); 28 | } 29 | if (isset($carriers) && isset($types)) { 30 | $url = "{$url}&"; 31 | } 32 | if (isset($types)) { 33 | $url = "{$url}types=" . join(',', $types); 34 | } 35 | 36 | $response = Requestor::request($this->client, 'get', $url, null); 37 | 38 | return InternalUtil::convertToEasyPostObject($this->client, $response['carriers'] ?? []); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /lib/EasyPost/Service/ClaimService.php: -------------------------------------------------------------------------------- 1 | getNextPageResources(self::serviceModelClassName(self::class), $claims, $pageSize); 56 | } 57 | 58 | /** 59 | * Cancel a claim object. 60 | * 61 | * @param string $id 62 | * @return mixed 63 | */ 64 | public function cancel(string $id): mixed 65 | { 66 | $response = Requestor::request($this->client, 'post', "/claims/{$id}/cancel"); 67 | 68 | return InternalUtil::convertToEasyPostObject($this->client, $response); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /lib/EasyPost/Service/CustomsInfoService.php: -------------------------------------------------------------------------------- 1 | getNextPageResources(self::serviceModelClassName(self::class), $events, $pageSize); 45 | } 46 | 47 | /** 48 | * Retrieve all payloads for an event. 49 | * 50 | * @param string $id The event id 51 | * @return mixed 52 | */ 53 | public function retrieveAllPayloads(string $id): mixed 54 | { 55 | $url = $this->instanceUrl(self::serviceModelClassName(self::class), $id) . '/payloads'; 56 | 57 | $response = Requestor::request($this->client, 'get', $url); 58 | 59 | return InternalUtil::convertToEasyPostObject($this->client, $response); 60 | } 61 | 62 | /** 63 | * Retrieve a payload for an event. 64 | * 65 | * @param string $id The event id 66 | * @param string $payloadId The payload id 67 | * @return mixed 68 | */ 69 | public function retrievePayload(string $id, string $payloadId): mixed 70 | { 71 | $url = $this->instanceUrl(self::serviceModelClassName(self::class), $id) . '/payloads/' . $payloadId; 72 | 73 | $response = Requestor::request($this->client, 'get', $url); 74 | 75 | return InternalUtil::convertToEasyPostObject($this->client, $response); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /lib/EasyPost/Service/InsuranceService.php: -------------------------------------------------------------------------------- 1 | getNextPageResources(self::serviceModelClassName(self::class), $insurances, $pageSize); 45 | } 46 | 47 | /** 48 | * Create an insurance object. 49 | * 50 | * @param mixed $params 51 | * @return mixed 52 | */ 53 | public function create(mixed $params = null): mixed 54 | { 55 | if (!isset($params['insurance']) || !is_array($params['insurance'])) { 56 | $clone = $params; 57 | unset($params); 58 | $params['insurance'] = $clone; 59 | } 60 | 61 | return self::createResource(self::serviceModelClassName(self::class), $params); 62 | } 63 | 64 | /** 65 | * Refund an insurance object. 66 | * 67 | * @param string $id 68 | * @return mixed 69 | */ 70 | public function refund(string $id): mixed 71 | { 72 | $response = Requestor::request($this->client, 'post', "/insurances/{$id}/refund"); 73 | 74 | return InternalUtil::convertToEasyPostObject($this->client, $response); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /lib/EasyPost/Service/OrderService.php: -------------------------------------------------------------------------------- 1 | instanceUrl(self::serviceModelClassName(self::class), $id) . '/rates'; 52 | $response = Requestor::request($this->client, 'get', $url, $params); 53 | 54 | return InternalUtil::convertToEasyPostObject($this->client, $response); 55 | } 56 | 57 | /** 58 | * Buy an order. 59 | * 60 | * @param string $id 61 | * @param mixed $params 62 | * @return mixed 63 | */ 64 | public function buy(string $id, mixed $params = null): mixed 65 | { 66 | if ($params instanceof Rate) { 67 | $clone = $params; 68 | unset($params); 69 | $params['carrier'] = $clone->carrier; 70 | $params['service'] = $clone->service; 71 | } 72 | 73 | $url = $this->instanceUrl(self::serviceModelClassName(self::class), $id) . '/buy'; 74 | $response = Requestor::request($this->client, 'post', $url, $params); 75 | 76 | return InternalUtil::convertToEasyPostObject($this->client, $response); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /lib/EasyPost/Service/ParcelService.php: -------------------------------------------------------------------------------- 1 | getNextPageResources(self::serviceModelClassName(self::class), $pickups, $pageSize); 45 | } 46 | 47 | /** 48 | * Create a pickup. 49 | * 50 | * @param mixed $params 51 | * @return mixed 52 | */ 53 | public function create(mixed $params = null): mixed 54 | { 55 | if (!isset($params['pickup']) || !is_array($params['pickup'])) { 56 | $clone = $params; 57 | unset($params); 58 | $params['pickup'] = $clone; 59 | } 60 | 61 | return self::createResource(self::serviceModelClassName(self::class), $params); 62 | } 63 | 64 | /** 65 | * Buy a pickup. 66 | * 67 | * @param string $id 68 | * @param mixed $params 69 | * @return mixed 70 | */ 71 | public function buy(string $id, mixed $params = null): mixed 72 | { 73 | $url = $this->instanceUrl(self::serviceModelClassName(self::class), $id) . '/buy'; 74 | $response = Requestor::request($this->client, 'post', $url, $params); 75 | 76 | return InternalUtil::convertToEasyPostObject($this->client, $response); 77 | } 78 | 79 | /** 80 | * Cancel a pickup. 81 | * 82 | * @param string $id 83 | * @param mixed $params 84 | * @return mixed 85 | */ 86 | public function cancel(string $id, mixed $params = null): mixed 87 | { 88 | $url = $this->instanceUrl(self::serviceModelClassName(self::class), $id) . '/cancel'; 89 | $response = Requestor::request($this->client, 'post', $url, $params); 90 | 91 | return InternalUtil::convertToEasyPostObject($this->client, $response); 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /lib/EasyPost/Service/RateService.php: -------------------------------------------------------------------------------- 1 | getNextPageResources(self::serviceModelClassName(self::class), $refunds, $pageSize); 42 | } 43 | 44 | /** 45 | * Create a refund. 46 | * 47 | * @param mixed $params 48 | * @return mixed 49 | */ 50 | public function create(mixed $params = null): mixed 51 | { 52 | if (!isset($params['refund']) || !is_array($params['refund'])) { 53 | $clone = $params; 54 | unset($params); 55 | $params['refund'] = $clone; 56 | } 57 | 58 | return self::createResource(self::serviceModelClassName(self::class), $params); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /lib/EasyPost/Service/ScanFormService.php: -------------------------------------------------------------------------------- 1 | getNextPageResources(self::serviceModelClassName(self::class), $scanforms, $pageSize); 42 | } 43 | 44 | /** 45 | * Create a scanform. 46 | * 47 | * @param mixed $params 48 | * @return mixed 49 | */ 50 | public function create(mixed $params = null): mixed 51 | { 52 | return self::createResource(self::serviceModelClassName(self::class), $params); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /lib/EasyPost/Service/SmartRateService.php: -------------------------------------------------------------------------------- 1 | client, 'post', '/smartrate/deliver_on', $params); 24 | 25 | return InternalUtil::convertToEasyPostObject($this->client, $response); 26 | } 27 | 28 | /** 29 | * Retrieve the estimated delivery date of each carrier-service level combination via the 30 | * Smart Deliver By API, based on a specific ship date and origin-destination postal code pair. 31 | * 32 | * @param mixed $params 33 | * @return mixed 34 | */ 35 | public function estimateDeliveryDate(mixed $params = null): mixed 36 | { 37 | $response = Requestor::request($this->client, 'post', '/smartrate/deliver_by', $params); 38 | 39 | return InternalUtil::convertToEasyPostObject($this->client, $response); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /lib/EasyPost/Service/TrackerService.php: -------------------------------------------------------------------------------- 1 | getNextPageResources(self::serviceModelClassName(self::class), $trackers, $pageSize); 45 | } 46 | 47 | /** 48 | * Create a tracker. 49 | * 50 | * @param mixed $params 51 | * @return mixed 52 | */ 53 | public function create(mixed $params = null): mixed 54 | { 55 | if (!is_array($params)) { 56 | $clone = $params; 57 | unset($params); 58 | $params['tracker']['tracking_code'] = $clone; 59 | } elseif (!isset($params['tracker']) || !is_array($params['tracker'])) { 60 | $clone = $params; 61 | unset($params); 62 | $params['tracker'] = $clone; 63 | } 64 | 65 | return self::createResource(self::serviceModelClassName(self::class), $params); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /lib/EasyPost/Service/WebhookService.php: -------------------------------------------------------------------------------- 1 | $forms 21 | * @property Insurance $insurance 22 | * @property Rate[] $rates 23 | * @property Rate $selected_rate 24 | * @property PostageLabel $postage_label 25 | * @property Message[] $messages 26 | * @property object $options 27 | * @property bool $is_return 28 | * @property string $tracking_code 29 | * @property bool $usps_zone 30 | * @property string $status 31 | * @property Tracker $tracker 32 | * @property Fee[] $fees 33 | * @property string $refund_status 34 | * @property string $batch_id 35 | * @property string $batch_status 36 | * @property string $batch_message 37 | * @property string $created_at 38 | * @property string $updated_at 39 | */ 40 | class Shipment extends EasyPostObject 41 | { 42 | /** 43 | * Get the lowest rate for the shipment. 44 | * 45 | * To exclude a carrier or service, prepend the string with `!`. 46 | * 47 | * @param array|null $carriers 48 | * @param array|null $services 49 | * @return Rate 50 | */ 51 | public function lowestRate(?array $carriers = [], ?array $services = []): Rate 52 | { 53 | /** @var Rate $lowestRate */ 54 | $lowestRate = InternalUtil::getLowestObjectRate($this, $carriers, $services); 55 | 56 | return $lowestRate; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /lib/EasyPost/TaxIdentifier.php: -------------------------------------------------------------------------------- 1 | $custom_headers 13 | */ 14 | class Webhook extends EasyPostObject 15 | { 16 | } 17 | -------------------------------------------------------------------------------- /phpstan.neon: -------------------------------------------------------------------------------- 1 | parameters: 2 | level: 8 3 | paths: 4 | - lib 5 | - test 6 | treatPhpDocTypesAsCertain: false 7 | -------------------------------------------------------------------------------- /phpunit.xml.dist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | ./test/EasyPost/ 6 | 7 | 8 | 9 | 10 | 11 | ./lib/EasyPost/ 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /test/EasyPost/ApiKeyTest.php: -------------------------------------------------------------------------------- 1 | apiKeys->all(); 37 | 38 | $this->assertContainsOnlyInstancesOf(ApiKey::class, $apiKeys['keys']); 39 | foreach ($apiKeys['children'] as $child) { 40 | $this->assertContainsOnlyInstancesOf(ApiKey::class, $child['keys']); 41 | } 42 | } 43 | 44 | /** 45 | * Test retrieving the authenticated user's API keys. 46 | */ 47 | public function testAuthenticatedUserApiKeys(): void 48 | { 49 | TestUtil::setupCassette('apiKeys/authenticatedUserApiKeys.yml'); 50 | 51 | $user = self::$client->user->retrieveMe(); 52 | 53 | $apiKeys = self::$client->apiKeys->retrieveApiKeysForUser($user->id); 54 | 55 | $this->assertContainsOnlyInstancesOf(ApiKey::class, $apiKeys); 56 | } 57 | 58 | /** 59 | * Test retrieving the authenticated user's API keys. 60 | */ 61 | public function testChildUserApiKeys(): void 62 | { 63 | TestUtil::setupCassette('apiKeys/childUserApiKeys.yml'); 64 | 65 | $user = self::$client->user->create([ 66 | 'name' => 'Test User', 67 | ]); 68 | $childUser = self::$client->user->retrieve($user->id); 69 | 70 | $apiKeys = self::$client->apiKeys->retrieveApiKeysForUser($childUser->id); 71 | 72 | $this->assertContainsOnlyInstancesOf(ApiKey::class, $apiKeys); 73 | 74 | // Delete the user once done so we don't pollute with hundreds of child users 75 | self::$client->user->delete($childUser->id); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /test/EasyPost/BetaRateTest.php: -------------------------------------------------------------------------------- 1 | betaRate->retrieveStatelessRates(Fixture::basicShipment()); 39 | 40 | $this->assertContainsOnlyInstancesOf(Rate::class, $statelessRates); 41 | } 42 | 43 | /** 44 | * Test retrieving lowest stateless rate. 45 | */ 46 | public function testRetrieveLowestStatelessRate(): void 47 | { 48 | TestUtil::setupCassette('beta/rate/retrieveLowestStatelessRates.yml'); 49 | 50 | $statelessRates = self::$client->betaRate->retrieveStatelessRates(Fixture::basicShipment()); 51 | 52 | $lowestStatelessRate = Util::getLowestStatelessRate($statelessRates); 53 | 54 | $this->assertEquals('GroundAdvantage', $lowestStatelessRate->service); 55 | 56 | try { 57 | $lowestStatelessRate = Util::getLowestStatelessRate($statelessRates, ['invalidCarrier']); 58 | } catch (EasyPostException $error) { 59 | $this->assertEquals('No rates found.', $error->getMessage()); 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /test/EasyPost/CarrierMetadataTest.php: -------------------------------------------------------------------------------- 1 | carrierMetadata->retrieve(); 36 | 37 | // Assert we get multiple carriers 38 | $uspsFound = false; 39 | $fedexFound = false; 40 | foreach ($carrierMetadata as $carrier) { 41 | if ($carrier->name == 'usps') { 42 | $uspsFound = true; 43 | } 44 | if ($carrier->name == 'fedex') { 45 | $fedexFound = true; 46 | } 47 | if ($uspsFound && $fedexFound) { 48 | break; 49 | } 50 | } 51 | 52 | $this->assertTrue($uspsFound); 53 | $this->assertTrue($fedexFound); 54 | } 55 | 56 | /** 57 | * Tests that we can retrieve metadata based on the filters provided. 58 | */ 59 | public function testRetrieveCarrierMetadataWithFilters(): void 60 | { 61 | TestUtil::setupCassette('carrier_metadata/retrieveCarrierMetadataWithFilters.yml'); 62 | 63 | $carrierMetadata = self::$client->carrierMetadata->retrieve( 64 | ['usps'], 65 | ['service_levels', 'predefined_packages'], 66 | ); 67 | 68 | // Assert we get the single carrier we asked for and only the types we asked for 69 | $uspsFound = false; 70 | foreach ($carrierMetadata as $carrier) { 71 | if ($carrier->name == 'usps') { 72 | $uspsFound = true; 73 | break; 74 | } 75 | } 76 | 77 | $this->assertTrue($uspsFound); 78 | $this->assertEquals(1, count($carrierMetadata)); 79 | $this->assertNotNull($carrierMetadata[0]['service_levels']); 80 | $this->assertNotNull($carrierMetadata[0]['predefined_packages']); 81 | $this->assertNull($carrierMetadata[0]['supported_features']); 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /test/EasyPost/CustomsInfoTest.php: -------------------------------------------------------------------------------- 1 | customsInfo->create(Fixture::basicCustomsInfo()); 37 | 38 | $this->assertInstanceOf(CustomsInfo::class, $customsInfo); 39 | $this->assertStringMatchesFormat('cstinfo_%s', $customsInfo->id); 40 | $this->assertEquals('NOEEI 30.37(a)', $customsInfo->eel_pfc); 41 | } 42 | 43 | /** 44 | * Test retrieving a CustomsInfo. 45 | */ 46 | public function testRetrieve(): void 47 | { 48 | TestUtil::setupCassette('customs_info/retrieve.yml'); 49 | 50 | $customsInfo = self::$client->customsInfo->create(Fixture::basicCustomsInfo()); 51 | 52 | $retrievedCustomsInfo = self::$client->customsInfo->retrieve($customsInfo->id); 53 | 54 | $this->assertInstanceOf(CustomsInfo::class, $retrievedCustomsInfo); 55 | $this->assertEquals($customsInfo, $retrievedCustomsInfo); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /test/EasyPost/CustomsItemTest.php: -------------------------------------------------------------------------------- 1 | customsItem->create(Fixture::basicCustomsItem()); 37 | 38 | $this->assertInstanceOf(CustomsItem::class, $customsItem); 39 | $this->assertStringMatchesFormat('cstitem_%s', $customsItem->id); 40 | $this->assertEquals('23.25', $customsItem->value); 41 | } 42 | 43 | /** 44 | * Test retrieving a CustomsItem. 45 | */ 46 | public function testRetrieve(): void 47 | { 48 | TestUtil::setupCassette('customs_items/retrieve.yml'); 49 | 50 | $customsItem = self::$client->customsItem->create(Fixture::basicCustomsItem()); 51 | 52 | $retrievedCustomsItem = self::$client->customsItem->retrieve($customsItem->id); 53 | 54 | $this->assertInstanceOf(CustomsItem::class, $retrievedCustomsItem); 55 | $this->assertEquals($customsItem, $retrievedCustomsItem); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /test/EasyPost/EasyPostClientTest.php: -------------------------------------------------------------------------------- 1 | getApiKey(); 18 | 19 | $apiKey2 = '456'; 20 | $client2 = new EasyPostClient($apiKey2); 21 | $clientApiKey2 = $client2->getApiKey(); 22 | 23 | $this->assertEquals($apiKey1, $clientApiKey1); 24 | $this->assertEquals($apiKey2, $clientApiKey2); 25 | } 26 | 27 | /** 28 | * Test setting and getting the API base. 29 | */ 30 | public function testApiBase(): void 31 | { 32 | $apiBase = 'http://example.com'; 33 | 34 | $client = new EasyPostClient((string)getenv('EASYPOST_TEST_API_KEY'), 60.0, $apiBase); 35 | $clientApiBase = $client->getApiBase(); 36 | 37 | $this->assertEquals($apiBase, $clientApiBase); 38 | } 39 | 40 | /** 41 | * Test setting and getting the timeout. 42 | */ 43 | public function testTimeout(): void 44 | { 45 | $timeout = 1.0; 46 | 47 | $client = new EasyPostClient((string)getenv('EASYPOST_TEST_API_KEY'), $timeout); 48 | $clientTimeout = $client->getTimeout(); 49 | 50 | $this->assertEquals($timeout, $clientTimeout); 51 | } 52 | 53 | /** 54 | * Test invalid property (service) called on an EasyPostClient. 55 | */ 56 | public function testInvalidServiceProperty(): void 57 | { 58 | try { 59 | $client = new EasyPostClient('123'); 60 | $client->invalidProperty; // @phpstan-ignore-line 61 | } catch (EasyPostException $error) { 62 | $this->assertEquals( 63 | 'EasyPost Notice: Undefined property of EasyPostClient instance: invalidProperty', 64 | $error->getMessage() 65 | ); 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /test/EasyPost/EasyPostObjectTest.php: -------------------------------------------------------------------------------- 1 | name); 28 | 29 | $this->assertTrue($isset); 30 | } 31 | 32 | /** 33 | * Test using `get` magic method with an invalid property. 34 | */ 35 | public function testGetMagicMethodInvalidProperty(): void 36 | { 37 | $object = InternalUtil::convertToEasyPostObject(self::$client, Fixture::caAddress1()); 38 | 39 | $invalidProperty = $object->invalidProperty; 40 | 41 | // TODO: This doesn't capture the `error_log()` call correctly, refactor the code so we can test this output 42 | $this->assertNull($invalidProperty); 43 | } 44 | 45 | /** 46 | * Tests that we can print an object correctly. 47 | */ 48 | public function testPrintObject(): void 49 | { 50 | $object = InternalUtil::convertToEasyPostObject(self::$client, Fixture::caAddress1()); 51 | 52 | echo $object; 53 | $this->expectOutputString('{ 54 | "name": "Jack Sparrow", 55 | "street1": "388 Townsend St", 56 | "street2": "Apt 20", 57 | "city": "San Francisco", 58 | "state": "CA", 59 | "zip": "94107", 60 | "country": "US", 61 | "email": "test@example.com", 62 | "phone": "5555555555" 63 | }'); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /test/EasyPost/EndShipperTest.php: -------------------------------------------------------------------------------- 1 | endShipper->create(Fixture::caAddress1()); 37 | 38 | $this->assertInstanceOf(EndShipper::class, $endShipper); 39 | $this->assertStringMatchesFormat('es_%s', $endShipper->id); 40 | $this->assertEquals('388 TOWNSEND ST APT 20', $endShipper->street1); 41 | } 42 | 43 | /** 44 | * Test retrieving an EndShipper. 45 | */ 46 | public function testRetrieve(): void 47 | { 48 | TestUtil::setupCassette('end_shipper/retrieve.yml'); 49 | 50 | $endShipper = self::$client->endShipper->create(Fixture::caAddress1()); 51 | 52 | $retrievedEndShipper = self::$client->endShipper->retrieve($endShipper->id); 53 | 54 | $this->assertInstanceOf(EndShipper::class, $retrievedEndShipper); 55 | $this->assertEquals($endShipper->street1, $retrievedEndShipper->street1); 56 | } 57 | 58 | /** 59 | * Test retrieving all EndShippers. 60 | */ 61 | public function testAll(): void 62 | { 63 | TestUtil::setupCassette('end_shipper/all.yml'); 64 | 65 | $endShippers = self::$client->endShipper->all([ 66 | 'page_size' => Fixture::pageSize(), 67 | ]); 68 | 69 | $endShipperArray = $endShippers['end_shippers']; 70 | 71 | $this->assertLessThanOrEqual($endShipperArray, Fixture::pageSize()); 72 | $this->assertNotNull($endShippers['has_more']); 73 | $this->assertContainsOnlyInstancesOf(EndShipper::class, $endShipperArray); 74 | } 75 | 76 | /** 77 | * Test updating an EndShipper. 78 | */ 79 | public function testUpdate(): void 80 | { 81 | TestUtil::setupCassette('end_shipper/update.yml'); 82 | 83 | $endShipper = self::$client->endShipper->create(Fixture::caAddress1()); 84 | 85 | // All caps because API will return all caps as part of verification. 86 | $newName = 'NEW NAME'; 87 | 88 | $params = [ 89 | 'name' => $newName, 90 | 'company' => 'EasyPost', 91 | 'street1' => '388 Townsend St', 92 | 'street2' => 'Apt 20', 93 | 'city' => 'San Francisco', 94 | 'state' => 'CA', 95 | 'zip' => '94107', 96 | 'country' => 'US', 97 | 'phone' => '9999999999', 98 | 'email' => 'test@example.com' 99 | ]; 100 | 101 | $updatedEndShipper = self::$client->endShipper->update($endShipper->id, $params); 102 | 103 | $this->assertInstanceOf(EndShipper::class, $updatedEndShipper); 104 | $this->assertStringMatchesFormat('es_%s', $updatedEndShipper->id); 105 | $this->assertEquals($newName, $updatedEndShipper->name); 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /test/EasyPost/HookTest.php: -------------------------------------------------------------------------------- 1 | $args 33 | */ 34 | public function requestTest(array $args): void 35 | { 36 | $this->assertEquals('post', $args['method']); 37 | $this->assertEquals('https://api.easypost.com/v2/parcels', $args['path']); 38 | $this->assertArrayHasKey('parcel', $args['request_body']); 39 | $this->assertArrayHasKey('Authorization', $args['headers']); 40 | $this->assertIsFloat($args['request_timestamp']); 41 | $this->assertEquals(13, strlen($args['request_uuid'])); 42 | } 43 | 44 | /** 45 | * Test that we fire a RequestHook prior to making an HTTP request. 46 | */ 47 | public function testRequestHooks(): void 48 | { 49 | TestUtil::setupCassette('hooks/request.yml'); 50 | 51 | self::$client->subscribeToRequestHook([$this, 'requestTest']); 52 | self::$client->parcel->create(Fixture::basicParcel()); 53 | } 54 | 55 | /** 56 | * Make assertions about a response once the ResponseHook fires. 57 | * 58 | * @param array $args 59 | */ 60 | public function responseTest(array $args): void 61 | { 62 | $this->assertEquals(201, $args['http_status']); 63 | $this->assertEquals('post', $args['method']); 64 | $this->assertEquals('https://api.easypost.com/v2/parcels', $args['path']); 65 | $this->assertNotNull(json_decode($args['response_body'], true)['object']); 66 | $this->assertArrayHasKey('location', $args['headers']); 67 | $this->assertTrue($args['response_timestamp'] > $args['request_timestamp']); 68 | $this->assertEquals(13, strlen($args['request_uuid'])); 69 | } 70 | 71 | /** 72 | * Test that we fire a ResponseHook after receiving an HTTP response. 73 | */ 74 | public function testResponseHooks(): void 75 | { 76 | TestUtil::setupCassette('hooks/response.yml'); 77 | 78 | self::$client->subscribeToResponseHook([$this, 'responseTest']); 79 | self::$client->parcel->create(Fixture::basicParcel()); 80 | } 81 | 82 | /** 83 | * This function should never run since we unsubscribe from HTTP hooks. 84 | */ 85 | public function failIfSubscribed(): void 86 | { 87 | throw new \Exception('Unsubscribing from HTTP hooks did not work as intended'); 88 | } 89 | 90 | /** 91 | * Test that we do not fire a hook once unsubscribed. 92 | */ 93 | public function testUnsubscribeHooks(): void 94 | { 95 | TestUtil::setupCassette('hooks/unsubscribe.yml'); 96 | 97 | self::$client->subscribeToRequestHook([$this, 'failIfSubscribed']); 98 | self::$client->unsubscribeFromRequestHook([$this, 'failIfSubscribed']); 99 | 100 | self::$client->subscribeToResponseHook([$this, 'failIfSubscribed']); 101 | self::$client->unsubscribeFromResponseHook([$this, 'failIfSubscribed']); 102 | 103 | self::$client->parcel->create(Fixture::basicParcel()); 104 | 105 | $this->expectNotToPerformAssertions(); 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /test/EasyPost/Mocking/MockRequest.php: -------------------------------------------------------------------------------- 1 | matchRule = $matchRule; 13 | $this->responseInfo = $responseInfo; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /test/EasyPost/Mocking/MockRequestMatchRule.php: -------------------------------------------------------------------------------- 1 | method = $method; 13 | $this->urlRegexPattern = $urlRegexPattern; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /test/EasyPost/Mocking/MockRequestResponseInfo.php: -------------------------------------------------------------------------------- 1 | statusCode = $statusCode; 14 | $this->body = $body; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /test/EasyPost/Mocking/MockingUtility.php: -------------------------------------------------------------------------------- 1 | 11 | */ 12 | public array $mockRequests; 13 | 14 | /** 15 | * Construct a new MockingUtility. 16 | * 17 | * @param array $mockRequests 18 | */ 19 | public function __construct(array $mockRequests) 20 | { 21 | $this->mockRequests = $mockRequests; 22 | } 23 | 24 | /** 25 | * Finds a matching mocked request. 26 | * 27 | * @param string $method 28 | * @param string $url 29 | * @return mixed 30 | */ 31 | public function findMatchingMockRequest($method, $url): mixed 32 | { 33 | foreach ($this->mockRequests as $mockRequest) { 34 | $methodMatches = $mockRequest->matchRule->method === '' 35 | || $mockRequest->matchRule->method === $method; 36 | $urlMatches = $mockRequest->matchRule->urlRegexPattern == '' 37 | || preg_match($mockRequest->matchRule->urlRegexPattern, $url) >= 1; // limit to exactly one match? 38 | if ($methodMatches && $urlMatches) { 39 | return $mockRequest; 40 | } 41 | } 42 | 43 | return null; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /test/EasyPost/ParcelTest.php: -------------------------------------------------------------------------------- 1 | parcel->create(Fixture::basicParcel()); 37 | 38 | $this->assertInstanceOf(Parcel::class, $parcel); 39 | $this->assertStringMatchesFormat('prcl_%s', $parcel->id); 40 | $this->assertEquals(15.4, $parcel->weight); 41 | } 42 | 43 | /** 44 | * Test retrieving a Parcel. 45 | */ 46 | public function testRetrieve(): void 47 | { 48 | TestUtil::setupCassette('parcels/retrieve.yml'); 49 | 50 | $parcel = self::$client->parcel->create(Fixture::basicParcel()); 51 | 52 | $retrievedParcel = self::$client->parcel->retrieve($parcel->id); 53 | 54 | $this->assertInstanceOf(Parcel::class, $retrievedParcel); 55 | $this->assertEquals($parcel, $retrievedParcel); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /test/EasyPost/RateTest.php: -------------------------------------------------------------------------------- 1 | shipment->create(Fixture::basicShipment()); 37 | 38 | $rate = self::$client->rate->retrieve($shipment->rates[0]['id']); 39 | 40 | $this->assertInstanceOf(Rate::class, $rate); 41 | $this->assertStringMatchesFormat('rate_%s', $rate->id); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /test/EasyPost/RefundTest.php: -------------------------------------------------------------------------------- 1 | shipment->create(Fixture::oneCallBuyShipment()); 39 | // We need to retrieve the shipment so that the tracking_code has time to populate 40 | $retrievedShipment = self::$client->shipment->retrieve($shipment->id); 41 | 42 | $refund = self::$client->refund->create([ 43 | 'carrier' => Fixture::usps(), 44 | 'tracking_codes' => [$retrievedShipment->tracking_code], 45 | ]); 46 | 47 | $this->assertStringMatchesFormat('rfnd_%s', $refund[0]->id); 48 | $this->assertEquals('submitted', $refund[0]->status); 49 | } 50 | 51 | /** 52 | * Test retrieving all refunds. 53 | */ 54 | public function testAll(): void 55 | { 56 | TestUtil::setupCassette('refunds/all.yml'); 57 | 58 | $refunds = self::$client->refund->all([ 59 | 'page_size' => Fixture::pageSize(), 60 | ]); 61 | 62 | $refundsArray = $refunds['refunds']; 63 | 64 | $this->assertLessThanOrEqual($refundsArray, Fixture::pageSize()); 65 | $this->assertNotNull($refunds['has_more']); 66 | $this->assertContainsOnlyInstancesOf(Refund::class, $refundsArray); 67 | } 68 | 69 | /** 70 | * Test retrieving next page. 71 | */ 72 | public function testGetNextPage(): void 73 | { 74 | TestUtil::setupCassette('refunds/getNextPage.yml'); 75 | 76 | try { 77 | $refunds = self::$client->refund->all([ 78 | 'page_size' => Fixture::pageSize(), 79 | ]); 80 | $nextPage = self::$client->refund->getNextPage($refunds, Fixture::pageSize()); 81 | 82 | $firstIdOfFirstPage = $refunds['refunds'][0]->id; 83 | $secondIdOfSecondPage = $nextPage['refunds'][0]->id; 84 | 85 | $this->assertNotEquals($firstIdOfFirstPage, $secondIdOfSecondPage); 86 | } catch (EndOfPaginationException $error) { 87 | // There's no second page, that's not a failure 88 | $this->expectNotToPerformAssertions(); 89 | } catch (Exception $error) { 90 | throw $error; 91 | } 92 | } 93 | 94 | /** 95 | * Test retrieving a refund. 96 | */ 97 | public function testRetrieve(): void 98 | { 99 | TestUtil::setupCassette('refunds/retrieve.yml'); 100 | 101 | $refunds = self::$client->refund->all([ 102 | 'page_size' => Fixture::pageSize(), 103 | ]); 104 | 105 | $retrievedRefund = self::$client->refund->retrieve($refunds['refunds'][0]->id); 106 | 107 | $this->assertInstanceOf(Refund::class, $retrievedRefund); 108 | $this->assertEquals($refunds['refunds'][0]->id, $retrievedRefund->id); 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /test/EasyPost/RequireTest.php: -------------------------------------------------------------------------------- 1 | expectNotToPerformAssertions(); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /test/EasyPost/ScanFormTest.php: -------------------------------------------------------------------------------- 1 | shipment->create(Fixture::oneCallBuyShipment()); 39 | 40 | $scanForm = self::$client->scanForm->create([ 41 | 'shipments' => [$shipment], 42 | ]); 43 | 44 | $this->assertInstanceOf(ScanForm::class, $scanForm); 45 | $this->assertStringMatchesFormat('sf_%s', $scanForm->id); 46 | } 47 | 48 | /** 49 | * Test retrieving a scanForm. 50 | */ 51 | public function testRetrieve(): void 52 | { 53 | TestUtil::setupCassette('scanForms/retrieve.yml'); 54 | 55 | $shipment = self::$client->shipment->create(Fixture::oneCallBuyShipment()); 56 | 57 | $scanForm = self::$client->scanForm->create([ 58 | 'shipments' => [$shipment], 59 | ]); 60 | 61 | $retrievedScanform = self::$client->scanForm->retrieve($scanForm->id); 62 | 63 | $this->assertInstanceOf(ScanForm::class, $retrievedScanform); 64 | $this->assertEquals($scanForm, $retrievedScanform); 65 | } 66 | 67 | /** 68 | * Test retrieving all scanForms. 69 | */ 70 | public function testAll(): void 71 | { 72 | TestUtil::setupCassette('scanForms/all.yml'); 73 | 74 | $scanForms = self::$client->scanForm->all([ 75 | 'page_size' => Fixture::pageSize(), 76 | ]); 77 | 78 | $scanformsArray = $scanForms['scan_forms']; 79 | 80 | $this->assertLessThanOrEqual($scanformsArray, Fixture::pageSize()); 81 | $this->assertNotNull($scanForms['has_more']); 82 | $this->assertContainsOnlyInstancesOf(ScanForm::class, $scanformsArray); 83 | } 84 | 85 | /** 86 | * Test retrieving next page. 87 | */ 88 | public function testGetNextPage(): void 89 | { 90 | TestUtil::setupCassette('scanForms/getNextPage.yml'); 91 | 92 | try { 93 | $scanforms = self::$client->scanForm->all([ 94 | 'page_size' => Fixture::pageSize(), 95 | ]); 96 | $nextPage = self::$client->scanForm->getNextPage($scanforms, Fixture::pageSize()); 97 | 98 | $firstIdOfFirstPage = $scanforms['scan_forms'][0]->id; 99 | $secondIdOfSecondPage = $nextPage['scan_forms'][0]->id; 100 | 101 | $this->assertNotEquals($firstIdOfFirstPage, $secondIdOfSecondPage); 102 | } catch (EndOfPaginationException $error) { 103 | // There's no second page, that's not a failure 104 | $this->expectNotToPerformAssertions(); 105 | } catch (Exception $error) { 106 | throw $error; 107 | } 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /test/EasyPost/SmartRateTest.php: -------------------------------------------------------------------------------- 1 | Fixture::caAddress1()['zip'], 39 | 'to_zip' => Fixture::caAddress2()['zip'], 40 | 'desired_delivery_date' => Fixture::desiredDeliveryDate(), 41 | 'carriers' => [Fixture::usps()], 42 | ]; 43 | 44 | $rates = self::$client->smartRate->recommendShipDate($params); 45 | 46 | foreach ($rates['results'] as $entry) { 47 | $this->assertTrue( 48 | isset($entry['easypost_time_in_transit_data']), 49 | 'Assertion failed: easypost_time_in_transit_data is not set.' 50 | ); 51 | } 52 | } 53 | 54 | /** 55 | * Test that we retrieve SmartRates when provided a from/to zip and planned ship date. 56 | */ 57 | public function testRetrieveEstimatedDeliveryDate(): void 58 | { 59 | TestUtil::setupCassette('smartrate/estimatedDeliveryDate.yml'); 60 | 61 | $params = [ 62 | 'from_zip' => Fixture::caAddress1()['zip'], 63 | 'to_zip' => Fixture::caAddress2()['zip'], 64 | 'planned_ship_date' => Fixture::plannedShipDate(), 65 | 'carriers' => [Fixture::usps()], 66 | ]; 67 | 68 | $rates = self::$client->smartRate->estimateDeliveryDate($params); 69 | 70 | foreach ($rates['results'] as $entry) { 71 | $this->assertTrue( 72 | isset($entry['easypost_time_in_transit_data']), 73 | 'Assertion failed: easypost_time_in_transit_data is not set.' 74 | ); 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /test/EasyPost/TestUtil.php: -------------------------------------------------------------------------------- 1 | $expirationTimestamp) { 62 | error_log("$fullCassettePath is older than $expirationDays days and has expired. Please re-record the cassette."); // phpcs:ignore 63 | } 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /test/EasyPost/UtilTest.php: -------------------------------------------------------------------------------- 1 | assertEquals('Jack Sparrow', $object['name']); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /test/bootstrap.php: -------------------------------------------------------------------------------- 1 | setCassettePath($cassetteDir) 15 | ->setStorage('yaml') 16 | ->setMode('once') 17 | ->setWhiteList(['vendor/guzzle']); 18 | 19 | $scrubbedString = ''; 20 | $scrubbedArray = []; // In PHP, this could be either an array or object 21 | 22 | define('RESPONSE_BODY_SCRUBBERS', [ 23 | ['client_ip', $scrubbedString], 24 | ['credentials', $scrubbedArray], 25 | ['email', $scrubbedString], 26 | ['fields', $scrubbedArray], 27 | ['key', $scrubbedString], 28 | ['phone_number', $scrubbedString], 29 | ['phone', $scrubbedString], 30 | ['test_credentials', $scrubbedArray], 31 | ]); 32 | 33 | VCRCleaner::enable([ 34 | 'request' => [ 35 | 'ignoreHeaders' => [ 36 | 'Authorization', 37 | 'User-Agent', 38 | ], 39 | 'ignoreQueryFields' => [ 40 | 'card', 41 | ] 42 | ], 43 | 'response' => [ 44 | 'bodyScrubbers' => [ 45 | function ($responseBody) { 46 | $responseBodyJson = json_decode($responseBody, true); 47 | $responseBodyEncoded = scrubCassette($responseBodyJson); 48 | 49 | // Re-encode the data so we can properly store it in the cassette 50 | return json_encode($responseBodyEncoded); 51 | } 52 | ], 53 | ], 54 | ]); 55 | 56 | /** 57 | * Scrub sensitive information from cassette files prior to persisting on disk. 58 | * 59 | * @param mixed $data 60 | * @return mixed 61 | */ 62 | function scrubCassette(mixed $data): mixed 63 | { 64 | if (isset($data)) { 65 | foreach (RESPONSE_BODY_SCRUBBERS as $scrubber) { 66 | $key = $scrubber[0]; 67 | $replacement = $scrubber[1]; 68 | 69 | // Root-level list scrubbing 70 | if (InternalUtil::isList($data)) { 71 | foreach ($data as $index => $item) { 72 | if (is_array($item)) { 73 | if (array_key_exists($key, $item)) { 74 | $data[$index][$key] = $replacement; 75 | } else { 76 | $data[$index] = scrubCassette($item); 77 | } 78 | } 79 | } 80 | } else { 81 | // Root-level key scrubbing 82 | if (is_array($data)) { 83 | if (array_key_exists($key, $data)) { 84 | $data[$key] = $replacement; 85 | } else { 86 | // Nested scrubbing 87 | foreach ($data as $index => $item) { 88 | if (is_array($item)) { 89 | if (InternalUtil::isList($item)) { 90 | foreach ($item as $nestedIndex => $nestedItem) { 91 | $data[$index][$nestedIndex] = scrubCassette($nestedItem); 92 | } 93 | } elseif (!InternalUtil::isList($item)) { 94 | $data[$index] = scrubCassette($item); 95 | } 96 | } 97 | } 98 | } 99 | } 100 | } 101 | } 102 | } 103 | 104 | return $data; 105 | } 106 | 107 | VCR::turnOn(); 108 | -------------------------------------------------------------------------------- /test/cassettes/addresses/create.yml: -------------------------------------------------------------------------------- 1 | 2 | - 3 | request: 4 | method: POST 5 | url: 'https://api.easypost.com/v2/addresses' 6 | headers: 7 | Host: api.easypost.com 8 | Expect: '' 9 | Accept-Encoding: '' 10 | Accept: application/json 11 | Authorization: '' 12 | Content-Type: application/json 13 | User-Agent: '' 14 | body: '{"address":{"name":"Jack Sparrow","street1":"388 Townsend St","street2":"Apt 20","city":"San Francisco","state":"CA","zip":"94107","country":"US","email":"test@example.com","phone":"5555555555"}}' 15 | response: 16 | status: 17 | code: 201 18 | message: Created 19 | headers: 20 | x-frame-options: SAMEORIGIN 21 | x-xss-protection: '1; mode=block' 22 | x-content-type-options: nosniff 23 | x-download-options: noopen 24 | x-permitted-cross-domain-policies: none 25 | referrer-policy: strict-origin-when-cross-origin 26 | x-ep-request-uuid: e181587766bcebf6e2b8ff730086f32e 27 | cache-control: 'private, no-cache, no-store' 28 | pragma: no-cache 29 | expires: '0' 30 | location: /api/v2/addresses/adr_3eaaf0ca5a6411efba32ac1f6bc53342 31 | content-type: 'application/json; charset=utf-8' 32 | content-length: '461' 33 | x-runtime: '0.034509' 34 | x-node: bigweb36nuq 35 | x-version-label: easypost-202408141633-8ef9a7bcc9-master 36 | x-backend: easypost 37 | x-proxied: ['intlb3nuq c0f5e722d1', 'extlb2nuq b6e1b5034c'] 38 | strict-transport-security: 'max-age=31536000; includeSubDomains; preload' 39 | body: '{"id":"adr_3eaaf0ca5a6411efba32ac1f6bc53342","object":"Address","created_at":"2024-08-14T17:40:06+00:00","updated_at":"2024-08-14T17:40:06+00:00","name":"Jack Sparrow","company":null,"street1":"388 Townsend St","street2":"Apt 20","city":"San Francisco","state":"CA","zip":"94107","country":"US","phone":"","email":"","mode":"test","carrier_facility":null,"residential":null,"federal_tax_id":null,"state_tax_id":null,"verifications":[]}' 40 | curl_info: 41 | url: 'https://api.easypost.com/v2/addresses' 42 | content_type: 'application/json; charset=utf-8' 43 | http_code: 201 44 | header_size: 759 45 | request_size: 503 46 | filetime: -1 47 | ssl_verify_result: 0 48 | redirect_count: 0 49 | total_time: 0.132585 50 | namelookup_time: 0.002263 51 | connect_time: 0.031664 52 | pretransfer_time: 0.065141 53 | size_upload: 195.0 54 | size_download: 461.0 55 | speed_download: 3477.0 56 | speed_upload: 1470.0 57 | download_content_length: 461.0 58 | upload_content_length: 195.0 59 | starttransfer_time: 0.132502 60 | redirect_time: 0.0 61 | redirect_url: '' 62 | primary_ip: 169.62.110.130 63 | certinfo: { } 64 | primary_port: 443 65 | local_ip: 192.168.1.75 66 | local_port: 52723 67 | http_version: 2 68 | protocol: 2 69 | ssl_verifyresult: 0 70 | scheme: https 71 | appconnect_time_us: 65070 72 | connect_time_us: 31664 73 | namelookup_time_us: 2263 74 | pretransfer_time_us: 65141 75 | redirect_time_us: 0 76 | starttransfer_time_us: 132502 77 | total_time_us: 132585 78 | effective_method: POST 79 | capath: '' 80 | cainfo: '' 81 | index: 0 82 | -------------------------------------------------------------------------------- /test/cassettes/batches/create.yml: -------------------------------------------------------------------------------- 1 | 2 | - 3 | request: 4 | method: POST 5 | url: 'https://api.easypost.com/v2/batches' 6 | headers: 7 | Host: api.easypost.com 8 | Expect: '' 9 | Accept-Encoding: '' 10 | Accept: application/json 11 | Authorization: '' 12 | Content-Type: application/json 13 | User-Agent: '' 14 | body: '{"batch":{"shipments":[{"from_address":{"name":"Jack Sparrow","street1":"388 Townsend St","street2":"Apt 20","city":"San Francisco","state":"CA","zip":"94107","country":"US","email":"test@example.com","phone":"5555555555"},"to_address":{"name":"Elizabeth Swan","street1":"179 N Harbor Dr","city":"Redondo Beach","state":"CA","zip":"90277","country":"US","email":"test@example.com","phone":"5555555555"},"parcel":{"length":"10","width":"8","height":"4","weight":"15.4"}}]}}' 15 | response: 16 | status: 17 | code: 200 18 | message: OK 19 | headers: 20 | x-frame-options: SAMEORIGIN 21 | x-xss-protection: '1; mode=block' 22 | x-content-type-options: nosniff 23 | x-download-options: noopen 24 | x-permitted-cross-domain-policies: none 25 | referrer-policy: strict-origin-when-cross-origin 26 | x-ep-request-uuid: e181587b66bceb9fe2b8f7d700869fd6 27 | cache-control: 'private, no-cache, no-store' 28 | pragma: no-cache 29 | expires: '0' 30 | content-type: 'application/json; charset=utf-8' 31 | content-length: '384' 32 | x-runtime: '0.056694' 33 | x-node: bigweb41nuq 34 | x-version-label: easypost-202408141633-8ef9a7bcc9-master 35 | x-backend: easypost 36 | x-proxied: ['intlb4nuq c0f5e722d1', 'extlb2nuq b6e1b5034c'] 37 | strict-transport-security: 'max-age=31536000; includeSubDomains; preload' 38 | body: '{"id":"batch_fa7dc70d080d4dccb967ecb2c6472393","object":"Batch","mode":"test","state":"creating","num_shipments":1,"reference":null,"created_at":"2024-08-14T17:38:39Z","updated_at":"2024-08-14T17:38:39Z","scan_form":null,"shipments":[],"status":{"created":0,"queued_for_purchase":0,"creation_failed":0,"postage_purchased":0,"postage_purchase_failed":0},"pickup":null,"label_url":null}' 39 | curl_info: 40 | url: 'https://api.easypost.com/v2/batches' 41 | content_type: 'application/json; charset=utf-8' 42 | http_code: 200 43 | header_size: 688 44 | request_size: 778 45 | filetime: -1 46 | ssl_verify_result: 0 47 | redirect_count: 0 48 | total_time: 0.156735 49 | namelookup_time: 0.002651 50 | connect_time: 0.032416 51 | pretransfer_time: 0.065898 52 | size_upload: 472.0 53 | size_download: 384.0 54 | speed_download: 2449.0 55 | speed_upload: 3011.0 56 | download_content_length: 384.0 57 | upload_content_length: 472.0 58 | starttransfer_time: 0.156648 59 | redirect_time: 0.0 60 | redirect_url: '' 61 | primary_ip: 169.62.110.130 62 | certinfo: { } 63 | primary_port: 443 64 | local_ip: 192.168.1.75 65 | local_port: 52592 66 | http_version: 2 67 | protocol: 2 68 | ssl_verifyresult: 0 69 | scheme: https 70 | appconnect_time_us: 65827 71 | connect_time_us: 32416 72 | namelookup_time_us: 2651 73 | pretransfer_time_us: 65898 74 | redirect_time_us: 0 75 | starttransfer_time_us: 156648 76 | total_time_us: 156735 77 | effective_method: POST 78 | capath: '' 79 | cainfo: '' 80 | index: 0 81 | -------------------------------------------------------------------------------- /test/cassettes/beta/referral_customers/addPaymentMethod.yml: -------------------------------------------------------------------------------- 1 | 2 | - 3 | request: 4 | method: POST 5 | url: 'https://api.easypost.com/beta/referral_customers/payment_method' 6 | headers: 7 | Host: api.easypost.com 8 | Expect: '' 9 | Accept-Encoding: '' 10 | Accept: application/json 11 | Authorization: '' 12 | Content-Type: application/json 13 | User-Agent: '' 14 | body: '{"payment_method":{"stripe_customer_id":"cus_123","payment_method_reference":"ba_123","priority":"primary"}}' 15 | response: 16 | status: 17 | code: 422 18 | message: 'Unprocessable Entity' 19 | headers: 20 | x-frame-options: SAMEORIGIN 21 | x-xss-protection: '1; mode=block' 22 | x-content-type-options: nosniff 23 | x-download-options: noopen 24 | x-permitted-cross-domain-policies: none 25 | referrer-policy: strict-origin-when-cross-origin 26 | x-ep-request-uuid: e181587766bcebfce2b8ffba0086fa91 27 | cache-control: 'private, no-cache, no-store' 28 | pragma: no-cache 29 | expires: '0' 30 | content-type: 'application/json; charset=utf-8' 31 | content-length: '115' 32 | x-runtime: '0.037942' 33 | vary: Origin 34 | x-node: bigweb36nuq 35 | x-version-label: easypost-202408141633-8ef9a7bcc9-master 36 | x-backend: easypost 37 | x-proxied: ['intlb4nuq c0f5e722d1', 'extlb2nuq b6e1b5034c'] 38 | strict-transport-security: 'max-age=31536000; includeSubDomains; preload' 39 | body: '{"error":{"code":"BILLING.INVALID_PAYMENT_GATEWAY_REFERENCE","message":"Invalid connect integration.","errors":[]}}' 40 | curl_info: 41 | url: 'https://api.easypost.com/beta/referral_customers/payment_method' 42 | content_type: 'application/json; charset=utf-8' 43 | http_code: 422 44 | header_size: 720 45 | request_size: 442 46 | filetime: -1 47 | ssl_verify_result: 0 48 | redirect_count: 0 49 | total_time: 0.135016 50 | namelookup_time: 0.002318 51 | connect_time: 0.032022 52 | pretransfer_time: 0.064096 53 | size_upload: 108.0 54 | size_download: 115.0 55 | speed_download: 851.0 56 | speed_upload: 799.0 57 | download_content_length: 115.0 58 | upload_content_length: 108.0 59 | starttransfer_time: 0.134988 60 | redirect_time: 0.0 61 | redirect_url: '' 62 | primary_ip: 169.62.110.130 63 | certinfo: { } 64 | primary_port: 443 65 | local_ip: 192.168.1.75 66 | local_port: 52748 67 | http_version: 2 68 | protocol: 2 69 | ssl_verifyresult: 0 70 | scheme: https 71 | appconnect_time_us: 64041 72 | connect_time_us: 32022 73 | namelookup_time_us: 2318 74 | pretransfer_time_us: 64096 75 | redirect_time_us: 0 76 | starttransfer_time_us: 134988 77 | total_time_us: 135016 78 | effective_method: POST 79 | capath: '' 80 | cainfo: '' 81 | index: 0 82 | -------------------------------------------------------------------------------- /test/cassettes/beta/referral_customers/refundByAmount.yml: -------------------------------------------------------------------------------- 1 | 2 | - 3 | request: 4 | method: POST 5 | url: 'https://api.easypost.com/beta/referral_customers/refunds' 6 | headers: 7 | Host: api.easypost.com 8 | Expect: '' 9 | Accept-Encoding: '' 10 | Accept: application/json 11 | Authorization: '' 12 | Content-Type: application/json 13 | User-Agent: '' 14 | body: '{"refund_amount":"2000"}' 15 | response: 16 | status: 17 | code: 422 18 | message: 'Unprocessable Entity' 19 | headers: 20 | x-frame-options: SAMEORIGIN 21 | x-xss-protection: '1; mode=block' 22 | x-content-type-options: nosniff 23 | x-download-options: noopen 24 | x-permitted-cross-domain-policies: none 25 | referrer-policy: strict-origin-when-cross-origin 26 | x-ep-request-uuid: e181587666bcebfde2b8ffbb0086fac0 27 | cache-control: 'private, no-cache, no-store' 28 | pragma: no-cache 29 | expires: '0' 30 | content-type: 'application/json; charset=utf-8' 31 | content-length: '147' 32 | x-runtime: '0.410398' 33 | vary: Origin 34 | x-node: bigweb42nuq 35 | x-version-label: easypost-202408141633-8ef9a7bcc9-master 36 | x-backend: easypost 37 | x-proxied: ['intlb3nuq c0f5e722d1', 'extlb2nuq b6e1b5034c'] 38 | strict-transport-security: 'max-age=31536000; includeSubDomains; preload' 39 | body: '{"error":{"code":"TRANSACTION.AMOUNT_INVALID","message":"Refund amount is invalid. Please use a valid amount or escalate to finance.","errors":[]}}' 40 | curl_info: 41 | url: 'https://api.easypost.com/beta/referral_customers/refunds' 42 | content_type: 'application/json; charset=utf-8' 43 | http_code: 422 44 | header_size: 720 45 | request_size: 350 46 | filetime: -1 47 | ssl_verify_result: 0 48 | redirect_count: 0 49 | total_time: 0.518428 50 | namelookup_time: 0.002452 51 | connect_time: 0.035385 52 | pretransfer_time: 0.070951 53 | size_upload: 24.0 54 | size_download: 147.0 55 | speed_download: 283.0 56 | speed_upload: 46.0 57 | download_content_length: 147.0 58 | upload_content_length: 24.0 59 | starttransfer_time: 0.518348 60 | redirect_time: 0.0 61 | redirect_url: '' 62 | primary_ip: 169.62.110.130 63 | certinfo: { } 64 | primary_port: 443 65 | local_ip: 192.168.1.75 66 | local_port: 52749 67 | http_version: 2 68 | protocol: 2 69 | ssl_verifyresult: 0 70 | scheme: https 71 | appconnect_time_us: 70894 72 | connect_time_us: 35385 73 | namelookup_time_us: 2452 74 | pretransfer_time_us: 70951 75 | redirect_time_us: 0 76 | starttransfer_time_us: 518348 77 | total_time_us: 518428 78 | effective_method: POST 79 | capath: '' 80 | cainfo: '' 81 | index: 0 82 | -------------------------------------------------------------------------------- /test/cassettes/beta/referral_customers/refundByPaymentLog.yml: -------------------------------------------------------------------------------- 1 | 2 | - 3 | request: 4 | method: POST 5 | url: 'https://api.easypost.com/beta/referral_customers/refunds' 6 | headers: 7 | Host: api.easypost.com 8 | Expect: '' 9 | Accept-Encoding: '' 10 | Accept: application/json 11 | Authorization: '' 12 | Content-Type: application/json 13 | User-Agent: '' 14 | body: '{"payment_log_id":"paylog_123"}' 15 | response: 16 | status: 17 | code: 422 18 | message: 'Unprocessable Entity' 19 | headers: 20 | x-frame-options: SAMEORIGIN 21 | x-xss-protection: '1; mode=block' 22 | x-content-type-options: nosniff 23 | x-download-options: noopen 24 | x-permitted-cross-domain-policies: none 25 | referrer-policy: strict-origin-when-cross-origin 26 | x-ep-request-uuid: e181587766bcebfde2b8ffd30086fb5b 27 | cache-control: 'private, no-cache, no-store' 28 | pragma: no-cache 29 | expires: '0' 30 | content-type: 'application/json; charset=utf-8' 31 | content-length: '117' 32 | x-runtime: '0.031455' 33 | vary: Origin 34 | x-node: bigweb43nuq 35 | x-version-label: easypost-202408141633-8ef9a7bcc9-master 36 | x-backend: easypost 37 | x-canary: direct 38 | x-proxied: ['intlb3nuq c0f5e722d1', 'extlb2nuq b6e1b5034c'] 39 | strict-transport-security: 'max-age=31536000; includeSubDomains; preload' 40 | body: '{"error":{"code":"TRANSACTION.DOES_NOT_EXIST","message":"We could not find a transaction with that id.","errors":[]}}' 41 | curl_info: 42 | url: 'https://api.easypost.com/beta/referral_customers/refunds' 43 | content_type: 'application/json; charset=utf-8' 44 | http_code: 422 45 | header_size: 738 46 | request_size: 357 47 | filetime: -1 48 | ssl_verify_result: 0 49 | redirect_count: 0 50 | total_time: 0.131149 51 | namelookup_time: 0.002073 52 | connect_time: 0.032084 53 | pretransfer_time: 0.065987 54 | size_upload: 31.0 55 | size_download: 117.0 56 | speed_download: 892.0 57 | speed_upload: 236.0 58 | download_content_length: 117.0 59 | upload_content_length: 31.0 60 | starttransfer_time: 0.131078 61 | redirect_time: 0.0 62 | redirect_url: '' 63 | primary_ip: 169.62.110.130 64 | certinfo: { } 65 | primary_port: 443 66 | local_ip: 192.168.1.75 67 | local_port: 52750 68 | http_version: 2 69 | protocol: 2 70 | ssl_verifyresult: 0 71 | scheme: https 72 | appconnect_time_us: 65917 73 | connect_time_us: 32084 74 | namelookup_time_us: 2073 75 | pretransfer_time_us: 65987 76 | redirect_time_us: 0 77 | starttransfer_time_us: 131078 78 | total_time_us: 131149 79 | effective_method: POST 80 | capath: '' 81 | cainfo: '' 82 | index: 0 83 | -------------------------------------------------------------------------------- /test/cassettes/beta/referral_customers/testCreateBankAccountClientSecret.yml: -------------------------------------------------------------------------------- 1 | 2 | - 3 | request: 4 | method: POST 5 | url: 'https://api.easypost.com/beta/financial_connections_sessions' 6 | headers: 7 | Host: api.easypost.com 8 | Expect: '' 9 | Accept-Encoding: '' 10 | Accept: application/json 11 | Authorization: '' 12 | Content-Type: application/json 13 | User-Agent: '' 14 | body: '[]' 15 | response: 16 | status: 17 | code: 201 18 | message: Created 19 | headers: 20 | x-frame-options: SAMEORIGIN 21 | x-xss-protection: '1; mode=block' 22 | x-content-type-options: nosniff 23 | x-download-options: noopen 24 | x-permitted-cross-domain-policies: none 25 | referrer-policy: strict-origin-when-cross-origin 26 | x-ep-request-uuid: 61550bae67dafec5e2b7eaad005c8c0a 27 | cache-control: 'private, no-cache, no-store' 28 | pragma: no-cache 29 | expires: '0' 30 | content-type: 'application/json; charset=utf-8' 31 | content-length: '65' 32 | x-runtime: '0.448738' 33 | vary: Origin 34 | x-node: bigweb35nuq 35 | x-version-label: easypost-202503182355-b9c2645d96-master 36 | x-backend: easypost 37 | x-proxied: ['intlb3nuq 284c5d344a', 'extlb2nuq 99aac35317'] 38 | strict-transport-security: 'max-age=31536000; includeSubDomains; preload' 39 | body: '{"client_secret":"fcsess_client_secret_TNbZVFK3BoA4sTsNOnS2bi9a"}' 40 | curl_info: 41 | url: 'https://api.easypost.com/beta/financial_connections_sessions' 42 | content_type: 'application/json; charset=utf-8' 43 | http_code: 201 44 | header_size: 706 45 | request_size: 330 46 | filetime: -1 47 | ssl_verify_result: 0 48 | redirect_count: 0 49 | total_time: 0.55644 50 | namelookup_time: 0.002442 51 | connect_time: 0.035598 52 | pretransfer_time: 0.072181 53 | size_upload: 2.0 54 | size_download: 65.0 55 | speed_download: 116.0 56 | speed_upload: 3.0 57 | download_content_length: 65.0 58 | upload_content_length: 2.0 59 | starttransfer_time: 0.5564 60 | redirect_time: 0.0 61 | redirect_url: '' 62 | primary_ip: 169.62.110.130 63 | certinfo: { } 64 | primary_port: 443 65 | local_ip: 192.168.1.75 66 | local_port: 50800 67 | http_version: 2 68 | protocol: 2 69 | ssl_verifyresult: 0 70 | scheme: https 71 | appconnect_time_us: 72134 72 | connect_time_us: 35598 73 | namelookup_time_us: 2442 74 | pretransfer_time_us: 72181 75 | redirect_time_us: 0 76 | starttransfer_time_us: 556400 77 | posttransfer_time_us: 72181 78 | total_time_us: 556440 79 | effective_method: POST 80 | capath: '' 81 | cainfo: '' 82 | index: 0 83 | -------------------------------------------------------------------------------- /test/cassettes/beta/referral_customers/testCreateCreditCardClientSecret.yml: -------------------------------------------------------------------------------- 1 | 2 | - 3 | request: 4 | method: POST 5 | url: 'https://api.easypost.com/beta/setup_intents' 6 | headers: 7 | Host: api.easypost.com 8 | Expect: '' 9 | Accept-Encoding: '' 10 | Accept: application/json 11 | Authorization: '' 12 | Content-Type: application/json 13 | User-Agent: '' 14 | body: '[]' 15 | response: 16 | status: 17 | code: 200 18 | message: OK 19 | headers: 20 | x-frame-options: SAMEORIGIN 21 | x-xss-protection: '1; mode=block' 22 | x-content-type-options: nosniff 23 | x-download-options: noopen 24 | x-permitted-cross-domain-policies: none 25 | referrer-policy: strict-origin-when-cross-origin 26 | x-ep-request-uuid: d11de88f67dafe25e2b7e71a005a76ba 27 | cache-control: 'private, no-cache, no-store' 28 | pragma: no-cache 29 | expires: '0' 30 | content-type: 'application/json; charset=utf-8' 31 | content-length: '88' 32 | x-runtime: '0.461817' 33 | vary: Origin 34 | x-node: bigweb38nuq 35 | x-version-label: easypost-202503182355-b9c2645d96-master 36 | x-backend: easypost 37 | x-proxied: ['intlb4nuq 284c5d344a', 'extlb1nuq 99aac35317'] 38 | strict-transport-security: 'max-age=31536000; includeSubDomains; preload' 39 | body: '{"client_secret":"seti_0R4QNNDqT4huGUvdVVF6bhFP_secret_RyN7QcwUJrRfMjmWUXJNUXf5czGbXxd"}' 40 | curl_info: 41 | url: 'https://api.easypost.com/beta/setup_intents' 42 | content_type: 'application/json; charset=utf-8' 43 | http_code: 200 44 | header_size: 701 45 | request_size: 313 46 | filetime: -1 47 | ssl_verify_result: 0 48 | redirect_count: 0 49 | total_time: 0.662147 50 | namelookup_time: 0.08618 51 | connect_time: 0.119883 52 | pretransfer_time: 0.162125 53 | size_upload: 2.0 54 | size_download: 88.0 55 | speed_download: 132.0 56 | speed_upload: 3.0 57 | download_content_length: 88.0 58 | upload_content_length: 2.0 59 | starttransfer_time: 0.662101 60 | redirect_time: 0.0 61 | redirect_url: '' 62 | primary_ip: 169.62.110.131 63 | certinfo: { } 64 | primary_port: 443 65 | local_ip: 192.168.1.75 66 | local_port: 50759 67 | http_version: 2 68 | protocol: 2 69 | ssl_verifyresult: 0 70 | scheme: https 71 | appconnect_time_us: 162056 72 | connect_time_us: 119883 73 | namelookup_time_us: 86180 74 | pretransfer_time_us: 162125 75 | redirect_time_us: 0 76 | starttransfer_time_us: 662101 77 | posttransfer_time_us: 162124 78 | total_time_us: 662147 79 | effective_method: POST 80 | capath: '' 81 | cainfo: '' 82 | index: 0 83 | -------------------------------------------------------------------------------- /test/cassettes/customs_items/create.yml: -------------------------------------------------------------------------------- 1 | 2 | - 3 | request: 4 | method: POST 5 | url: 'https://api.easypost.com/v2/customs_items' 6 | headers: 7 | Host: api.easypost.com 8 | Expect: '' 9 | Accept-Encoding: '' 10 | Accept: application/json 11 | Authorization: '' 12 | Content-Type: application/json 13 | User-Agent: '' 14 | body: '{"customs_item":{"description":"Sweet shirts","quantity":"2","weight":"11","value":"23.25","hs_tariff_number":"654321","origin_country":"US"}}' 15 | response: 16 | status: 17 | code: 201 18 | message: Created 19 | headers: 20 | x-frame-options: SAMEORIGIN 21 | x-xss-protection: '1; mode=block' 22 | x-content-type-options: nosniff 23 | x-download-options: noopen 24 | x-permitted-cross-domain-policies: none 25 | referrer-policy: strict-origin-when-cross-origin 26 | x-ep-request-uuid: ce89011e66bcec0be2b9005b0084d4f0 27 | cache-control: 'private, no-cache, no-store' 28 | pragma: no-cache 29 | expires: '0' 30 | location: /api/v2/customs_items/cstitem_c3a2f7c1df2e46cdb14d0baf955bdb4b 31 | content-type: 'application/json; charset=utf-8' 32 | content-length: '376' 33 | x-runtime: '0.035869' 34 | x-node: bigweb39nuq 35 | x-version-label: easypost-202408141633-8ef9a7bcc9-master 36 | x-backend: easypost 37 | x-proxied: ['intlb3nuq c0f5e722d1', 'extlb1nuq b6e1b5034c'] 38 | strict-transport-security: 'max-age=31536000; includeSubDomains; preload' 39 | body: '{"id":"cstitem_c3a2f7c1df2e46cdb14d0baf955bdb4b","object":"CustomsItem","created_at":"2024-08-14T17:40:27Z","updated_at":"2024-08-14T17:40:27Z","description":"Sweet shirts","hs_tariff_number":"654321","origin_country":"US","quantity":2,"value":"23.25","weight":11,"code":null,"mode":"test","manufacturer":null,"currency":null,"eccn":null,"printed_commodity_identifier":null}' 40 | curl_info: 41 | url: 'https://api.easypost.com/v2/customs_items' 42 | content_type: 'application/json; charset=utf-8' 43 | http_code: 201 44 | header_size: 767 45 | request_size: 454 46 | filetime: -1 47 | ssl_verify_result: 0 48 | redirect_count: 0 49 | total_time: 0.148571 50 | namelookup_time: 0.00199 51 | connect_time: 0.037917 52 | pretransfer_time: 0.074554 53 | size_upload: 142.0 54 | size_download: 376.0 55 | speed_download: 2530.0 56 | speed_upload: 955.0 57 | download_content_length: 376.0 58 | upload_content_length: 142.0 59 | starttransfer_time: 0.148554 60 | redirect_time: 0.0 61 | redirect_url: '' 62 | primary_ip: 169.62.110.131 63 | certinfo: { } 64 | primary_port: 443 65 | local_ip: 192.168.1.75 66 | local_port: 52794 67 | http_version: 2 68 | protocol: 2 69 | ssl_verifyresult: 0 70 | scheme: https 71 | appconnect_time_us: 74498 72 | connect_time_us: 37917 73 | namelookup_time_us: 1990 74 | pretransfer_time_us: 74554 75 | redirect_time_us: 0 76 | starttransfer_time_us: 148554 77 | total_time_us: 148571 78 | effective_method: POST 79 | capath: '' 80 | cainfo: '' 81 | index: 0 82 | -------------------------------------------------------------------------------- /test/cassettes/end_shipper/create.yml: -------------------------------------------------------------------------------- 1 | 2 | - 3 | request: 4 | method: POST 5 | url: 'https://api.easypost.com/v2/end_shippers' 6 | headers: 7 | Host: api.easypost.com 8 | Expect: '' 9 | Accept-Encoding: '' 10 | Accept: application/json 11 | Authorization: '' 12 | Content-Type: application/json 13 | User-Agent: '' 14 | body: '{"address":{"name":"Jack Sparrow","street1":"388 Townsend St","street2":"Apt 20","city":"San Francisco","state":"CA","zip":"94107","country":"US","email":"test@example.com","phone":"5555555555"}}' 15 | response: 16 | status: 17 | code: 201 18 | message: Created 19 | headers: 20 | x-frame-options: SAMEORIGIN 21 | x-xss-protection: '1; mode=block' 22 | x-content-type-options: nosniff 23 | x-download-options: noopen 24 | x-permitted-cross-domain-policies: none 25 | referrer-policy: strict-origin-when-cross-origin 26 | x-ep-request-uuid: e181587b66bcec0be2b9005f00870c17 27 | cache-control: 'private, no-cache, no-store' 28 | pragma: no-cache 29 | expires: '0' 30 | content-type: 'application/json; charset=utf-8' 31 | content-length: '365' 32 | x-runtime: '0.053124' 33 | x-node: bigweb33nuq 34 | x-version-label: easypost-202408141633-8ef9a7bcc9-master 35 | x-backend: easypost 36 | x-proxied: ['intlb3nuq c0f5e722d1', 'extlb2nuq b6e1b5034c'] 37 | strict-transport-security: 'max-age=31536000; includeSubDomains; preload' 38 | body: '{"id":"es_6880eb4656df4ed5b81ba3674e415f87","object":"EndShipper","mode":"test","created_at":"2024-08-14T17:40:27+00:00","updated_at":"2024-08-14T17:40:27+00:00","name":"JACK SPARROW","company":null,"street1":"388 TOWNSEND ST APT 20","street2":"","city":"SAN FRANCISCO","state":"CA","zip":"94107-1670","country":"US","phone":"","email":""}' 39 | curl_info: 40 | url: 'https://api.easypost.com/v2/end_shippers' 41 | content_type: 'application/json; charset=utf-8' 42 | http_code: 201 43 | header_size: 693 44 | request_size: 506 45 | filetime: -1 46 | ssl_verify_result: 0 47 | redirect_count: 0 48 | total_time: 0.152128 49 | namelookup_time: 0.003002 50 | connect_time: 0.032264 51 | pretransfer_time: 0.064569 52 | size_upload: 195.0 53 | size_download: 365.0 54 | speed_download: 2399.0 55 | speed_upload: 1281.0 56 | download_content_length: 365.0 57 | upload_content_length: 195.0 58 | starttransfer_time: 0.152113 59 | redirect_time: 0.0 60 | redirect_url: '' 61 | primary_ip: 169.62.110.130 62 | certinfo: { } 63 | primary_port: 443 64 | local_ip: 192.168.1.75 65 | local_port: 52798 66 | http_version: 2 67 | protocol: 2 68 | ssl_verifyresult: 0 69 | scheme: https 70 | appconnect_time_us: 64515 71 | connect_time_us: 32264 72 | namelookup_time_us: 3002 73 | pretransfer_time_us: 64569 74 | redirect_time_us: 0 75 | starttransfer_time_us: 152113 76 | total_time_us: 152128 77 | effective_method: POST 78 | capath: '' 79 | cainfo: '' 80 | index: 0 81 | -------------------------------------------------------------------------------- /test/cassettes/errors/errors.yml: -------------------------------------------------------------------------------- 1 | 2 | - 3 | request: 4 | method: POST 5 | url: 'https://api.easypost.com/v2/shipments' 6 | headers: 7 | Host: api.easypost.com 8 | Expect: '' 9 | Accept-Encoding: '' 10 | Accept: application/json 11 | Authorization: '' 12 | Content-Type: application/json 13 | User-Agent: '' 14 | body: '[]' 15 | response: 16 | status: 17 | code: 422 18 | message: 'Unprocessable Entity' 19 | headers: 20 | x-frame-options: SAMEORIGIN 21 | x-xss-protection: '1; mode=block' 22 | x-content-type-options: nosniff 23 | x-download-options: noopen 24 | x-permitted-cross-domain-policies: none 25 | referrer-policy: strict-origin-when-cross-origin 26 | x-ep-request-uuid: e181587866bcec0de2b9037400870d63 27 | cache-control: 'private, no-cache, no-store' 28 | pragma: no-cache 29 | expires: '0' 30 | content-type: 'application/json; charset=utf-8' 31 | content-length: '139' 32 | x-runtime: '0.023497' 33 | x-node: bigweb38nuq 34 | x-version-label: easypost-202408141633-8ef9a7bcc9-master 35 | x-backend: easypost 36 | x-proxied: ['intlb3nuq c0f5e722d1', 'extlb2nuq b6e1b5034c'] 37 | strict-transport-security: 'max-age=31536000; includeSubDomains; preload' 38 | body: '{"error":{"code":"PARAMETER.REQUIRED","message":"Missing required parameter.","errors":[{"field":"shipment","message":"cannot be blank"}]}}' 39 | curl_info: 40 | url: 'https://api.easypost.com/v2/shipments' 41 | content_type: 'application/json; charset=utf-8' 42 | http_code: 422 43 | header_size: 706 44 | request_size: 308 45 | filetime: -1 46 | ssl_verify_result: 0 47 | redirect_count: 0 48 | total_time: 0.119793 49 | namelookup_time: 0.001663 50 | connect_time: 0.031202 51 | pretransfer_time: 0.063838 52 | size_upload: 2.0 53 | size_download: 139.0 54 | speed_download: 1160.0 55 | speed_upload: 16.0 56 | download_content_length: 139.0 57 | upload_content_length: 2.0 58 | starttransfer_time: 0.119769 59 | redirect_time: 0.0 60 | redirect_url: '' 61 | primary_ip: 169.62.110.130 62 | certinfo: { } 63 | primary_port: 443 64 | local_ip: 192.168.1.75 65 | local_port: 52805 66 | http_version: 2 67 | protocol: 2 68 | ssl_verifyresult: 0 69 | scheme: https 70 | appconnect_time_us: 63775 71 | connect_time_us: 31202 72 | namelookup_time_us: 1663 73 | pretransfer_time_us: 63838 74 | redirect_time_us: 0 75 | starttransfer_time_us: 119769 76 | total_time_us: 119793 77 | effective_method: POST 78 | capath: '' 79 | cainfo: '' 80 | index: 0 81 | -------------------------------------------------------------------------------- /test/cassettes/errors/errorsAlternativeFormat.yml: -------------------------------------------------------------------------------- 1 | 2 | - 3 | request: 4 | method: POST 5 | url: 'https://api.easypost.com/v2/claims' 6 | headers: 7 | Host: api.easypost.com 8 | Expect: '' 9 | Accept-Encoding: '' 10 | Accept: application/json 11 | Authorization: '' 12 | Content-Type: application/json 13 | User-Agent: '' 14 | body: '{"type":"damage","email_evidence_attachments":["data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAAAeUlEQVR42mP8\/\/8\/AwAI\/AL+4Q7AIAAAAABJRU5ErkJggg=="],"invoice_attachments":["data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAAAeUlEQVR42mP8\/\/8\/AwAI\/AL+4Q7AIAAAAABJRU5ErkJggg=="],"supporting_documentation_attachments":["data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAAAeUlEQVR42mP8\/\/8\/AwAI\/AL+4Q7AIAAAAABJRU5ErkJggg=="],"description":"Test description","contact_email":"test@example.com","tracking_code":"123"}' 15 | response: 16 | status: 17 | code: 404 18 | message: 'Not Found' 19 | headers: 20 | x-frame-options: SAMEORIGIN 21 | x-xss-protection: '1; mode=block' 22 | x-content-type-options: nosniff 23 | x-download-options: noopen 24 | x-permitted-cross-domain-policies: none 25 | referrer-policy: strict-origin-when-cross-origin 26 | x-ep-request-uuid: 764a527867b8f50be2b9fad700359f02 27 | cache-control: 'private, no-cache, no-store' 28 | pragma: no-cache 29 | expires: '0' 30 | content-type: 'application/json; charset=utf-8' 31 | content-length: '156' 32 | x-runtime: '0.028895' 33 | x-node: bigweb58nuq 34 | x-version-label: easypost-202502212131-cc7bde76a5-master 35 | x-backend: easypost 36 | x-proxied: ['intlb4nuq 51d74985a2', 'extlb1nuq 99aac35317'] 37 | strict-transport-security: 'max-age=31536000; includeSubDomains; preload' 38 | body: '{"error":{"code":"NOT_FOUND","errors":["No eligible insurance found with provided tracking code."],"message":"The requested resource could not be found."}}' 39 | curl_info: 40 | url: 'https://api.easypost.com/v2/claims' 41 | content_type: 'application/json; charset=utf-8' 42 | http_code: 404 43 | header_size: 695 44 | request_size: 886 45 | filetime: -1 46 | ssl_verify_result: 0 47 | redirect_count: 0 48 | total_time: 0.140263 49 | namelookup_time: 0.002094 50 | connect_time: 0.03625 51 | pretransfer_time: 0.07411 52 | size_upload: 581.0 53 | size_download: 156.0 54 | speed_download: 1112.0 55 | speed_upload: 4142.0 56 | download_content_length: 156.0 57 | upload_content_length: 581.0 58 | starttransfer_time: 0.140219 59 | redirect_time: 0.0 60 | redirect_url: '' 61 | primary_ip: 169.62.110.131 62 | certinfo: { } 63 | primary_port: 443 64 | local_ip: 192.168.1.75 65 | local_port: 54059 66 | http_version: 2 67 | protocol: 2 68 | ssl_verifyresult: 0 69 | scheme: https 70 | appconnect_time_us: 74056 71 | connect_time_us: 36250 72 | namelookup_time_us: 2094 73 | pretransfer_time_us: 74110 74 | redirect_time_us: 0 75 | starttransfer_time_us: 140219 76 | total_time_us: 140263 77 | effective_method: POST 78 | index: 0 79 | -------------------------------------------------------------------------------- /test/cassettes/hooks/request.yml: -------------------------------------------------------------------------------- 1 | 2 | - 3 | request: 4 | method: POST 5 | url: 'https://api.easypost.com/v2/parcels' 6 | headers: 7 | Host: api.easypost.com 8 | Expect: '' 9 | Accept-Encoding: '' 10 | Accept: application/json 11 | Authorization: '' 12 | Content-Type: application/json 13 | User-Agent: '' 14 | body: '{"parcel":{"length":"10","width":"8","height":"4","weight":"15.4"}}' 15 | response: 16 | status: 17 | code: 201 18 | message: Created 19 | headers: 20 | x-frame-options: SAMEORIGIN 21 | x-xss-protection: '1; mode=block' 22 | x-content-type-options: nosniff 23 | x-download-options: noopen 24 | x-permitted-cross-domain-policies: none 25 | referrer-policy: strict-origin-when-cross-origin 26 | x-ep-request-uuid: e181587a66bcec1be2b903b200871b4e 27 | cache-control: 'private, no-cache, no-store' 28 | pragma: no-cache 29 | expires: '0' 30 | location: /api/v2/parcels/prcl_13c7e8870ac14b53929ae2dfb871e78d 31 | content-type: 'application/json; charset=utf-8' 32 | content-length: '229' 33 | x-runtime: '0.033386' 34 | x-node: bigweb34nuq 35 | x-version-label: easypost-202408141633-8ef9a7bcc9-master 36 | x-backend: easypost 37 | x-proxied: ['intlb3nuq c0f5e722d1', 'extlb2nuq b6e1b5034c'] 38 | strict-transport-security: 'max-age=31536000; includeSubDomains; preload' 39 | body: '{"id":"prcl_13c7e8870ac14b53929ae2dfb871e78d","object":"Parcel","created_at":"2024-08-14T17:40:43Z","updated_at":"2024-08-14T17:40:43Z","length":10,"width":8,"height":4,"predefined_package":null,"weight":15.4,"mode":"test"}' 40 | curl_info: 41 | url: 'https://api.easypost.com/v2/parcels' 42 | content_type: 'application/json; charset=utf-8' 43 | http_code: 201 44 | header_size: 758 45 | request_size: 372 46 | filetime: -1 47 | ssl_verify_result: 0 48 | redirect_count: 0 49 | total_time: 0.134087 50 | namelookup_time: 0.004001 51 | connect_time: 0.033944 52 | pretransfer_time: 0.067329 53 | size_upload: 67.0 54 | size_download: 229.0 55 | speed_download: 1707.0 56 | speed_upload: 499.0 57 | download_content_length: 229.0 58 | upload_content_length: 67.0 59 | starttransfer_time: 0.134058 60 | redirect_time: 0.0 61 | redirect_url: '' 62 | primary_ip: 169.62.110.130 63 | certinfo: { } 64 | primary_port: 443 65 | local_ip: 192.168.1.75 66 | local_port: 52821 67 | http_version: 2 68 | protocol: 2 69 | ssl_verifyresult: 0 70 | scheme: https 71 | appconnect_time_us: 67267 72 | connect_time_us: 33944 73 | namelookup_time_us: 4001 74 | pretransfer_time_us: 67329 75 | redirect_time_us: 0 76 | starttransfer_time_us: 134058 77 | total_time_us: 134087 78 | effective_method: POST 79 | capath: '' 80 | cainfo: '' 81 | index: 0 82 | -------------------------------------------------------------------------------- /test/cassettes/hooks/response.yml: -------------------------------------------------------------------------------- 1 | 2 | - 3 | request: 4 | method: POST 5 | url: 'https://api.easypost.com/v2/parcels' 6 | headers: 7 | Host: api.easypost.com 8 | Expect: '' 9 | Accept-Encoding: '' 10 | Accept: application/json 11 | Authorization: '' 12 | Content-Type: application/json 13 | User-Agent: '' 14 | body: '{"parcel":{"length":"10","width":"8","height":"4","weight":"15.4"}}' 15 | response: 16 | status: 17 | code: 201 18 | message: Created 19 | headers: 20 | x-frame-options: SAMEORIGIN 21 | x-xss-protection: '1; mode=block' 22 | x-content-type-options: nosniff 23 | x-download-options: noopen 24 | x-permitted-cross-domain-policies: none 25 | referrer-policy: strict-origin-when-cross-origin 26 | x-ep-request-uuid: e181587766bcec1be2b903b300871b75 27 | cache-control: 'private, no-cache, no-store' 28 | pragma: no-cache 29 | expires: '0' 30 | location: /api/v2/parcels/prcl_33736c67f22a43a4b56e514e8b434d3a 31 | content-type: 'application/json; charset=utf-8' 32 | content-length: '229' 33 | x-runtime: '0.036926' 34 | x-node: bigweb34nuq 35 | x-version-label: easypost-202408141633-8ef9a7bcc9-master 36 | x-backend: easypost 37 | x-proxied: ['intlb4nuq c0f5e722d1', 'extlb2nuq b6e1b5034c'] 38 | strict-transport-security: 'max-age=31536000; includeSubDomains; preload' 39 | body: '{"id":"prcl_33736c67f22a43a4b56e514e8b434d3a","object":"Parcel","created_at":"2024-08-14T17:40:43Z","updated_at":"2024-08-14T17:40:43Z","length":10,"width":8,"height":4,"predefined_package":null,"weight":15.4,"mode":"test"}' 40 | curl_info: 41 | url: 'https://api.easypost.com/v2/parcels' 42 | content_type: 'application/json; charset=utf-8' 43 | http_code: 201 44 | header_size: 758 45 | request_size: 372 46 | filetime: -1 47 | ssl_verify_result: 0 48 | redirect_count: 0 49 | total_time: 0.136492 50 | namelookup_time: 0.002763 51 | connect_time: 0.032453 52 | pretransfer_time: 0.065974 53 | size_upload: 67.0 54 | size_download: 229.0 55 | speed_download: 1677.0 56 | speed_upload: 490.0 57 | download_content_length: 229.0 58 | upload_content_length: 67.0 59 | starttransfer_time: 0.136359 60 | redirect_time: 0.0 61 | redirect_url: '' 62 | primary_ip: 169.62.110.130 63 | certinfo: { } 64 | primary_port: 443 65 | local_ip: 192.168.1.75 66 | local_port: 52822 67 | http_version: 2 68 | protocol: 2 69 | ssl_verifyresult: 0 70 | scheme: https 71 | appconnect_time_us: 65904 72 | connect_time_us: 32453 73 | namelookup_time_us: 2763 74 | pretransfer_time_us: 65974 75 | redirect_time_us: 0 76 | starttransfer_time_us: 136359 77 | total_time_us: 136492 78 | effective_method: POST 79 | capath: '' 80 | cainfo: '' 81 | index: 0 82 | -------------------------------------------------------------------------------- /test/cassettes/hooks/unsubscribe.yml: -------------------------------------------------------------------------------- 1 | 2 | - 3 | request: 4 | method: POST 5 | url: 'https://api.easypost.com/v2/parcels' 6 | headers: 7 | Host: api.easypost.com 8 | Expect: '' 9 | Accept-Encoding: '' 10 | Accept: application/json 11 | Authorization: '' 12 | Content-Type: application/json 13 | User-Agent: '' 14 | body: '{"parcel":{"length":"10","width":"8","height":"4","weight":"15.4"}}' 15 | response: 16 | status: 17 | code: 201 18 | message: Created 19 | headers: 20 | x-frame-options: SAMEORIGIN 21 | x-xss-protection: '1; mode=block' 22 | x-content-type-options: nosniff 23 | x-download-options: noopen 24 | x-permitted-cross-domain-policies: none 25 | referrer-policy: strict-origin-when-cross-origin 26 | x-ep-request-uuid: e181587a66bcec1be2b903b400871b9b 27 | cache-control: 'private, no-cache, no-store' 28 | pragma: no-cache 29 | expires: '0' 30 | location: /api/v2/parcels/prcl_982ab0fcc68744d9bfb1125de796be86 31 | content-type: 'application/json; charset=utf-8' 32 | content-length: '229' 33 | x-runtime: '0.031405' 34 | x-node: bigweb53nuq 35 | x-version-label: easypost-202408141633-8ef9a7bcc9-master 36 | x-backend: easypost 37 | x-proxied: ['intlb4nuq c0f5e722d1', 'extlb2nuq b6e1b5034c'] 38 | strict-transport-security: 'max-age=31536000; includeSubDomains; preload' 39 | body: '{"id":"prcl_982ab0fcc68744d9bfb1125de796be86","object":"Parcel","created_at":"2024-08-14T17:40:44Z","updated_at":"2024-08-14T17:40:44Z","length":10,"width":8,"height":4,"predefined_package":null,"weight":15.4,"mode":"test"}' 40 | curl_info: 41 | url: 'https://api.easypost.com/v2/parcels' 42 | content_type: 'application/json; charset=utf-8' 43 | http_code: 201 44 | header_size: 758 45 | request_size: 372 46 | filetime: -1 47 | ssl_verify_result: 0 48 | redirect_count: 0 49 | total_time: 0.138536 50 | namelookup_time: 0.002139 51 | connect_time: 0.034989 52 | pretransfer_time: 0.07068 53 | size_upload: 67.0 54 | size_download: 229.0 55 | speed_download: 1652.0 56 | speed_upload: 483.0 57 | download_content_length: 229.0 58 | upload_content_length: 67.0 59 | starttransfer_time: 0.138458 60 | redirect_time: 0.0 61 | redirect_url: '' 62 | primary_ip: 169.62.110.130 63 | certinfo: { } 64 | primary_port: 443 65 | local_ip: 192.168.1.75 66 | local_port: 52823 67 | http_version: 2 68 | protocol: 2 69 | ssl_verifyresult: 0 70 | scheme: https 71 | appconnect_time_us: 70613 72 | connect_time_us: 34989 73 | namelookup_time_us: 2139 74 | pretransfer_time_us: 70680 75 | redirect_time_us: 0 76 | starttransfer_time_us: 138458 77 | total_time_us: 138536 78 | effective_method: POST 79 | capath: '' 80 | cainfo: '' 81 | index: 0 82 | -------------------------------------------------------------------------------- /test/cassettes/parcels/create.yml: -------------------------------------------------------------------------------- 1 | 2 | - 3 | request: 4 | method: POST 5 | url: 'https://api.easypost.com/v2/parcels' 6 | headers: 7 | Host: api.easypost.com 8 | Expect: '' 9 | Accept-Encoding: '' 10 | Accept: application/json 11 | Authorization: '' 12 | Content-Type: application/json 13 | User-Agent: '' 14 | body: '{"parcel":{"length":"10","width":"8","height":"4","weight":"15.4"}}' 15 | response: 16 | status: 17 | code: 201 18 | message: Created 19 | headers: 20 | x-frame-options: SAMEORIGIN 21 | x-xss-protection: '1; mode=block' 22 | x-content-type-options: nosniff 23 | x-download-options: noopen 24 | x-permitted-cross-domain-policies: none 25 | referrer-policy: strict-origin-when-cross-origin 26 | x-ep-request-uuid: e181587666bcec1ce2b903b500871bbd 27 | cache-control: 'private, no-cache, no-store' 28 | pragma: no-cache 29 | expires: '0' 30 | location: /api/v2/parcels/prcl_79a5e794d45a42ecb34da66e44225bcf 31 | content-type: 'application/json; charset=utf-8' 32 | content-length: '229' 33 | x-runtime: '0.032582' 34 | x-node: bigweb39nuq 35 | x-version-label: easypost-202408141633-8ef9a7bcc9-master 36 | x-backend: easypost 37 | x-proxied: ['intlb4nuq c0f5e722d1', 'extlb2nuq b6e1b5034c'] 38 | strict-transport-security: 'max-age=31536000; includeSubDomains; preload' 39 | body: '{"id":"prcl_79a5e794d45a42ecb34da66e44225bcf","object":"Parcel","created_at":"2024-08-14T17:40:44Z","updated_at":"2024-08-14T17:40:44Z","length":10,"width":8,"height":4,"predefined_package":null,"weight":15.4,"mode":"test"}' 40 | curl_info: 41 | url: 'https://api.easypost.com/v2/parcels' 42 | content_type: 'application/json; charset=utf-8' 43 | http_code: 201 44 | header_size: 758 45 | request_size: 372 46 | filetime: -1 47 | ssl_verify_result: 0 48 | redirect_count: 0 49 | total_time: 0.141535 50 | namelookup_time: 0.00201 51 | connect_time: 0.035048 52 | pretransfer_time: 0.072237 53 | size_upload: 67.0 54 | size_download: 229.0 55 | speed_download: 1617.0 56 | speed_upload: 473.0 57 | download_content_length: 229.0 58 | upload_content_length: 67.0 59 | starttransfer_time: 0.141457 60 | redirect_time: 0.0 61 | redirect_url: '' 62 | primary_ip: 169.62.110.130 63 | certinfo: { } 64 | primary_port: 443 65 | local_ip: 192.168.1.75 66 | local_port: 52824 67 | http_version: 2 68 | protocol: 2 69 | ssl_verifyresult: 0 70 | scheme: https 71 | appconnect_time_us: 72157 72 | connect_time_us: 35048 73 | namelookup_time_us: 2010 74 | pretransfer_time_us: 72237 75 | redirect_time_us: 0 76 | starttransfer_time_us: 141457 77 | total_time_us: 141535 78 | effective_method: POST 79 | capath: '' 80 | cainfo: '' 81 | index: 0 82 | -------------------------------------------------------------------------------- /test/cassettes/referral_customers/addBankAccountFromStripe.yml: -------------------------------------------------------------------------------- 1 | 2 | - 3 | request: 4 | method: POST 5 | url: 'https://api.easypost.com/v2/bank_accounts' 6 | headers: 7 | Host: api.easypost.com 8 | Expect: '' 9 | Accept-Encoding: '' 10 | Accept: application/json 11 | Authorization: '' 12 | Content-Type: application/json 13 | User-Agent: '' 14 | body: '{"financial_connections_id":"fca_0QAc7sDqT4huGUvdf6BahYa9","mandate_data":{"ip_address":"127.0.0.1","user_agent":"Mozilla\/5.0","accepted_at":"1722510730"},"priority":"primary"}' 15 | response: 16 | status: 17 | code: 422 18 | message: 'Unprocessable Entity' 19 | headers: 20 | x-frame-options: SAMEORIGIN 21 | x-xss-protection: '1; mode=block' 22 | x-content-type-options: nosniff 23 | x-download-options: noopen 24 | x-permitted-cross-domain-policies: none 25 | referrer-policy: strict-origin-when-cross-origin 26 | x-ep-request-uuid: 2d7028a967db16a0e2b8fc1d0012c1a4 27 | cache-control: 'private, no-cache, no-store' 28 | pragma: no-cache 29 | expires: '0' 30 | content-type: 'application/json; charset=utf-8' 31 | content-length: '161' 32 | x-runtime: '0.029711' 33 | x-node: bigweb33nuq 34 | x-version-label: easypost-202503182355-b9c2645d96-master 35 | x-backend: easypost 36 | x-proxied: ['intlb4nuq 284c5d344a', 'extlb1nuq 99aac35317'] 37 | strict-transport-security: 'max-age=31536000; includeSubDomains; preload' 38 | body: '{"error":{"code":"BANK_ACCOUNT.INVALID_PARAMS","message":"account_holder_name must be present when creating a Financial Connections payment method","errors":[]}}' 39 | curl_info: 40 | url: 'https://api.easypost.com/v2/bank_accounts' 41 | content_type: 'application/json; charset=utf-8' 42 | http_code: 422 43 | header_size: 706 44 | request_size: 488 45 | filetime: -1 46 | ssl_verify_result: 0 47 | redirect_count: 0 48 | total_time: 0.130543 49 | namelookup_time: 0.002065 50 | connect_time: 0.03258 51 | pretransfer_time: 0.06639 52 | size_upload: 177.0 53 | size_download: 161.0 54 | speed_download: 1233.0 55 | speed_upload: 1355.0 56 | download_content_length: 161.0 57 | upload_content_length: 177.0 58 | starttransfer_time: 0.130492 59 | redirect_time: 0.0 60 | redirect_url: '' 61 | primary_ip: 169.62.110.131 62 | certinfo: { } 63 | primary_port: 443 64 | local_ip: 192.168.1.75 65 | local_port: 52697 66 | http_version: 2 67 | protocol: 2 68 | ssl_verifyresult: 0 69 | scheme: https 70 | appconnect_time_us: 66311 71 | connect_time_us: 32580 72 | namelookup_time_us: 2065 73 | pretransfer_time_us: 66390 74 | redirect_time_us: 0 75 | starttransfer_time_us: 130492 76 | posttransfer_time_us: 66389 77 | total_time_us: 130543 78 | effective_method: POST 79 | capath: '' 80 | cainfo: '' 81 | index: 0 82 | -------------------------------------------------------------------------------- /test/cassettes/referral_customers/addCreditCardFromStripe.yml: -------------------------------------------------------------------------------- 1 | 2 | - 3 | request: 4 | method: POST 5 | url: 'https://api.easypost.com/v2/credit_cards' 6 | headers: 7 | Host: api.easypost.com 8 | Expect: '' 9 | Accept-Encoding: '' 10 | Accept: application/json 11 | Authorization: '' 12 | Content-Type: application/json 13 | User-Agent: '' 14 | body: '{"credit_card":{"payment_method_id":"pm_0Pn6bQDqT4huGUvd0CjpRerH","priority":"primary"}}' 15 | response: 16 | status: 17 | code: 404 18 | message: 'Not Found' 19 | headers: 20 | x-frame-options: SAMEORIGIN 21 | x-xss-protection: '1; mode=block' 22 | x-content-type-options: nosniff 23 | x-download-options: noopen 24 | x-permitted-cross-domain-policies: none 25 | referrer-policy: strict-origin-when-cross-origin 26 | x-ep-request-uuid: 2d7028ab67db169fe2b8fc1c0012c0a7 27 | cache-control: 'private, no-cache, no-store' 28 | pragma: no-cache 29 | expires: '0' 30 | content-type: 'application/json; charset=utf-8' 31 | content-length: '134' 32 | x-runtime: '0.581913' 33 | x-node: bigweb55nuq 34 | x-version-label: easypost-202503182355-b9c2645d96-master 35 | x-backend: easypost 36 | x-proxied: ['intlb4nuq 284c5d344a', 'extlb1nuq 99aac35317'] 37 | strict-transport-security: 'max-age=31536000; includeSubDomains; preload' 38 | body: '{"error":{"code":"CREDIT_CARD.NOT_FOUND","message":"Stripe::PaymentMethod does not exist for the specified reference_id","errors":[]}}' 39 | curl_info: 40 | url: 'https://api.easypost.com/v2/credit_cards' 41 | content_type: 'application/json; charset=utf-8' 42 | http_code: 404 43 | header_size: 695 44 | request_size: 397 45 | filetime: -1 46 | ssl_verify_result: 0 47 | redirect_count: 0 48 | total_time: 0.719085 49 | namelookup_time: 0.040472 50 | connect_time: 0.070849 51 | pretransfer_time: 0.103479 52 | size_upload: 88.0 53 | size_download: 134.0 54 | speed_download: 186.0 55 | speed_upload: 122.0 56 | download_content_length: 134.0 57 | upload_content_length: 88.0 58 | starttransfer_time: 0.719037 59 | redirect_time: 0.0 60 | redirect_url: '' 61 | primary_ip: 169.62.110.131 62 | certinfo: { } 63 | primary_port: 443 64 | local_ip: 192.168.1.75 65 | local_port: 52696 66 | http_version: 2 67 | protocol: 2 68 | ssl_verifyresult: 0 69 | scheme: https 70 | appconnect_time_us: 103408 71 | connect_time_us: 70849 72 | namelookup_time_us: 40472 73 | pretransfer_time_us: 103479 74 | redirect_time_us: 0 75 | starttransfer_time_us: 719037 76 | posttransfer_time_us: 103478 77 | total_time_us: 719085 78 | effective_method: POST 79 | capath: '' 80 | cainfo: '' 81 | index: 0 82 | -------------------------------------------------------------------------------- /test/cassettes/refunds/all.yml: -------------------------------------------------------------------------------- 1 | 2 | - 3 | request: 4 | method: GET 5 | url: 'https://api.easypost.com/v2/refunds?page_size=5' 6 | headers: 7 | Host: api.easypost.com 8 | Accept-Encoding: '' 9 | Accept: application/json 10 | Authorization: '' 11 | Content-Type: application/json 12 | User-Agent: '' 13 | response: 14 | status: 15 | code: 200 16 | message: OK 17 | headers: 18 | x-frame-options: SAMEORIGIN 19 | x-xss-protection: '1; mode=block' 20 | x-content-type-options: nosniff 21 | x-download-options: noopen 22 | x-permitted-cross-domain-policies: none 23 | referrer-policy: strict-origin-when-cross-origin 24 | x-ep-request-uuid: e181587c66bcebcae2b8fb590086c9fb 25 | cache-control: 'private, no-cache, no-store' 26 | pragma: no-cache 27 | expires: '0' 28 | content-type: 'application/json; charset=utf-8' 29 | content-length: '326' 30 | x-runtime: '0.049081' 31 | x-node: bigweb34nuq 32 | x-version-label: easypost-202408141633-8ef9a7bcc9-master 33 | x-backend: easypost 34 | x-proxied: ['intlb4nuq c0f5e722d1', 'extlb2nuq b6e1b5034c'] 35 | strict-transport-security: 'max-age=31536000; includeSubDomains; preload' 36 | body: '{"refunds":[{"id":"rfnd_1513d464240f447bae0485a6ac447379","object":"Refund","created_at":"2024-08-14T17:39:22Z","updated_at":"2024-08-14T17:39:22Z","tracking_code":"9400100105807075196603","confirmation_number":null,"status":"submitted","carrier":"USPS","shipment_id":"shp_c1bfabbf012845fca34e61aa50ad0d19"}],"has_more":false}' 37 | curl_info: 38 | url: 'https://api.easypost.com/v2/refunds?page_size=5' 39 | content_type: 'application/json; charset=utf-8' 40 | http_code: 200 41 | header_size: 688 42 | request_size: 296 43 | filetime: -1 44 | ssl_verify_result: 0 45 | redirect_count: 0 46 | total_time: 0.148099 47 | namelookup_time: 0.005893 48 | connect_time: 0.035196 49 | pretransfer_time: 0.066473 50 | size_upload: 0.0 51 | size_download: 326.0 52 | speed_download: 2201.0 53 | speed_upload: 0.0 54 | download_content_length: 326.0 55 | upload_content_length: 0.0 56 | starttransfer_time: 0.148079 57 | redirect_time: 0.0 58 | redirect_url: '' 59 | primary_ip: 169.62.110.130 60 | certinfo: { } 61 | primary_port: 443 62 | local_ip: 192.168.1.75 63 | local_port: 52639 64 | http_version: 2 65 | protocol: 2 66 | ssl_verifyresult: 0 67 | scheme: https 68 | appconnect_time_us: 66444 69 | connect_time_us: 35196 70 | namelookup_time_us: 5893 71 | pretransfer_time_us: 66473 72 | redirect_time_us: 0 73 | starttransfer_time_us: 148079 74 | total_time_us: 148099 75 | effective_method: GET 76 | capath: '' 77 | cainfo: '' 78 | index: 0 79 | -------------------------------------------------------------------------------- /test/cassettes/refunds/getNextPage.yml: -------------------------------------------------------------------------------- 1 | 2 | - 3 | request: 4 | method: GET 5 | url: 'https://api.easypost.com/v2/refunds?page_size=5' 6 | headers: 7 | Host: api.easypost.com 8 | Accept-Encoding: '' 9 | Accept: application/json 10 | Authorization: '' 11 | Content-Type: application/json 12 | User-Agent: '' 13 | response: 14 | status: 15 | code: 200 16 | message: OK 17 | headers: 18 | x-frame-options: SAMEORIGIN 19 | x-xss-protection: '1; mode=block' 20 | x-content-type-options: nosniff 21 | x-download-options: noopen 22 | x-permitted-cross-domain-policies: none 23 | referrer-policy: strict-origin-when-cross-origin 24 | x-ep-request-uuid: e181587966bcebcae2b8fb710086ca22 25 | cache-control: 'private, no-cache, no-store' 26 | pragma: no-cache 27 | expires: '0' 28 | content-type: 'application/json; charset=utf-8' 29 | content-length: '326' 30 | x-runtime: '0.061351' 31 | x-node: bigweb53nuq 32 | x-version-label: easypost-202408141633-8ef9a7bcc9-master 33 | x-backend: easypost 34 | x-proxied: ['intlb3nuq c0f5e722d1', 'extlb2nuq b6e1b5034c'] 35 | strict-transport-security: 'max-age=31536000; includeSubDomains; preload' 36 | body: '{"refunds":[{"id":"rfnd_1513d464240f447bae0485a6ac447379","object":"Refund","created_at":"2024-08-14T17:39:22Z","updated_at":"2024-08-14T17:39:22Z","tracking_code":"9400100105807075196603","confirmation_number":null,"status":"submitted","carrier":"USPS","shipment_id":"shp_c1bfabbf012845fca34e61aa50ad0d19"}],"has_more":false}' 37 | curl_info: 38 | url: 'https://api.easypost.com/v2/refunds?page_size=5' 39 | content_type: 'application/json; charset=utf-8' 40 | http_code: 200 41 | header_size: 688 42 | request_size: 296 43 | filetime: -1 44 | ssl_verify_result: 0 45 | redirect_count: 0 46 | total_time: 0.159475 47 | namelookup_time: 0.00435 48 | connect_time: 0.033943 49 | pretransfer_time: 0.065349 50 | size_upload: 0.0 51 | size_download: 326.0 52 | speed_download: 2044.0 53 | speed_upload: 0.0 54 | download_content_length: 326.0 55 | upload_content_length: 0.0 56 | starttransfer_time: 0.159458 57 | redirect_time: 0.0 58 | redirect_url: '' 59 | primary_ip: 169.62.110.130 60 | certinfo: { } 61 | primary_port: 443 62 | local_ip: 192.168.1.75 63 | local_port: 52640 64 | http_version: 2 65 | protocol: 2 66 | ssl_verifyresult: 0 67 | scheme: https 68 | appconnect_time_us: 65315 69 | connect_time_us: 33943 70 | namelookup_time_us: 4350 71 | pretransfer_time_us: 65349 72 | redirect_time_us: 0 73 | starttransfer_time_us: 159458 74 | total_time_us: 159475 75 | effective_method: GET 76 | capath: '' 77 | cainfo: '' 78 | index: 0 79 | -------------------------------------------------------------------------------- /test/cassettes/reports/createCustomAdditionalColumnReport.yml: -------------------------------------------------------------------------------- 1 | 2 | - 3 | request: 4 | method: POST 5 | url: 'https://api.easypost.com/v2/reports/shipment' 6 | headers: 7 | Host: api.easypost.com 8 | Expect: '' 9 | Accept-Encoding: '' 10 | Accept: application/json 11 | Authorization: '' 12 | Content-Type: application/json 13 | User-Agent: '' 14 | body: '{"start_date":"2022-04-09","end_date":"2022-04-09","type":"shipment","additional_columns":["from_name","from_company"]}' 15 | response: 16 | status: 17 | code: 201 18 | message: Created 19 | headers: 20 | x-frame-options: SAMEORIGIN 21 | x-xss-protection: '1; mode=block' 22 | x-content-type-options: nosniff 23 | x-download-options: noopen 24 | x-permitted-cross-domain-policies: none 25 | referrer-policy: strict-origin-when-cross-origin 26 | x-ep-request-uuid: e181587866bcec21e2b903db0087200c 27 | cache-control: 'private, no-cache, no-store' 28 | pragma: no-cache 29 | expires: '0' 30 | content-type: 'application/json; charset=utf-8' 31 | content-length: '283' 32 | x-runtime: '0.072261' 33 | x-node: bigweb42nuq 34 | x-version-label: easypost-202408141633-8ef9a7bcc9-master 35 | x-backend: easypost 36 | x-proxied: ['intlb4nuq c0f5e722d1', 'extlb2nuq b6e1b5034c'] 37 | strict-transport-security: 'max-age=31536000; includeSubDomains; preload' 38 | body: '{"id":"shprep_6e878f6b241740dfaa24a5846976b832","object":"ShipmentReport","created_at":"2024-08-14T17:40:49Z","updated_at":"2024-08-14T17:40:49Z","start_date":"2022-04-09","end_date":"2022-04-09","mode":"test","status":"new","url":null,"url_expires_at":null,"include_children":false}' 39 | curl_info: 40 | url: 'https://api.easypost.com/v2/reports/shipment' 41 | content_type: 'application/json; charset=utf-8' 42 | http_code: 201 43 | header_size: 693 44 | request_size: 434 45 | filetime: -1 46 | ssl_verify_result: 0 47 | redirect_count: 0 48 | total_time: 0.179315 49 | namelookup_time: 0.002126 50 | connect_time: 0.034484 51 | pretransfer_time: 0.07071 52 | size_upload: 119.0 53 | size_download: 283.0 54 | speed_download: 1578.0 55 | speed_upload: 663.0 56 | download_content_length: 283.0 57 | upload_content_length: 119.0 58 | starttransfer_time: 0.17925 59 | redirect_time: 0.0 60 | redirect_url: '' 61 | primary_ip: 169.62.110.130 62 | certinfo: { } 63 | primary_port: 443 64 | local_ip: 192.168.1.75 65 | local_port: 52839 66 | http_version: 2 67 | protocol: 2 68 | ssl_verifyresult: 0 69 | scheme: https 70 | appconnect_time_us: 70621 71 | connect_time_us: 34484 72 | namelookup_time_us: 2126 73 | pretransfer_time_us: 70710 74 | redirect_time_us: 0 75 | starttransfer_time_us: 179250 76 | total_time_us: 179315 77 | effective_method: POST 78 | capath: '' 79 | cainfo: '' 80 | index: 0 81 | -------------------------------------------------------------------------------- /test/cassettes/reports/createCustomColumnReport.yml: -------------------------------------------------------------------------------- 1 | 2 | - 3 | request: 4 | method: POST 5 | url: 'https://api.easypost.com/v2/reports/shipment' 6 | headers: 7 | Host: api.easypost.com 8 | Expect: '' 9 | Accept-Encoding: '' 10 | Accept: application/json 11 | Authorization: '' 12 | Content-Type: application/json 13 | User-Agent: '' 14 | body: '{"start_date":"2022-04-09","end_date":"2022-04-09","type":"shipment","columns":["usps_zone"]}' 15 | response: 16 | status: 17 | code: 201 18 | message: Created 19 | headers: 20 | x-frame-options: SAMEORIGIN 21 | x-xss-protection: '1; mode=block' 22 | x-content-type-options: nosniff 23 | x-download-options: noopen 24 | x-permitted-cross-domain-policies: none 25 | referrer-policy: strict-origin-when-cross-origin 26 | x-ep-request-uuid: e181587866bcec20e2b903da00871fd2 27 | cache-control: 'private, no-cache, no-store' 28 | pragma: no-cache 29 | expires: '0' 30 | content-type: 'application/json; charset=utf-8' 31 | content-length: '283' 32 | x-runtime: '0.095889' 33 | x-node: bigweb36nuq 34 | x-version-label: easypost-202408141633-8ef9a7bcc9-master 35 | x-backend: easypost 36 | x-proxied: ['intlb3nuq c0f5e722d1', 'extlb2nuq b6e1b5034c'] 37 | strict-transport-security: 'max-age=31536000; includeSubDomains; preload' 38 | body: '{"id":"shprep_add46838e7454c42898f6663924ca060","object":"ShipmentReport","created_at":"2024-08-14T17:40:49Z","updated_at":"2024-08-14T17:40:49Z","start_date":"2022-04-09","end_date":"2022-04-09","mode":"test","status":"new","url":null,"url_expires_at":null,"include_children":false}' 39 | curl_info: 40 | url: 'https://api.easypost.com/v2/reports/shipment' 41 | content_type: 'application/json; charset=utf-8' 42 | http_code: 201 43 | header_size: 693 44 | request_size: 407 45 | filetime: -1 46 | ssl_verify_result: 0 47 | redirect_count: 0 48 | total_time: 0.20506 49 | namelookup_time: 0.001803 50 | connect_time: 0.034841 51 | pretransfer_time: 0.071281 52 | size_upload: 93.0 53 | size_download: 283.0 54 | speed_download: 1380.0 55 | speed_upload: 453.0 56 | download_content_length: 283.0 57 | upload_content_length: 93.0 58 | starttransfer_time: 0.205012 59 | redirect_time: 0.0 60 | redirect_url: '' 61 | primary_ip: 169.62.110.130 62 | certinfo: { } 63 | primary_port: 443 64 | local_ip: 192.168.1.75 65 | local_port: 52838 66 | http_version: 2 67 | protocol: 2 68 | ssl_verifyresult: 0 69 | scheme: https 70 | appconnect_time_us: 71221 71 | connect_time_us: 34841 72 | namelookup_time_us: 1803 73 | pretransfer_time_us: 71281 74 | redirect_time_us: 0 75 | starttransfer_time_us: 205012 76 | total_time_us: 205060 77 | effective_method: POST 78 | capath: '' 79 | cainfo: '' 80 | index: 0 81 | -------------------------------------------------------------------------------- /test/cassettes/reports/createReport.yml: -------------------------------------------------------------------------------- 1 | 2 | - 3 | request: 4 | method: POST 5 | url: 'https://api.easypost.com/v2/reports/shipment' 6 | headers: 7 | Host: api.easypost.com 8 | Expect: '' 9 | Accept-Encoding: '' 10 | Accept: application/json 11 | Authorization: '' 12 | Content-Type: application/json 13 | User-Agent: '' 14 | body: '{"start_date":"2022-04-09","end_date":"2022-04-09","type":"shipment"}' 15 | response: 16 | status: 17 | code: 201 18 | message: Created 19 | headers: 20 | x-frame-options: SAMEORIGIN 21 | x-xss-protection: '1; mode=block' 22 | x-content-type-options: nosniff 23 | x-download-options: noopen 24 | x-permitted-cross-domain-policies: none 25 | referrer-policy: strict-origin-when-cross-origin 26 | x-ep-request-uuid: e181587966bcec20e2b903d900871fa2 27 | cache-control: 'private, no-cache, no-store' 28 | pragma: no-cache 29 | expires: '0' 30 | content-type: 'application/json; charset=utf-8' 31 | content-length: '283' 32 | x-runtime: '0.068875' 33 | x-node: bigweb39nuq 34 | x-version-label: easypost-202408141633-8ef9a7bcc9-master 35 | x-backend: easypost 36 | x-proxied: ['intlb3nuq c0f5e722d1', 'extlb2nuq b6e1b5034c'] 37 | strict-transport-security: 'max-age=31536000; includeSubDomains; preload' 38 | body: '{"id":"shprep_633d54f27c044588909ad9e7db168e2a","object":"ShipmentReport","created_at":"2024-08-14T17:40:48Z","updated_at":"2024-08-14T17:40:48Z","start_date":"2022-04-09","end_date":"2022-04-09","mode":"test","status":"new","url":null,"url_expires_at":null,"include_children":false}' 39 | curl_info: 40 | url: 'https://api.easypost.com/v2/reports/shipment' 41 | content_type: 'application/json; charset=utf-8' 42 | http_code: 201 43 | header_size: 693 44 | request_size: 383 45 | filetime: -1 46 | ssl_verify_result: 0 47 | redirect_count: 0 48 | total_time: 0.180362 49 | namelookup_time: 0.003756 50 | connect_time: 0.037045 51 | pretransfer_time: 0.073024 52 | size_upload: 69.0 53 | size_download: 283.0 54 | speed_download: 1569.0 55 | speed_upload: 382.0 56 | download_content_length: 283.0 57 | upload_content_length: 69.0 58 | starttransfer_time: 0.180327 59 | redirect_time: 0.0 60 | redirect_url: '' 61 | primary_ip: 169.62.110.130 62 | certinfo: { } 63 | primary_port: 443 64 | local_ip: 192.168.1.75 65 | local_port: 52837 66 | http_version: 2 67 | protocol: 2 68 | ssl_verifyresult: 0 69 | scheme: https 70 | appconnect_time_us: 72961 71 | connect_time_us: 37045 72 | namelookup_time_us: 3756 73 | pretransfer_time_us: 73024 74 | redirect_time_us: 0 75 | starttransfer_time_us: 180327 76 | total_time_us: 180362 77 | effective_method: POST 78 | capath: '' 79 | cainfo: '' 80 | index: 0 81 | -------------------------------------------------------------------------------- /test/cassettes/webhooks/all.yml: -------------------------------------------------------------------------------- 1 | 2 | - 3 | request: 4 | method: GET 5 | url: 'https://api.easypost.com/v2/webhooks?page_size=5' 6 | headers: 7 | Host: api.easypost.com 8 | Accept-Encoding: '' 9 | Accept: application/json 10 | Authorization: '' 11 | Content-Type: application/json 12 | User-Agent: '' 13 | response: 14 | status: 15 | code: 200 16 | message: OK 17 | headers: 18 | x-frame-options: SAMEORIGIN 19 | x-xss-protection: '1; mode=block' 20 | x-content-type-options: nosniff 21 | x-download-options: noopen 22 | x-permitted-cross-domain-policies: none 23 | referrer-policy: strict-origin-when-cross-origin 24 | x-ep-request-uuid: e181587666bcebf4e2b8ff560086f047 25 | cache-control: 'private, no-cache, no-store' 26 | pragma: no-cache 27 | expires: '0' 28 | content-type: 'application/json; charset=utf-8' 29 | content-length: '15' 30 | x-runtime: '0.036117' 31 | x-node: bigweb53nuq 32 | x-version-label: easypost-202408141633-8ef9a7bcc9-master 33 | x-backend: easypost 34 | x-proxied: ['intlb3nuq c0f5e722d1', 'extlb2nuq b6e1b5034c'] 35 | strict-transport-security: 'max-age=31536000; includeSubDomains; preload' 36 | body: '{"webhooks":[]}' 37 | curl_info: 38 | url: 'https://api.easypost.com/v2/webhooks?page_size=5' 39 | content_type: 'application/json; charset=utf-8' 40 | http_code: 200 41 | header_size: 687 42 | request_size: 297 43 | filetime: -1 44 | ssl_verify_result: 0 45 | redirect_count: 0 46 | total_time: 0.135606 47 | namelookup_time: 0.001852 48 | connect_time: 0.031639 49 | pretransfer_time: 0.066518 50 | size_upload: 0.0 51 | size_download: 15.0 52 | speed_download: 110.0 53 | speed_upload: 0.0 54 | download_content_length: 15.0 55 | upload_content_length: 0.0 56 | starttransfer_time: 0.135482 57 | redirect_time: 0.0 58 | redirect_url: '' 59 | primary_ip: 169.62.110.130 60 | certinfo: { } 61 | primary_port: 443 62 | local_ip: 192.168.1.75 63 | local_port: 52717 64 | http_version: 2 65 | protocol: 2 66 | ssl_verifyresult: 0 67 | scheme: https 68 | appconnect_time_us: 66462 69 | connect_time_us: 31639 70 | namelookup_time_us: 1852 71 | pretransfer_time_us: 66518 72 | redirect_time_us: 0 73 | starttransfer_time_us: 135482 74 | total_time_us: 135606 75 | effective_method: GET 76 | capath: '' 77 | cainfo: '' 78 | index: 0 79 | --------------------------------------------------------------------------------