OnlineHashCrack Private API
Submit authorized hash recovery tasks and retrieve your task list. JSON over HTTPS, sk_-prefixed API keys, each response includes a request_id.
https://api.onlinehashcrack.com/v2
api_key in the JSON body.
Content-Type: application/json.
Endpoints
https://api.onlinehashcrack.com/v2https://api.onlinehashcrack.com/v2?schema=1https://api.onlinehashcrack.com/v2?openapi=1agree_terms to yes only when you have read and accepted the Terms & Conditions and you are submitting hashes you are authorized to test.
Request Body
All API actions use a JSON object. If action is omitted, the API defaults to add_tasks.
| Field | Type | Required | Description |
|---|---|---|---|
api_key |
String | Required | Your private API key. Format: sk_ followed by 32 to 64 alphanumeric characters. Generate or manage it from API management. |
agree_terms |
String | Required | Must be exactly yes. Any other value returns terms_not_accepted. |
action |
String | Optional | Allowed values: add_tasks, list_tasks, identify_hash, or list_wordlists. Defaults to add_tasks. |
algo_mode |
Integer | Required for add_tasks | Non-negative Hashcat algorithm mode. See the accepted hash list. Example: 0 for MD5. Not accepted for list_tasks, identify_hash, or list_wordlists. |
hashes |
Array<string> | Required for add_tasks / identify_hash | One to 50 hash strings. Each value is trimmed, HTML tags are stripped, values are capped at 512 characters, and duplicates in the same request are ignored. Not accepted for list_tasks or list_wordlists. |
Examples
# Add hash recovery tasks
curl -sS -X POST "https://api.onlinehashcrack.com/v2" \
-H "Content-Type: application/json" \
-d '{
"api_key": "sk_REPLACE_WITH_YOUR_KEY",
"agree_terms": "yes",
"action": "add_tasks",
"algo_mode": 0,
"hashes": [
"8124BC0A5335C27F086F24BA2C7A4810"
]
}'
# List current tasks
curl -sS -X POST "https://api.onlinehashcrack.com/v2" \
-H "Content-Type: application/json" \
-d '{
"api_key": "sk_REPLACE_WITH_YOUR_KEY",
"agree_terms": "yes",
"action": "list_tasks"
}'
# Identify the algo_mode(s) matching one or more hashes
curl -sS -X POST "https://api.onlinehashcrack.com/v2" \
-H "Content-Type: application/json" \
-d '{
"api_key": "sk_REPLACE_WITH_YOUR_KEY",
"agree_terms": "yes",
"action": "identify_hash",
"hashes": [
"8124BC0A5335C27F086F24BA2C7A4810"
]
}'
# List your uploaded wordlists and storage quota
curl -sS -X POST "https://api.onlinehashcrack.com/v2" \
-H "Content-Type: application/json" \
-d '{
"api_key": "sk_REPLACE_WITH_YOUR_KEY",
"agree_terms": "yes",
"action": "list_wordlists"
}'
# Inspect the request schema
curl -sS "https://api.onlinehashcrack.com/v2?schema=1"
# Inspect the OpenAPI 3.0 schema
curl -sS "https://api.onlinehashcrack.com/v2?openapi=1"
import requests
url = "https://api.onlinehashcrack.com/v2"
payload = {
"api_key": "sk_REPLACE_WITH_YOUR_KEY",
"agree_terms": "yes",
"action": "add_tasks",
"algo_mode": 0,
"hashes": ["8124BC0A5335C27F086F24BA2C7A4810"],
}
response = requests.post(url, json=payload, timeout=30)
data = response.json()
if response.status_code == 429:
print("Retry after", response.headers.get("Retry-After"), "seconds")
elif not response.ok:
print(data.get("error_code"), data.get("message"), data.get("request_id"))
else:
print(data)
const response = await fetch('https://api.onlinehashcrack.com/v2', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
api_key: 'sk_REPLACE_WITH_YOUR_KEY',
agree_terms: 'yes',
action: 'add_tasks',
algo_mode: 0,
hashes: ['8124BC0A5335C27F086F24BA2C7A4810'],
}),
});
const data = await response.json();
if (response.status === 429) {
console.log('Retry after', response.headers.get('Retry-After'), 'seconds');
} else if (!response.ok) {
console.error(data.error_code, data.message, data.request_id);
} else {
console.log(data);
}
$uri = 'https://api.onlinehashcrack.com/v2'
$payload = @{
api_key = 'sk_REPLACE_WITH_YOUR_KEY'
agree_terms = 'yes'
action = 'add_tasks'
algo_mode = 0
hashes = @('8124BC0A5335C27F086F24BA2C7A4810')
} | ConvertTo-Json -Depth 4
try {
$response = Invoke-RestMethod `
-Uri $uri `
-Method Post `
-ContentType 'application/json' `
-Body $payload `
-TimeoutSec 30
$response
} catch {
$statusCode = $_.Exception.Response.StatusCode.value__
$retryAfter = $_.Exception.Response.Headers['Retry-After']
Write-Error "OHC API error HTTP $statusCode. Retry-After: $retryAfter"
}
package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
"time"
)
func main() {
payload := map[string]any{
"api_key": "sk_REPLACE_WITH_YOUR_KEY",
"agree_terms": "yes",
"action": "add_tasks",
"algo_mode": 0,
"hashes": []string{"8124BC0A5335C27F086F24BA2C7A4810"},
}
body, err := json.Marshal(payload)
if err != nil {
panic(err)
}
client := &http.Client{Timeout: 30 * time.Second}
req, err := http.NewRequest(http.MethodPost, "https://api.onlinehashcrack.com/v2", bytes.NewReader(body))
if err != nil {
panic(err)
}
req.Header.Set("Content-Type", "application/json")
resp, err := client.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
responseBody, err := io.ReadAll(resp.Body)
if err != nil {
panic(err)
}
if resp.StatusCode == http.StatusTooManyRequests {
fmt.Println("Retry after", resp.Header.Get("Retry-After"), "seconds")
}
if resp.StatusCode >= 400 {
fmt.Println("API error:", resp.Status, string(responseBody))
return
}
fmt.Println(string(responseBody))
}
$url = 'https://api.onlinehashcrack.com/v2';
$payload = [
'api_key' => 'sk_REPLACE_WITH_YOUR_KEY',
'agree_terms' => 'yes',
'action' => 'add_tasks',
'algo_mode' => 0,
'hashes' => ['8124BC0A5335C27F086F24BA2C7A4810'],
];
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
CURLOPT_POSTFIELDS => json_encode($payload, JSON_THROW_ON_ERROR),
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 30,
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
$error = curl_error($ch);
curl_close($ch);
if ($body === false) {
throw new RuntimeException('API request failed: ' . $error);
}
$data = json_decode($body, true, 512, JSON_THROW_ON_ERROR);
if ($status >= 400) {
error_log('OHC API error ' . ($data['error_code'] ?? 'unknown') . ' request_id=' . ($data['request_id'] ?? 'none'));
}
print_r($data);
Successful Responses
add_tasks response
The response groups submitted hashes into accepted, skipped, and rejected. Hashes are masked for safe correlation in local logs.
{
"accepted": {
"count": 1,
"hashes": [
"8124...4810"
]
},
"skipped": {
"count": 1,
"reason": "already_sent",
"hashes": [
"5F4D...27E0"
]
},
"rejected": {
"count": 1,
"hashes": [
"BAD...HASH"
],
"reason": "invalid_format"
},
"success": true,
"request_id": "9f8a7b6c5d4e3f21"
}
list_tasks response
Includes wordlists and wordlist_quota for the account. The recovered password is never returned by the API; when status is FOUND, the item includes cleartext_location instead.
{
"success": true,
"tasks": [
{
"created_at": "2026-05-12 14:25:00",
"hash": "8124BC0A5335C27F086F24BA2C7A4810",
"algomode": "0",
"algorithm": "MD5",
"usernote": "",
"status": "In queue",
"lastAttack": ""
},
{
"created_at": "2026-05-10 09:02:41",
"hash": "5F4DCC3B5AA765D61D8327DEB882CF99",
"algomode": "0",
"algorithm": "MD5",
"usernote": "",
"status": "FOUND",
"lastAttack": "Last attempt: Base wordlist",
"cleartext_location": "https://app.onlinehashcrack.com"
}
],
"wordlists": [
{
"name": "custom.txt",
"count": 1240000,
"size_bytes": 18874368,
"size_gb": 0.018,
"created_at": "2026-04-02 09:11:03"
}
],
"wordlist_quota": {
"unlimited": false,
"used_bytes": 18874368,
"max_bytes": 52428800,
"remaining_bytes": 33554432,
"upgrade_url": "https://app.onlinehashcrack.com/wordlists"
},
"request_id": "9f8a7b6c5d4e3f21"
}
identify_hash response
ambiguous is true when more than one algorithm matches; candidates is empty when none match.
{
"success": true,
"hashes": [
{
"hash": "8124BC0A5335C27F086F24BA2C7A4810",
"candidates": [
{ "algo_mode": 0, "name": "MD5" }
],
"ambiguous": false
}
],
"request_id": "9f8a7b6c5d4e3f21"
}
list_wordlists response
Lists wordlists uploaded to this account, plus storage quota. max_bytes, remaining_bytes, and upgrade_url are null when unlimited is true.
{
"success": true,
"wordlists": [
{
"name": "myCustomList.txt",
"count": 1240000,
"size_bytes": 18874368,
"size_gb": 0.018,
"created_at": "2026-04-02 09:11:03"
}
],
"wordlist_quota": {
"unlimited": false,
"used_bytes": 18874368,
"max_bytes": 52428800,
"remaining_bytes": 33554432
},
"request_id": "9f8a7b6c5d4e3f21"
}
Error Responses
Request-level errors return a non-2xx HTTP status, success: false, a machine-readable error_code, a human-readable message, and a request_id.
{
"success": false,
"error_code": "invalid_api_key",
"message": "Invalid API key.",
"request_id": "9f8a7b6c5d4e3f21"
}
| Status | Error code | When it happens |
|---|---|---|
| 400 | empty_body |
The request body is empty. |
| 400 | malformed_json |
The body is not a valid JSON object. |
| 400 | missing_field |
api_key or agree_terms is missing. The response includes a missing array. |
| 400 | terms_not_accepted |
agree_terms is not exactly yes. |
| 400 | invalid_action |
action is not add_tasks, list_tasks, identify_hash, or list_wordlists. |
| 400 | invalid_field_combination |
algo_mode or hashes sent with list_tasks or list_wordlists, or algo_mode sent with identify_hash. |
| 400 | invalid_algo_mode |
algo_mode is missing, negative, or not an integer for add_tasks. |
| 400 | invalid_hashes |
hashes is missing, not an array, empty, above 50 items, or contains non-string values (for add_tasks or identify_hash). |
| 401 | invalid_api_key |
The API key format is invalid, the key is unknown, the account is not verified, or API access is unavailable for the account. |
| 405 | method_not_allowed |
The request method is not POST. The response includes Allow: POST. |
| 413 | body_too_large |
The JSON body exceeds 1 MB. |
| 429 | rate_limit_exceeded |
The hourly API limit is exhausted. The response includes Retry-After, retry_after, and limit. |
| 500 | internal_error |
An internal server error occurred. Provide request_id when contacting support. |
Hash-level rejection reasons
When the request itself is valid but individual hashes cannot be added, they appear in rejected. The reason field contains the last rejection reason returned for that batch.
invalid_format: the hash does not match the selectedalgo_mode.invalid_algorithm: the selected algorithm is unsupported or invalid.quota_exceeded: the account quota is reached.internal_error: an unexpected server-side error occurred while saving a task.
Rate Limits
Enforced per API key, fixed one-hour window.
| Tier | Requests per hour | Upgrade path |
|---|---|---|
| Tier 1 | 50 | Profile |
| Tier 2 | 500 | Profile |
| Tier 3 | 2000 | Profile |
{
"success": false,
"error_code": "rate_limit_exceeded",
"message": "Hourly rate limit of 500 requests exceeded. Retry after 532 seconds, or upgrade your Tier (see Profile).",
"request_id": "9f8a7b6c5d4e3f21",
"retry_after": 532,
"limit": 500
}
Implementation Best Practices
- Keep API keys server-side. Do not expose
sk_keys in browser JavaScript, mobile apps, public repositories, screenshots, or client logs. - Store
request_idwith failed calls. It is the safest value to share with support. - Respect
Retry-Afteron429responses and use backoff instead of retry loops. - Submit up to 50 hashes per request instead of one request per hash when possible.
- Use the schema endpoint in tests to validate your request format before sending production traffic.
- Never submit hashes unless you own the system or have written authorization to test it.
MCP Server
Model Context Protocol server, Streamable HTTP (spec 2025-03-26). Same sk_ key as the REST API.
https://mcp.onlinehashcrack.com/sk_YOUR_API_KEYAvailable tools
| Tool | Type | Description |
|---|---|---|
ohc_submit_hashes |
Write | Submit 1–50 hashes. Parameters: algo_mode, hashes, user_confirmed: true. |
ohc_list_tasks |
Read-only | Tasks (status, algorithm, last attack), account wordlists, storage quota, and a prioritized recommendations analysis. |
ohc_identify_hash |
Read-only | Identify the Hashcat algo_mode(s) matching 1–50 hash strings. Read-only. |
ohc_list_wordlists |
Read-only | Custom wordlists (name, password count, size) and storage quota used/remaining. |
Client setup
Three ways to connect Claude to your OHC account — all use the same URL.
Option 1 — Claude Code (recommended for developers)
Register the server once. Claude Code persists it across sessions.
claude mcp add onlinehashcrack \
--transport http \
"https://mcp.onlinehashcrack.com/sk_YOUR_API_KEY"
Confirm the server is registered:
claude mcp list
Then just open a session and ask:
claude
# → "List my OHC tasks" or "Submit this hash ..."
Option 2 — Claude Desktop
Open claude_desktop_config.json and add the entry under mcpServers. Create the file if it does not exist.
| OS | Path |
|---|---|
| macOS | ~/Library/Application Support/Claude/claude_desktop_config.json |
| Windows | %APPDATA%\Claude\claude_desktop_config.json |
{
"mcpServers": {
"onlinehashcrack": {
"url": "https://mcp.onlinehashcrack.com/sk_YOUR_API_KEY"
}
}
}
Restart Claude Desktop. The OHC tools will appear in the tool picker.
Option 3 — Claude.ai (web)
Go to Settings → Integrations, click Add integration, and paste the MCP URL:
https://mcp.onlinehashcrack.com/sk_YOUR_API_KEY
No restart needed — tools are available immediately in the next conversation.
ChatGPT Desktop and the OpenAI Agents SDK both support MCP remote servers.
Option 1 — ChatGPT Desktop
Open Settings → Connections and add the OHC MCP server by pasting the URL directly into the remote server field:
https://mcp.onlinehashcrack.com/sk_YOUR_API_KEY
Option 2 — OpenAI Agents SDK
Use the OHC MCP server inside an agent workflow. Install with pip install openai-agents.
import asyncio
from agents import Agent, Runner
from agents.mcp import MCPServerStreamableHttp
async def main():
params = {"url": "https://mcp.onlinehashcrack.com/sk_YOUR_API_KEY"}
async with MCPServerStreamableHttp(name="OnlineHashCrack", params=params) as ohc:
agent = Agent(
name="hash-auditor",
instructions=(
"You are a security audit assistant with access to OnlineHashCrack. "
"Only submit hashes the user confirms they own or are authorized to test."
),
mcp_servers=[ohc],
)
result = await Runner.run(agent, "List my cracking tasks and summarize the results.")
print(result.final_output)
asyncio.run(main())
See the OpenAI Agents SDK docs for streaming, tool filtering, and multi-server setups.
ohc_submit_hashes. Requires user_confirmed: true, enforced server-side.