Skip to content

BrianHenryIE/bh-php-bitcoinpostageinfo

Repository files navigation

PHP 8.1 PHPCS PSR-12 PHPUnit PHPStan

BitcoinPostage.info PHP API

A thin PHP wrapper for BitcoinPostage.info – a website/API which sells USPS, UPS and FedEx postage and accepts Bitcoin and Monero for payment.

composer require brianhenryie/bh-php-bitcoinpostageinfo

See:

Use

Create an instance of the API class with a PSR HTTP implementation. Guzzle is the most popular.

$httpFactory = new \GuzzleHttp\Psr7\HttpFactory();
$client      = new \GuzzleHttp\Client();

$bitcoinPostageInfo = new \BrianHenryIE\BitcoinPostageInfo\BitcoinPostageInfoAPI(
    requestFactory: $httpFactory,
    streamFactory: $httpFactory,
    client: $client,
);

All API calls require authentication:

$credentials = new \BrianHenryIE\BitcoinPostageInfo\Model\Request\Credentials(
    key: $_ENV[ 'BITCOINPOSTAGEINFO_API_KEY' ],
    secret: $_ENV[ 'BITCOINPOSTAGEINFO_API_SECRET' ],
);

Add credit to your account:

$chargeCreditsRequest = new \BrianHenryIE\BitcoinPostageInfo\Model\Request\ChargeCreditsRequest(
    credentials: $credentials,
    amount: '10.00'
);

/** @var \BrianHenryIE\BitcoinPostageInfo\Model\Response\ChargeCredits $chargeCreditsResponse */
$chargeCreditsResponse = $api->chargeCredits($chargeCreditsRequest);

$bitcoinAddressHref = 'bitcoin:' . $chargeCreditsResponse->address . '?amount=' . $chargeCreditsResponse->amount;
$bitcoinQrCode = 'https://chart.googleapis.com/chart?chs=300x300&cht=qr&chl=' . $bitcoinAddressHref . '&choe=UTF-8';

printf(
    '<a href="%s" target="_blank"><img src="%s"/><br/>Pay BitcoinPostage.info for $%s credits.</a>',
    $bitcoinAddressHref,
    $bitcoinQrCode,
    $chargeCreditsResponse->credits
);

Check your account balance:

$credits = $api->getCredits($credentials);

echo $credits->credits;

You'll need your from and to addresses and the package dimensions to get rates and to purchase labels:

$fromAddress = new \BrianHenryIE\BitcoinPostageInfo\Model\Address(
    name: 'Brian Henry',
    street: '800 N St.',
    street2: null,
    city: 'Sacramento',
    state: 'CA',
    zip: '95814',
    country: 'US',
    phone: null,
);
$toAddress = new \BrianHenryIE\BitcoinPostageInfo\Model\Address(
    name: 'Brian Henry',
    street: '1 Palace St',
    street2: 'Apartment 3',
    city: 'Dublin',
    state: 'Dublin',
    zip: 'D02 XR57',
    country: 'IE',
    phone: null,
);
$dimensions = new \BrianHenryIE\BitcoinPostageInfo\Model\Dimensions(
    weightLbs: 0,
    weightOz: 1.5,
    heightInches: 1.0,
    widthInches: 2.0,
    depthInches: 3.0,
);

Query for rates:

$ratesRequest = new \BrianHenryIE\BitcoinPostageInfo\Model\Request\GetRatesRequest(
    credentials: $credentials,
    fromAddress: $fromAddress,
    toAddress: $toAddress,
    service: new \BrianHenryIE\BitcoinPostageInfo\Model\Service(
        packageType: UspsPackage::FLAT_RATE_ENVELOPE,
    ),
    dimensions: $dimensions,
);

/** @var \BrianHenryIE\BitcoinPostageInfo\Model\Response\Rate[] $ratesResponse */
$ratesResponse = $api->getRates($ratesRequest);

$cheapest_rate = array_reduce(
    $ratesResponse,
    function (\BrianHenryIE\BitcoinPostageInfo\Model\Response\Rate $carry, \BrianHenryIE\BitcoinPostageInfo\Model\Response\Rate $rate) {
        return is_null($carry) || $rate->rate < $carry->rate ? $rate : $carry;
    },
    null
);
echo "{$cheapest_rate->currency} {$cheapest_rate->rate}";
echo $cheapest_rate->service;

International shipments require customs information:

$customs = new Customs(
    type: CustomsContentsType::GIFT,
    signer: 'Brian Henry',
    customs: [
         new \BrianHenryIE\BitcoinPostageInfo\Model\CustomsItem(
             quantity: 1,
             description: 'T-shirt',
             totalValue: '10.00',
             totalWeightOz: 20.5,
             countryCodeOfOrigin: 'US',
             hsTariffNumber: '610910',
         )
    ],
);

Purchase a label:

$createPurchaseRequest = new \BrianHenryIE\BitcoinPostageInfo\Model\Request\CreatePurchaseRequest(
    credentials: $credentials,
    fromAddress: $fromAddress,
    toAddress: $toAddress,
    service: new \BrianHenryIE\BitcoinPostageInfo\Model\Service(
        packageType: UspsPackage::FLAT_RATE_ENVELOPE,
        service: 'usps_intl_first_class_package',
    ),
    dimensions: $dimensions,
    customs: $customs,
    testMode: true,
);

/** @var \BrianHenryIE\BitcoinPostageInfo\Model\Response\Purchase $purchaseResponse */
$purchaseResponse = $api->createPurchase($createPurchaseRequest);

/** @var \BrianHenryIE\BitcoinPostageInfo\Model\Response\PurchaseItem $purchasedLabel */
$purchasedLabel = $purchaseResponse->items[0];

echo $purchasedLabel->price;
echo $purchasedLabel->filename;
echo $purchasedLabel->trackingNo;

Notes

  • Currency amounts are strings and other numbers are floats, except for weightLbs which is an int
  • A good PHP library for generating QR codes is chillerlan/php-qrcode (for the ::chargeCredits() payment address)
  • Guzzle is a great PSR HTTP library but consider Art4/WP-Requests-PSR18-Adapter if you are developing for WordPress
  • USPS will send you free flat rate envelopes and boxes. Order them online or pick them up at your local post office.

Contribute

PhpDoc is incomplete. I'm not sure the correct way to document PHP 8.0 constructor property promotion properties.

What's a better coding standard to use?

No testing has been done for UPS / FedEx.

Acknowledgements

The BitcoinPostage.info support was very quick to reply to emails and update documentation as requested.

About

Buy USPS, UPS and FedEx postage with Bitcoin and Monero.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages