Private API/MCP Documentation

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.

JSON over HTTPS Maximum 50 hashes per request Per-key hourly limits Authorized use only
Base endpoint https://api.onlinehashcrack.com/v2
Authentication Send api_key in the JSON body.
Content type Use Content-Type: application/json.

Endpoints

POST https://api.onlinehashcrack.com/v2
Add tasks or list existing tasks.
GET https://api.onlinehashcrack.com/v2?schema=1
Return the JSON Schema for the request body. No API key required.
GET https://api.onlinehashcrack.com/v2?openapi=1
Return the OpenAPI 3.0.3 schema. No API key required.
Terms and authorized use. Set agree_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 selected algo_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_id with failed calls. It is the safest value to share with support.
  • Respect Retry-After on 429 responses 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.

Same key, two interfaces. Rotating your key requires updating both endpoints.
MCP https://mcp.onlinehashcrack.com/sk_YOUR_API_KEY
Streamable HTTP · MCP spec 2025-03-26

Available 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.

OSPath
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.

Confirmation gate on ohc_submit_hashes. Requires user_confirmed: true, enforced server-side.