Reference
Error codes, security, and quick reference.
Lookup tables for error handling, the security architecture, and copy-pasteable integration patterns.
Fire API errors
All window.fire.* methods throw FireWalletApiError on failure.
JavaScript
try {
await window.fire.getBalances();
} catch (err) {
console.log(err.name); // 'FireWalletApiError'
console.log(err.code); // 'NOT_GRANTED' | 'LOCKED' | 'INVALID_PARAMS' | 'INTERNAL_ERROR'
console.log(err.message); // Human-readable description
}
| Code | Meaning |
|---|---|
NOT_GRANTED |
Required permission scope not granted |
LOCKED |
Wallet is locked — user needs to enter PIN |
INVALID_PARAMS |
Bad or missing parameters |
INTERNAL_ERROR |
Wallet internal error or timeout |
EIP-1193 errors
Ethereum provider errors follow the EIP-1193 standard.
JavaScript
try {
await provider.request({ method: 'eth_sendTransaction', params: [tx] });
} catch (err) {
console.log(err.code); // numeric
console.log(err.message); // human-readable
}
| Code | Meaning |
|---|---|
4001 |
User rejected the request |
4200 |
Method not supported |
4902 |
Unrecognized chain ID |
-32602 |
Invalid parameters |
-32603 |
Internal/RPC error |
Security model
Key isolation
Private keys never leave the service worker. The page-injected API (window.fire) communicates through a content script bridge. No page script — including your own — can access keys.
Architecture
Your page ←→ fire-page-api.js ←→ Content script ←→ Service worker (keys here)
(MAIN) (MAIN world) (ISOLATED world) (extension process)
Trust boundaries
- The content script validates all page messages via
event.source === window - Merchant domain is extracted from Chrome's
sender.origin(not spoofable) - Read-only Ethereum calls are proxied to public RPC nodes without touching keys
- Write operations always route through a user-facing approval dialog
What you cannot do
- Access private keys or seed phrases
- Sign transactions without user approval
- Read wallet data without explicit permission grants
- Bypass the approval dialog
Quick reference: payment (address-based)
JavaScript
// 1. Request payment
const result = await window.fire.requestPayment({
recipientB58: '3Fhv7x...',
amount: '1000000',
tokenId: 1,
merchantRef: 'order-42'
});
// 2. Listen for confirmation
window.addEventListener('fire-payment-update', (e) => {
if (e.detail.status === 'confirmed') {
// Done. e.detail.txId has the transaction ID.
}
});
Quick reference: resolve protocol
JavaScript
// 1. Request payment (address stays server-side)
const result = await window.fire.requestPayment({
resolveUrl: 'https://yoursite.com/api/resolve',
intentToken: 'tok_abc123',
amount: '5000000',
tokenId: 1,
merchantRef: 'order-42'
});
// 2. Same event listener
window.addEventListener('fire-payment-update', (e) => {
if (e.detail.status === 'confirmed') { /* ... */ }
});
Quick reference: Read API
JavaScript
// 1. Request permission
await window.fire.requestPermissions(['balances:read']);
// 2. Read data
const balances = await window.fire.getBalances();
// 3. Handle revocation
window.fire.onPermissionRevoked((scopes) => { /* ... */ });
Quick reference: Ethereum
JavaScript
// 1. Detect wallet (EIP-6963)
window.addEventListener('eip6963:announceProvider', (e) => {
if (e.detail.info.rdns === 'co.fire.wallet') {
const provider = e.detail.provider;
// 2. Connect
const accounts = await provider.request({
method: 'eth_requestAccounts'
});
// 3. Sign or send
const sig = await provider.request({
method: 'personal_sign',
params: [message, accounts[0]]
});
}
});
window.dispatchEvent(new Event('eip6963:requestProvider'));