Sudoku Grid Validity Checker
A single duplicated digit can make a Sudoku position invalid long before the mistake becomes visually obvious.
Run — free
This checker examines a complete or partially filled standard grid and identifies every occupied cell involved in an immediate rule conflict. It checks rows, columns, and 3x3 boxes independently, ignores blank cells, and returns stable coordinates with the reason each cell is flagged. It does not solve the puzzle or reveal missing values, making it suitable for private practice, puzzle editing, classroom feedback, and automated validation.
Format the grid before checking it
Enter a standard Sudoku grid as nine lines containing nine cells each. Filled cells must be digits from 1 through 9. Write an empty cell as a period or zero; both forms mean exactly the same thing and do not participate in duplicate checks. Spaces, commas, and vertical bars may be used between cells for readability, so compact puzzle notation and visually separated notation are both accepted. The checker removes those separators but does not infer or repair any other characters. This distinction keeps malformed input separate from a validly shaped grid that breaks Sudoku rules. A request produces an input error when there are not exactly nine rows, when a row does not contain exactly nine cells after separators are removed, or when a cell contains an unsupported character. Partial grids are welcome, including puzzles with only the starting clues, positions from the middle of a game, and nearly completed boards. A fully blank grid is structurally valid because there are no occupied cells that can conflict. The checker evaluates only the supplied position and never fills gaps or changes the submitted values.
Read the conflict report cell by cell
The result starts with a Boolean <code>valid</code> value. It is true when no occupied cell shares its digit with another occupied cell in the same row, column, or 3x3 box. The <code>filled_cells</code> count shows how many nonblank entries were examined. When the position is invalid, <code>conflict_cells</code> lists every involved cell using one-based row and column coordinates, the digit stored there, and one or more conflict descriptions. Each description names the rule type, the one-based unit index, and the duplicated value. A cell can carry multiple reasons. For example, a repeated five might violate both its row and its upper-left box, and both facts remain visible. Reporting every affected cell is useful for interfaces because each incorrect location can be highlighted directly without reconstructing groups from a summary. Output order is deterministic: cells follow reading order from the first row to the ninth, while reasons follow row, column, then box checks. Blank cells never appear in the report. If three copies of one digit occupy a unit, all three are flagged rather than selecting an arbitrary pair, so the report represents the full local contradiction.
Know what Sudoku validity does and does not prove
This check answers a narrow but important question: does the current position immediately violate the uniqueness rule for any row, column, or box? A valid response does not prove that the puzzle is solvable, that it has exactly one solution, or that its clue design is fair. Some positions contain no direct duplicates yet still cannot be completed because earlier choices eliminate every candidate from a later cell. Determining that requires a solver or deeper feasibility analysis, which this capability intentionally does not perform. The limited scope is valuable when feedback should reveal mistakes without exposing an answer. A learning tool can highlight the precise cells involved in a duplicate; a puzzle editor can validate clues after each change; and an import pipeline can reject damaged records before more expensive processing begins. Since the computation is a fixed scan over at most 81 cells, it uses no network, random values, clock, or external state. Identical input therefore produces identical structured output. The browser experience can run the same pure logic locally, while an automated workflow can request the API result for $0.002 per item and store the conflict coordinates for later review.
What you can do with it
Check a game in progress
Find duplicated entries in a partial board without asking a solver to reveal any missing digit.
Review puzzle clues
Validate a newly entered clue grid and highlight every cell involved in an immediate rule violation.
Protect an import pipeline
Separate malformed text from well-formed but conflicting Sudoku records before downstream processing.
FAQ
Can I check an unfinished Sudoku?
Yes. Use a period or zero for every blank cell. Blank cells are ignored when checking duplicates.
Does valid mean the puzzle has a solution?
No. Valid means the current entries have no row, column, or box duplicate. It does not prove solvability or uniqueness.
Why can one cell have several conflict reasons?
The same entry can simultaneously duplicate a digit in its row, column, and box. Each violated rule is reported independently.
Are coordinates zero-based?
No. Rows, columns, and unit indexes start at 1 so they match customary human descriptions of a Sudoku grid.
How much does an API check cost?
Each API item costs $0.002. The interactive browser checker can run locally for free.
For developers — API access
Everything on this page is available programmatically. This section is for teams who want to wire it into their own systems; everyone else can just use the tool above.
API endpoint
Prefer to automate it? One authenticated POST creates the task; the result comes back by webhook or a signed link. The same capability also runs here on the web, by email and from Telegram — and soon from our app too.
Call it from your stack
curl -X POST https://api.kit.forhosting.com/hobby/game-sudoku-validity \
-H "Authorization: Bearer $KIT_KEY" \
-H "Content-Type: application/json" \
-d '{"grid":"53..7....\n6..195...\n.98....6.\n8...6...3\n4..8.3..1\n7...2...6\n.6....28.\n...419..5\n....8..79"}'const res = await fetch("https://api.kit.forhosting.com/hobby/game-sudoku-validity", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.KIT_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
"grid": "53..7....\n6..195...\n.98....6.\n8...6...3\n4..8.3..1\n7...2...6\n.6....28.\n...419..5\n....8..79"
})
});
const { task_id } = await res.json();import os, requests
res = requests.post(
"https://api.kit.forhosting.com/hobby/game-sudoku-validity",
headers={"Authorization": f"Bearer {os.environ['KIT_KEY']}"},
json={
"grid": "53..7....\n6..195...\n.98....6.\n8...6...3\n4..8.3..1\n7...2...6\n.6....28.\n...419..5\n....8..79"
},
)
task_id = res.json()["task_id"]<?php
$res = file_get_contents("https://api.kit.forhosting.com/hobby/game-sudoku-validity", false, stream_context_create([
"http" => [
"method" => "POST",
"header" => "Authorization: Bearer " . getenv("KIT_KEY") . "\r\nContent-Type: application/json",
"content" => '{"grid":"53..7....\\n6..195...\\n.98....6.\\n8...6...3\\n4..8.3..1\\n7...2...6\\n.6....28.\\n...419..5\\n....8..79"}',
],
]));
$task = json_decode($res, true);body := bytes.NewBufferString(`{"grid":"53..7....\n6..195...\n.98....6.\n8...6...3\n4..8.3..1\n7...2...6\n.6....28.\n...419..5\n....8..79"}`)
req, _ := http.NewRequest("POST", "https://api.kit.forhosting.com/hobby/game-sudoku-validity", body)
req.Header.Set("Authorization", "Bearer "+os.Getenv("KIT_KEY"))
req.Header.Set("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)Example request
{
"grid": "53..7....\n6..195...\n.98....6.\n8...6...3\n4..8.3..1\n7...2...6\n.6....28.\n...419..5\n....8..79"
}Example response
{
"task_id": "tsk_a1b2c3d4e5f6a1b2c3d4e5f6",
"type": "hobby.game_sudoku_validity",
"status": "queued",
"_links": {
"result": "/tasks/tsk_…/result"
}
}The API is asynchronous: the call returns a task_id immediately and the result arrives by webhook. Polling is capped at 1 req/s per task.
Pricing
Published price — no tokens, no invented credits. A failed task is never charged.
Errors
| HTTP | Code | Meaning |
|---|---|---|
401 | unauthorized | Missing or invalid API key. |
402 | insufficient_balance | Your balance doesn't cover the task price. |
404 | unknown_type | That task type doesn't exist. |
429 | rate_limited | Too many requests. Use the webhook instead of polling. |