A hand-rolled PHP client for the Block.io API — wallet creation, withdrawals, and transaction notifications for Bitcoin, Litecoin, and Dogecoin.
Written in 2017, when integrating cryptocurrency payments meant reading the REST docs and writing your own cURL wrapper. Preserved deliberately: two projects forked it, and the code is small enough to read end to end in a few minutes.
One class, ~120 lines. No dependencies beyond cURL.
One class, service.php, wrapping the full Block.io v2 surface as it existed at the
time. Every method funnels through a single private cRequest() that builds the URL,
issues the cURL call, and JSON-decodes the response.
| Group | Methods |
|---|---|
| Addresses | get_balance, get_new_address, get_my_addresses, get_address_balance, get_address_by_label |
| Withdrawals | withdraw, withdraw_from_addresses, withdraw_from_labels, get_network_fee_estimate |
| Archive | archive_addresses, unarchive_addresses, get_my_archived_addresses |
| Green addresses | is_green_address, is_green_transaction |
| Transactions | get_transactions |
| Webhooks | create_notification, get_notifications |
| Pricing | get_current_price |
require("service.php");
$object = new BlockIoServeice();
$address = $object->get_new_address();
print_r($address);Set $apiKey and $pin in service.php first. See example.php.
The code is unchanged from 2017 apart from one security fix, because forks depend on it. What I would do differently now, written out because the gap is the interesting part:
Credentials do not belong in source. They are class properties here. They should be read from environment variables and injected through the constructor. Block.io's own guidance is explicit that API keys and Secret PINs should never sit in config files or enter version control — the fields are blank in this repo by luck, not by design.
The Secret PIN travels in the query string. ?api_key=...&pin=... puts a
withdrawal-authorizing credential somewhere that proxies, access logs, and referrer
headers all capture. Credentials belong in a POST body.
Local signing is the right model. Current Block.io clients never transmit the PIN at
all. They derive a signing key on the client and walk prepare_transaction →
summarize_prepared_transaction → create_and_sign_transaction → submit_transaction,
so the secret never leaves the machine. This wrapper predates that design, and the
design is better.
The constructor swallows its own exception. It throws and catches inside the same block, echoes the message, and continues — so an instance with empty credentials constructs successfully and fails silently at request time. A constructor should either complete with valid state or not return.
No URL encoding on parameters. A label containing a space or & corrupts the query
string. urlencode() on each value, which is the fix I did not make in 2017.
The class name is misspelled — BlockIoServeice. Left as-is on purpose: correcting
it would break every existing fork's call sites, which is a worse outcome than a visible
typo.
CURLOPT_SSL_VERIFYPEER => false has been removed. It disabled TLS certificate
verification on requests carrying both an API key and a withdrawal PIN — a
man-in-the-middle hole on exactly the traffic that could least afford one. cURL verifies
by default, so the deletion changes nothing else. Anyone running a fork of this should
pull that change.
For current work: BlockIo/block_io-php, the official client, with local transaction signing.
MIT — see LICENSE.