Portugal NIF check digit calculator and validator
This Portugal NIF check digit calculator applies the standard modulo-eleven checksum used for a Portuguese tax identification number.
Run — free
Give it the first eight digits to calculate the ninth digit, or submit all nine digits to test whether the supplied check digit agrees with the calculation. The result is deterministic and immediate, making it suitable for form checks, imports, accounting workflows, and API validation. Invalid lengths, non-digit characters, and unsupported modes are reported clearly instead of being silently cleaned or guessed.
Choose whether to compute or validate
Use compute mode when you already have the eight-digit base of a Portuguese NIF and need its final check digit. The response includes the calculated digit and the complete nine-digit value, so you can place it directly into a subsequent validation or test workflow. Use validate mode when the source already contains all nine digits. Validation separates the first eight digits from the supplied ninth digit, calculates the expected value, and reports whether both digits match. It also returns the supplied and expected digits, which makes a failed result easy to diagnose. Keep the input as a string rather than a numeric value. A string preserves every character exactly, including a leading zero, and prevents spreadsheet or programming-language number formatting from changing the identifier before the checksum is evaluated. The default mode is validate because checking an existing complete NIF is the most common form and import task, but callers should set the mode explicitly when a workflow may handle both shapes.
How the modulo-eleven calculation works
The algorithm processes the first eight digits from left to right with descending weights from nine through two. It multiplies the first digit by nine, the second by eight, and continues until the eighth digit is multiplied by two. Those eight products are added, and the total is reduced modulo eleven. If the remainder is zero or one, the check digit is zero. For any other remainder, the check digit is eleven minus that remainder. Validation performs exactly the same calculation on the first eight positions and compares the result with position nine. This capability does not strip spaces, dots, dashes, country prefixes, or labels before calculating. That strict behavior is intentional: automatic cleanup can make malformed source data appear trustworthy and can hide errors in upstream field mapping. Submit only ASCII digits from zero through nine. The calculation uses no network request, random value, clock, database, or locale-sensitive conversion, so identical input and mode always produce identical JSON output.
Interpret the result and its limits
A true validation result means the ninth digit is consistent with the modulo-eleven checksum derived from the preceding eight digits. It is a useful structural check for typing mistakes, damaged imports, and incorrectly mapped columns, but it does not prove that the number was issued, remains active, or belongs to a particular person or organization. Those questions require an authoritative registry or an appropriate business verification process. Likewise, this calculator deliberately evaluates the checksum rather than enforcing assumptions about categories encoded in the leading digit. That keeps its scope precise and avoids rejecting a checksum-valid number merely because an external allocation rule changes. In a data pipeline, treat invalid input errors differently from a false validity result: an error means the request had the wrong type, length, characters, or mode, while false means a well-formed nine-digit value was checked and its supplied digit did not match. API requests cost $0.002 each, and the same deterministic core can run in the browser for quick manual checks.
What you can do with it
Check a tax form before submission
Validate a nine-digit NIF as soon as it is entered and show a focused correction message when its check digit does not match.
Audit imported customer records
Run checksum validation over NIF fields after a CSV or system migration to identify truncation, transposition, and mapping errors.
Generate deterministic test fixtures
Compute the ninth digit for an eight-digit base when preparing integration tests for billing, invoicing, or onboarding software.
FAQ
What input does compute mode require?
Exactly eight digits as a string. The response returns the calculated check digit and the complete nine-digit NIF.
What input does validate mode require?
Exactly nine digits as a string, including the check digit in the final position.
Does a valid checksum prove that the NIF was issued?
No. It only proves that the supplied ninth digit matches the checksum calculated from the first eight digits.
Can I include spaces, punctuation, or a country prefix?
No. Submit digits only. Formatting characters are rejected so malformed source data is not silently changed.
How is the check digit calculated?
The first eight digits are weighted from nine down to two, summed, and reduced modulo eleven; remainder zero or one produces zero, otherwise the digit is eleven minus the remainder.
What does an API request cost?
Each API request costs $0.002. You can also use the browser execution path for a quick local calculation.
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/enc/nif-portugal \
-H "Authorization: Bearer $KIT_KEY" \
-H "Content-Type: application/json" \
-d '{"number":"501964843"}'const res = await fetch("https://api.kit.forhosting.com/enc/nif-portugal", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.KIT_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
"number": "501964843"
})
});
const { task_id } = await res.json();import os, requests
res = requests.post(
"https://api.kit.forhosting.com/enc/nif-portugal",
headers={"Authorization": f"Bearer {os.environ['KIT_KEY']}"},
json={
"number": "501964843"
},
)
task_id = res.json()["task_id"]<?php
$res = file_get_contents("https://api.kit.forhosting.com/enc/nif-portugal", false, stream_context_create([
"http" => [
"method" => "POST",
"header" => "Authorization: Bearer " . getenv("KIT_KEY") . "\r\nContent-Type: application/json",
"content" => '{"number":"501964843"}',
],
]));
$task = json_decode($res, true);body := bytes.NewBufferString(`{"number":"501964843"}`)
req, _ := http.NewRequest("POST", "https://api.kit.forhosting.com/enc/nif-portugal", body)
req.Header.Set("Authorization", "Bearer "+os.Getenv("KIT_KEY"))
req.Header.Set("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)Example request
{
"number": "501964843"
}Example response
{
"task_id": "tsk_a1b2c3d4e5f6a1b2c3d4e5f6",
"type": "enc.nif_portugal",
"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. |