@hopla/sickw
v1.3.3
Published
TypeScript client for the Sickw IMEI check/unlock API
Maintainers
Readme
@hopla/sickw
TypeScript client for the Sickw IMEI check/unlock API.
- Zero dependencies (uses native
fetch) - ESM + CJS + full type definitions
- React hooks via
@hopla/sickw/react(no external dependencies) - Claude Code skill for AI-assisted development
- Tree-shakeable (
sideEffects: false) - Node.js >= 18
Install
npm install @hopla/sickwClaude Code Skill (optional)
Install the skill so Claude Code knows how to use this library when building your projects:
# Global — available in all projects
npx sickw-skill-install --global
# Project-level — only for current repo
npx sickw-skill-installOnce installed, Claude will automatically use @hopla/sickw when you ask it to build features involving IMEI checks, carrier lookups, iCloud status, phone unlocks, etc. You can also invoke it explicitly with /sickw.
To uninstall: npx sickw-skill-uninstall --global
Quick Start (React + Cloudflare Worker)
1. Backend proxy (Cloudflare Worker with Hono)
Never expose your API key in the browser. Create a Worker route that forwards requests to Sickw:
// worker/src/routes/sickw.ts
import { Hono } from 'hono';
import { createSickwClient } from '@hopla/sickw';
const app = new Hono<{ Bindings: { SICKW_API_KEY: string } }>();
app.post('/sickw/check', async (c) => {
const sickw = createSickwClient({ apiKey: c.env.SICKW_API_KEY });
const { imei, serviceId } = await c.req.json();
const result = await sickw.check(imei, serviceId);
return c.json({ success: true, data: result });
});
app.get('/sickw/services', async (c) => {
const sickw = createSickwClient({ apiKey: c.env.SICKW_API_KEY });
const services = await sickw.services();
return c.json({ success: true, data: services });
});
app.get('/sickw/balance', async (c) => {
const sickw = createSickwClient({ apiKey: c.env.SICKW_API_KEY });
const balance = await sickw.balance();
return c.json({ success: true, data: balance });
});
export default app;2. Use the hooks (frontend)
The hooks receive a generic fetchFn — use your app's existing fetch wrapper (e.g., apiPost/apiGet):
import { useSickwCheck, useSickwServices, useSickwBalance } from '@hopla/sickw/react';
import { isValidImeiOrSn } from '@hopla/sickw';
import { apiPost, apiGet } from '@/lib/api'; // your fetch wrapper
import { useState } from 'react';
function ImeiChecker() {
const [imei, setImei] = useState('');
const [serviceId, setServiceId] = useState(3);
const { data: services } = useSickwServices(
() => apiGet('/sickw/services').then(r => r.data!)
);
const { data: balance } = useSickwBalance(
() => apiGet('/sickw/balance').then(r => r.data!),
60_000 // refetch every 60s
);
const check = useSickwCheck(
(params) => apiPost('/sickw/check', params).then(r => r.data!)
);
const isValid = imei.length === 0 || isValidImeiOrSn(imei);
return (
<div>
<p>Balance: ${balance}</p>
<input
value={imei}
onChange={(e) => setImei(e.target.value.trim())}
placeholder="Enter IMEI or Serial Number"
maxLength={15}
style={{ borderColor: isValid ? undefined : 'red' }}
/>
<select value={serviceId} onChange={(e) => setServiceId(Number(e.target.value))}>
{services?.map((s) => (
<option key={s.service} value={s.service}>
{s.name} (${s.price})
</option>
))}
</select>
<button
disabled={!isValidImeiOrSn(imei) || check.isPending}
onClick={() => check.mutate({ imei, serviceId })}
>
{check.isPending ? 'Checking...' : 'Check IMEI'}
</button>
{check.isSuccess && (
<pre>{JSON.stringify(check.data!.result, null, 2)}</pre>
)}
{check.isError && (
<p style={{ color: 'red' }}>{check.error!.message}</p>
)}
</div>
);
}React Hooks
| Hook | Type | Signature |
|------|------|-----------|
| useSickwCheck(fetchFn, options?) | Action (manual trigger) | → { data, error, isPending, isSuccess, isError, mutate, reset } |
| useSickwHistory(fetchFn, options?) | Action (manual trigger) | → { data, error, isPending, isSuccess, isError, mutate, reset } |
| useSickwServices(fetchFn) | Auto-fetch on mount | → { data, error, isLoading } |
| useSickwBalance(fetchFn, intervalMs?) | Auto-fetch + refetch | → { data, error, isLoading, refetch } |
No @tanstack/react-query or any other external dependency required. The hooks use vanilla useState/useEffect/useCallback.
Each hook receives a fetchFn — a function that calls your backend. This lets you plug in any fetch wrapper (apiPost, apiGet, plain fetch, etc.) without coupling to the Sickw client directly.
Node.js / Backend Usage
The client also works standalone without React:
import { createSickwClient } from '@hopla/sickw';
const client = createSickwClient({
apiKey: 'ABC-DEF-GHI-JKL-MNO-PQR-STU-VWX',
});
const result = await client.check('354442067957123', 3);
const balance = await client.balance();
const services = await client.services();
const history = await client.history('76369088');Validators
Validate user input before submitting:
import { isValidImeiOrSn, isValidServiceId, isValidApiKey } from '@hopla/sickw';
isValidImeiOrSn('354442067957123'); // true — 11-15 alphanumeric chars
isValidServiceId(3); // true — integer 0-250
isValidApiKey('ABC-DEF-GHI-...'); // true — XXX-XXX-XXX-XXX-XXX-XXX-XXX-XXXService Catalog
All 84 services are available as a typed constant for building UI dropdowns, filtering, etc.:
import { SERVICES, getServiceById, getServicesByCategory } from '@hopla/sickw';
// Lookup by ID
const icloud = getServiceById(3);
// { id: 3, name: 'iCloud On/Off', price: '0.01', category: 'Apple', instant: true }
// Filter by category
const appleServices = getServicesByCategory('Apple'); // 21 services
// Group for a dropdown
const categories = ['Apple', 'Status', 'Generico', 'Premium', 'Unlock iPhone', 'Unlock Gen'];| Category | Count | Instant | |----------|-------|---------| | Apple | 21 | Yes | | Status | 10 | Mostly | | Generico | 23 | Yes | | Premium | 1 | No | | Unlock iPhone | 22 | No | | Unlock Gen | 7 | No |
Error Handling
API errors are thrown as SickwError with a typed error code:
import { SickwError } from '@hopla/sickw';
try {
const result = await sickw.check(imei, serviceId);
} catch (err) {
if (err instanceof SickwError) {
console.log(err.code); // 'E01', 'B01', 'A01', etc.
console.log(err.rawMessage); // Original API error string
}
}| Code | Description | |------|-------------| | E01 | IMEI failed Luhn checksum | | E02 | IMEI/SN invalid format or length | | R01 | Service offline or IMEI/SN not found | | B01 | Insufficient balance | | S01/S02 | Service ID does not exist or is inactive | | S03 | Service is not instant | | A01/A02/A03 | Invalid API key |
Configuration
createSickwClient({
apiKey: 'XXX-XXX-...', // Required (can be empty for proxy usage)
baseUrl: 'https://...', // Default: 'https://sickw.com'
timeout: 60000, // Default: 60000ms
});Documentation
Full API documentation is included in the docs/ directory:
docs/Sickw API Reference.md— All 84 service IDs with prices and categoriesdocs/api-docs/Sickw API.md— Endpoint, auth, formats, error codesdocs/api-docs/Servicios Apple.md— 21 Apple services (iCloud, carrier, MDM, GSX)docs/api-docs/Servicios Status Check.md— 10 carrier/blacklist status servicesdocs/api-docs/Servicios Genericos.md— 23 brand info servicesdocs/api-docs/Servicios Premium.md— MDM bypassdocs/api-docs/Servicios Unlock iPhone.md— 22 iPhone unlock servicesdocs/api-docs/Servicios Unlock Generico.md— 7 generic unlock servicesdocs/guides/typescript-api-client.md— Guide: building a TS clientdocs/guides/react-integration.md— Guide: React hooks and proxy pattern
License
MIT
