Repository navigation
URLhaus API
Client configuration and endpoint methods for @tundraconnect/urlhaus.
import { URLhaus } from '@tundraconnect/urlhaus';
const urlhaus = new URLhaus({
auth: { type: 'CUSTOM', authKey: 'YOUR_AUTH_KEY' },
timeout: 1.5,
});| Option | Type | Required | Default | Description |
|---|---|---|---|---|
auth |
URLhausAuth |
yes | — |
{ type: 'CUSTOM', authKey }, sent as the Auth-Key header. |
timeout |
number |
no | 10 |
Default per-call deadline in seconds, 1–120, fractions allowed. |
baseURL |
string |
no | https://urlhaus-api.abuse.ch/{version} |
Override for a proxy or a test double. |
version |
string |
no | v1 |
Fills {version} in baseURL. |
auth missing, not CUSTOM, or with a blank authKey →
CONFIG_INVALID_AUTH at construction. The Auth-Key header is marked
sensitive, so RESTler redacts it from call/authFailure event payloads
and from error contexts.
| Getter | Type | Description |
|---|---|---|
vendor |
string |
Always 'URLhaus'. |
Lookups never return raw query_status:
query_status |
lookupUrl / lookupHost
|
Other lookups | Feeds |
|---|---|---|---|
ok |
{ listed: true, entry } |
{ found: true, entry } |
the array |
no_results |
{ listed: false } |
{ found: false } |
[] |
| anything else | throws URLhausError
|
throws URLhausError
|
throws |
Numeric values URLhaus sends as strings (id, url_count, file_size,
response_size, takedown_time_seconds) stay strings. larted is the
string 'true' or 'false'. Every entry field is optional: URLhaus's own
examples are inconsistent, and a missing cosmetic field must never turn a
listed URL into a RESPONSE_ERROR.
Every method takes an optional timeout (seconds, 1–120, fractions
allowed) bounding the whole call.
POST /v1/url/, form url=<url> → ListedResult<UrlEntrySchema>.
const verdict = await urlhaus.lookupUrl({ url: 'http://example.com/x.exe' });
if (verdict.listed && verdict.entry.url_status === 'online') {
// actively serving malware
}INVALID_URL when URLhaus refuses the URL.
POST /v1/urlid/ → FoundResult<UrlEntrySchema>. id is a positive
integer, as a number or string. URLhaus's documentation names the form
field id in its parameter table but urlid in its example request. Both
are sent with the same value, so the call works whichever the server reads.
POST /v1/host/, form host=<host> → ListedResult<HostEntrySchema>.
An IPv4 address, hostname or domain, case-insensitive. INVALID_HOST when
URLhaus refuses it. blacklists is absent for an IPv4 host.
POST /v1/payload/ → FoundResult<PayloadEntrySchema>. Exactly one
hash, validated locally as 32 or 64 hex characters. INVALID_HASH when
URLhaus refuses it.
POST /v1/tag/ / POST /v1/signature/ → FoundResult<TagEntrySchema>
/ FoundResult<SignatureEntrySchema>. Up to 1,000 URLs each.
GET /v1/urls/recent/ / GET /v1/payloads/recent/, or
…/recent/limit/<n>/ with a limit of 1–1000 → RecentUrlSchema[] /
PayloadEntrySchema[]. These cover the past three days, newest first, and
return at most 1,000 entries.
The sample download (/v1/download/<sha256>/), the hourly and daily
batches, and the bulk dumps on urlhaus.abuse.ch/downloads/ (regenerated
every five minutes) are left out. Fetch those directly if you need them.
Subclass and reassign the protected _fetch:
import { URLhaus, type URLhausOptions } from '@tundraconnect/urlhaus';
class RoutedURLhaus extends URLhaus {
constructor(options: URLhausOptions, transport: typeof fetch) {
super(options);
this._fetch = transport;
}
}