A fact is a yes or no that Prson signs about a person: "over 18", "an EU citizen", "lives in Lisbon", "has a work email". The person shares only the answer, never the data behind it. This page shows how to ask for each kind, what a yes proves and what it doesn't.
Prson works out the answer from something it verified: the chip of a passport, ID card or residence permit, a code sent by email or SMS, a letter posted to an address, or a DNS record.
The person sees who is asking and why, and decides whether to answer. If they do, you get yes or no, signed by Prson. They can also decline.
When Prson can't tell (for example a birth year without a date, right at the age you ask), it gives no answer rather than guess, and the person can't fulfil that requirement. Mark a requirement optional if a missing answer shouldn't hold up the rest.
A fact is only as good as the verification behind it: each section below says what that is, and what it doesn't prove.
How to ask
Every fact is one requirement, { "type": "fact", "fact": "<id>" }, in a verification. Over REST, send it to POST /v1/verifications (see Verifications API). An AI agent calls the create_verification tool on the MCP server https://api.prson.net/mcp/verify with the same title and requirements (see MCP for AI agents). Either way you get a share_url to send to the person yourself.
POST /v1/verifications
REST (cURL)POST /v1/verifications
curl -X POST https://api.prson.net/v1/verifications \
-H "Authorization: Bearer $PRSON_API_KEY" \
-H "Content-Type: application/json" \
-d @- <<'JSON'
{
"title": "Confirm you are over 18 to open an account",
"requirements": [
{ "type": "fact", "fact": "age_gte_18" }
]
}
JSON
MCPtools/call on https://api.prson.net/mcp/verify
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "create_verification",
"arguments": {
"title": "Confirm you are over 18 to open an account",
"requirements": [
{ "type": "fact", "fact": "age_gte_18" }
]
}
}
}
Up to 10 requirements fit in one verification, so you can ask for several facts at once.
The answer
Each answer comes back in the verification's responses (and in the verification.* webhooks): fact.value is the yes or no. Prson vouches for it until fact.expires_at: an hour unless asked otherwise, never more than 180 days, and never past the verification it rests on. verdict_signature lets you check Prson signed it.
response.json
GET /v1/verifications/{id}
{
"id": "…",
"status": "fulfilled",
"responses": [
{
"respondent_id": "rsp_…",
"type": "fact",
"status": "verified",
"fact": {
"id": "age_gte_18",
"value": true,
"description": "Person is at least 18 years old",
"expires_at": "…"
},
"verdict_signature": "…"
}
]
}
Availability
Available Age, verification level, nationality, document, residence permit, email and website facts.
Where enabled Phone and address facts work only where Prson can verify them: capabilities.phone_verification and capabilities.address_verification in GET https://api.prson.net/v1/verifications/requirements (public). Otherwise the API answers 422 requirement_unavailable. Countries: Coverage by country.
Not available yet Bank balance, income and bank account facts, and academic email addresses: asking for them is refused.
All facts
Every fact the API knows, by family: 46 in all. Each says what a yes proves, what it doesn't, where it comes from and whether you can ask for it now. To put a request together and get its code, use Build your request.
Age
How old the person is, from the date of birth on their passport or ID card chip. You learn only yes or no, never the date.
The date of birth on their passport or ID card chip
Limits
Worked out from the chip's date of birth at the moment Prson signs the answer. If only a birth year is known and the person could be on either side of the age, Prson gives no answer rather than guess, so the request can't be fulfilled.
The person is at most this many years old (age_lte_17 is under 18).
Example
age_lte_17 (17 or younger)
From
The date of birth on their passport or ID card chip
Limits
Worked out from the chip's date of birth at the moment Prson signs the answer. If only a birth year is known and the person could be on either side of the age, Prson gives no answer rather than guess, so the request can't be fulfilled.
The person is between these two ages, both included.
Example
age_between_18_30 (Between 18 and 30 years old)
From
The date of birth on their passport or ID card chip
Limits
Worked out from the chip's date of birth at the moment Prson signs the answer. If only a birth year is known and the person could be on either side of the age, Prson gives no answer rather than guess, so the request can't be fulfilled.
Read from the chip of the document they verified in Prson (level 5 or 6). The expiry is the date on the chip: it doesn't say whether the document was since reported lost, stolen or cancelled.
The document expires more than this many months from now.
Example
doc_expires_after_6m (Identity document valid for more than 6 months)
From
Their passport or ID card chip, checked by Prson
Limits
Read from the chip of the document they verified in Prson (level 5 or 6). The expiry is the date on the chip: it doesn't say whether the document was since reported lost, stolen or cancelled.
The document they verified is a passport, a national ID card or a residence permit.
Example
document_type_eq_passport (Identity document is a passport)
From
Their passport or ID card chip, checked by Prson
Limits
Read from the chip of the document they verified in Prson (level 5 or 6). The expiry is the date on the chip: it doesn't say whether the document was since reported lost, stolen or cancelled.
issuing_country_eq_PRT (Identity document issued by Portugal)
From
Their passport or ID card chip, checked by Prson
Limits
Read from the chip of the document they verified in Prson (level 5 or 6). The expiry is the date on the chip: it doesn't say whether the document was since reported lost, stolen or cancelled.
issuing_country_in_eu (Identity document issued by an EU country)
From
Their passport or ID card chip, checked by Prson
Limits
Read from the chip of the document they verified in Prson (level 5 or 6). The expiry is the date on the chip: it doesn't say whether the document was since reported lost, stolen or cancelled.
issuing_country_in_eea (Identity document issued by an EU or EEA country)
From
Their passport or ID card chip, checked by Prson
Limits
Read from the chip of the document they verified in Prson (level 5 or 6). The expiry is the date on the chip: it doesn't say whether the document was since reported lost, stolen or cancelled.
issuing_country_in_schengen (Identity document issued by a Schengen country)
From
Their passport or ID card chip, checked by Prson
Limits
Read from the chip of the document they verified in Prson (level 5 or 6). The expiry is the date on the chip: it doesn't say whether the document was since reported lost, stolen or cancelled.
The nationality written in the document whose chip they verified in Prson (level 5 or 6). A person with two nationalities is matched on the one in that document: a no doesn't mean they hold no other.
The nationality written in the document whose chip they verified in Prson (level 5 or 6). A person with two nationalities is matched on the one in that document: a no doesn't mean they hold no other.
nationality_in_eea (Citizen of an EU or EEA country)
From
Their passport or ID card chip, checked by Prson
Limits
The nationality written in the document whose chip they verified in Prson (level 5 or 6). A person with two nationalities is matched on the one in that document: a no doesn't mean they hold no other.
nationality_in_schengen (Citizen of a Schengen country)
From
Their passport or ID card chip, checked by Prson
Limits
The nationality written in the document whose chip they verified in Prson (level 5 or 6). A person with two nationalities is matched on the one in that document: a no doesn't mean they hold no other.
A letter with a one-time code was posted to the address (by Pingen) and the person typed the code in the app. It proves a letter reached them there on the day they verified, not that they live there now, own it, or are the only person there. An address verification lasts 365 days.
address_country_eq_PT (Postal address in Portugal)
From
A code in a letter posted to their address
Limits
Any country where the letter can be delivered: see Coverage by country. A letter with a one-time code was posted to the address (by Pingen) and the person typed the code in the app. It proves a letter reached them there on the day they verified, not that they live there now, own it, or are the only person there. An address verification lasts 365 days.
address_country_in_eu (Postal address in an EU country)
From
A code in a letter posted to their address
Limits
Any country where the letter can be delivered: see Coverage by country. A letter with a one-time code was posted to the address (by Pingen) and the person typed the code in the app. It proves a letter reached them there on the day they verified, not that they live there now, own it, or are the only person there. An address verification lasts 365 days.
address_country_in_eea (Postal address in an EU or EEA country)
From
A code in a letter posted to their address
Limits
Any country where the letter can be delivered: see Coverage by country. A letter with a one-time code was posted to the address (by Pingen) and the person typed the code in the app. It proves a letter reached them there on the day they verified, not that they live there now, own it, or are the only person there. An address verification lasts 365 days.
address_country_in_schengen (Postal address in a Schengen country)
From
A code in a letter posted to their address
Limits
Any country where the letter can be delivered: see Coverage by country. A letter with a one-time code was posted to the address (by Pingen) and the person typed the code in the app. It proves a letter reached them there on the day they verified, not that they live there now, own it, or are the only person there. An address verification lasts 365 days.
Their verified postal address is in this region of this country.
Example
address_region_eq_US_california (Postal address in California, United States)
From
A code in a letter posted to their address
Limits
The region is written lower case, accents removed, words joined by hyphens ("São Paulo" becomes sao-paulo), and compared with what the person wrote on their address, so local spellings matter: lisboa, not lisbon. No answer if their address has no region; an address in another country is a no. A letter with a one-time code was posted to the address (by Pingen) and the person typed the code in the app. It proves a letter reached them there on the day they verified, not that they live there now, own it, or are the only person there. An address verification lasts 365 days.
Their verified postal address is in this city of this country.
Example
address_city_eq_PT_lisboa (Postal address in Lisboa, Portugal)
From
A code in a letter posted to their address
Limits
The city is written lower case, accents removed, words joined by hyphens ("São Paulo" becomes sao-paulo), and compared with what the person wrote on their address, so local spellings matter: lisboa, not lisbon. No answer if their address has no city; an address in another country is a no. A letter with a one-time code was posted to the address (by Pingen) and the person typed the code in the app. It proves a letter reached them there on the day they verified, not that they live there now, own it, or are the only person there. An address verification lasts 365 days.
Their verified postal address has a postcode starting with these letters and digits.
Example
address_postcode_prefix_PT_1000 (Postal address in Portugal, postcode starting 1000)
From
A code in a letter posted to their address
Limits
Compares letters and digits only, in upper case: spaces and dashes are removed from their postcode (1000-001 becomes 1000001), so write the prefix the same way. An address in another country is a no. A letter with a one-time code was posted to the address (by Pingen) and the person typed the code in the app. It proves a letter reached them there on the day they verified, not that they live there now, own it, or are the only person there. An address verification lasts 365 days.
Countries use ISO 3166-1 alpha-2 codes in upper case (PT, US). Regions and cities are written lower case without accents, words joined by hyphens: address_region_eq_US_new-york, address_city_eq_BR_sao-paulo.
Use the local spelling people write on their address (lisboa, munchen, not lisbon or munich). When unsure, a postcode prefix or the country is more reliable.
Example
POST /v1/verifications
REST (cURL)POST /v1/verifications
curl -X POST https://api.prson.net/v1/verifications \
-H "Authorization: Bearer $PRSON_API_KEY" \
-H "Content-Type: application/json" \
-d @- <<'JSON'
{
"title": "Confirm you live in Lisbon to join the residents' offer",
"requirements": [
{ "type": "fact", "fact": "address_city_eq_PT_lisboa" }
]
}
JSON
MCPtools/call on https://api.prson.net/mcp/verify
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "create_verification",
"arguments": {
"title": "Confirm you live in Lisbon to join the residents' offer",
"requirements": [
{ "type": "fact", "fact": "address_city_eq_PT_lisboa" }
]
}
}
}
Residence permit
A residence permit read from its chip, and which country issued it.
They verified a residence permit issued by this country.
Example
residence_permit_from_PRT (Residence permit from Portugal)
From
The chip of a residence permit they verified in Prson, checked by Prson
Limits
Needs a residence permit whose chip the person verified in Prson (document type residence_permit); it says which country issued it. It doesn't say what the permit allows (work, study, family) or whether it was revoked; add doc_not_expired to know it hasn't expired. Someone who verified a passport or ID card instead answers no: that isn't evidence they have no permit.
residence_permit_in_eu (Residence permit from an EU country)
From
The chip of a residence permit they verified in Prson, checked by Prson
Limits
Needs a residence permit whose chip the person verified in Prson (document type residence_permit); it says which country issued it. It doesn't say what the permit allows (work, study, family) or whether it was revoked; add doc_not_expired to know it hasn't expired. Someone who verified a passport or ID card instead answers no: that isn't evidence they have no permit.
Holds a residence permit issued by an EU or EEA country.
Example
residence_permit_in_eea (Residence permit from an EU or EEA country)
From
The chip of a residence permit they verified in Prson, checked by Prson
Limits
Needs a residence permit whose chip the person verified in Prson (document type residence_permit); it says which country issued it. It doesn't say what the permit allows (work, study, family) or whether it was revoked; add doc_not_expired to know it hasn't expired. Someone who verified a passport or ID card instead answers no: that isn't evidence they have no permit.
Holds a residence permit issued by a Schengen country.
Example
residence_permit_in_schengen (Residence permit from a Schengen country)
From
The chip of a residence permit they verified in Prson, checked by Prson
Limits
Needs a residence permit whose chip the person verified in Prson (document type residence_permit); it says which country issued it. It doesn't say what the permit allows (work, study, family) or whether it was revoked; add doc_not_expired to know it hasn't expired. Someone who verified a passport or ID card instead answers no: that isn't evidence they have no permit.
They signed in with a code sent by SMS to that number, so they could receive its texts when they verified. A phone verification lasts 365 days. It doesn't say whose name the line is in.
The line type comes from the international numbering plan, not a live lookup with the carrier: a number moved to another network keeps its original range's type. Where the plan doesn't separate mobiles from landlines (the US, Canada and a few others) Prson gives no answer, so the request can't be fulfilled with a yes or no there. Internet (VoIP) numbers are a no. They signed in with a code sent by SMS to that number, so they could receive its texts when they verified. A phone verification lasts 365 days. It doesn't say whose name the line is in.
Their verified phone number belongs to this country's numbering plan.
Example
phone_country_eq_PT (Phone number from Portugal)
From
A code sent by SMS to their phone
Limits
The country comes from the number itself (the international numbering plan), not a live lookup with the carrier: it says nothing about where the person is. They signed in with a code sent by SMS to that number, so they could receive its texts when they verified. A phone verification lasts 365 days. It doesn't say whose name the line is in.
phone_country_in_eu (Phone number from an EU country)
From
A code sent by SMS to their phone
Limits
The country comes from the number itself (the international numbering plan), not a live lookup with the carrier: it says nothing about where the person is. They signed in with a code sent by SMS to that number, so they could receive its texts when they verified. A phone verification lasts 365 days. It doesn't say whose name the line is in.
phone_is_mobile can't be answered for US and Canadian numbers (their numbering plan doesn't separate mobiles from landlines): don't ask it of people there.
Example
POST /v1/verifications
REST (cURL)POST /v1/verifications
curl -X POST https://api.prson.net/v1/verifications \
-H "Authorization: Bearer $PRSON_API_KEY" \
-H "Content-Type: application/json" \
-d @- <<'JSON'
{
"title": "Confirm you have a Portuguese mobile number",
"requirements": [
{ "type": "fact", "fact": "phone_is_mobile" },
{ "type": "fact", "fact": "phone_country_eq_PT" }
]
}
JSON
MCPtools/call on https://api.prson.net/mcp/verify
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "create_verification",
"arguments": {
"title": "Confirm you have a Portuguese mobile number",
"requirements": [
{ "type": "fact", "fact": "phone_is_mobile" },
{ "type": "fact", "fact": "phone_country_eq_PT" }
]
}
}
}
Email
An email address they proved with a code: that it is verified, a work address, at a given domain, or not a throwaway one.
They typed a code sent to that address, so they could read that inbox when they verified. An email verification lasts 180 days. It doesn't say who owns or runs the address.
Email address is at an organisation's own domain, not a free or throwaway provider.
Example
email_work (Work email address (not a free or throwaway provider))
From
A code sent to their email address
Limits
Yes means the domain isn't on Prson's list of free or throwaway providers (gmail.com, outlook.com, yahoo, gmx and others; mailinator.com and others). It doesn't prove an employer or a job title, or that a company runs the domain: a personal domain counts. To ask about one organisation, use email_domain_eq_{domain}. They typed a code sent to that address, so they could read that inbox when they verified. An email verification lasts 180 days. It doesn't say who owns or runs the address.
Their verified email address is at exactly this domain.
Example
email_domain_eq_example.com (Email address at example.com)
From
A code sent to their email address
Limits
The domain must match exactly: mail.example.com and example.com are different. They could read an inbox at that domain when they verified; it doesn't prove they still work or study there, or their role. They typed a code sent to that address, so they could read that inbox when they verified. An email verification lasts 180 days. It doesn't say who owns or runs the address.
email_not_disposable (Email address is not a throwaway one)
From
A code sent to their email address
Limits
Yes means the domain isn't on a short list of throwaway inbox services. The list isn't complete: a rare throwaway service can still pass. They typed a code sent to that address, so they could read that inbox when they verified. An email verification lasts 180 days. It doesn't say who owns or runs the address.
email_work only says the address isn't at a free or throwaway provider. To know someone has an address at one company or school, ask email_domain_eq_{domain} with its domain.
Example
POST /v1/verifications
REST (cURL)POST /v1/verifications
curl -X POST https://api.prson.net/v1/verifications \
-H "Authorization: Bearer $PRSON_API_KEY" \
-H "Content-Type: application/json" \
-d @- <<'JSON'
{
"title": "Confirm you have an example.com email address",
"requirements": [
{ "type": "fact", "fact": "email_domain_eq_example.com" }
]
}
JSON
website_domain_eq_example.com (Controls the website example.com)
From
A DNS record they added to the domain, checked by Prson
Limits
They added a DNS TXT record at _prson-challenge.{domain} that Prson looked up, so they controlled the domain's DNS at that time. It lasts up to 365 days, never past the domain's registration expiry. It doesn't prove who legally owns the domain or the company behind it. The domain must match exactly: www.example.com and example.com are different.
Prson checked the chip of their passport or ID card (level 5 or more).
Example
verification_level_gte_5 (Verified human (identity level 5 or higher))
From
Their verification level in Prson (5 and 6: chip checked by Prson)
Limits
Says how far the identity was checked, not who the person is: no name or document detail is shared. Levels 5 and 6 (a passport or ID card chip checked by Prson) are what Prson calls a verified human; 6 adds a face match between a live selfie and the chip photo. Levels 1 to 4 are checks done on the phone and are never called verified human.
Level 6: chip checked by Prson, plus a face match between a live selfie and the chip photo.
Example
verification_level_gte_6 (Verified human (identity level 6 or higher))
From
Their verification level in Prson (5 and 6: chip checked by Prson)
Limits
Says how far the identity was checked, not who the person is: no name or document detail is shared. Levels 5 and 6 (a passport or ID card chip checked by Prson) are what Prson calls a verified human; 6 adds a face match between a live selfie and the chip photo. Levels 1 to 4 are checks done on the phone and are never called verified human.
At least a photo of an identity document, checked on the phone (never called a verified human).
Example
verification_level_gte_4 (Identity verified to level 4 or higher)
From
Their verification level in Prson (5 and 6: chip checked by Prson)
Limits
Says how far the identity was checked, not who the person is: no name or document detail is shared. Levels 5 and 6 (a passport or ID card chip checked by Prson) are what Prson calls a verified human; 6 adds a face match between a live selfie and the chip photo. Levels 1 to 4 are checks done on the phone and are never called verified human.
At least a live selfie and Face ID on their phone (never called a verified human).
Example
verification_level_gte_3 (Identity verified to level 3 or higher)
From
Their verification level in Prson (5 and 6: chip checked by Prson)
Limits
Says how far the identity was checked, not who the person is: no name or document detail is shared. Levels 5 and 6 (a passport or ID card chip checked by Prson) are what Prson calls a verified human; 6 adds a face match between a live selfie and the chip photo. Levels 1 to 4 are checks done on the phone and are never called verified human.
verification_level_gte_5 is what Prson calls a verified human: the chip of their passport or ID card was read and checked by Prson. verification_level_gte_6 adds a face match between a live selfie and the chip photo.
Instead of a fact, you can set min_verification_level on the verification: only people at that level can answer it. Sign in with Prson gives the same answer as the verified_human claim.
Example
POST /v1/verifications
REST (cURL)POST /v1/verifications
curl -X POST https://api.prson.net/v1/verifications \
-H "Authorization: Bearer $PRSON_API_KEY" \
-H "Content-Type: application/json" \
-d @- <<'JSON'
{
"title": "Confirm you are a real person to join the beta",
"requirements": [
{ "type": "fact", "fact": "verification_level_gte_5" }
]
}
JSON
MCPtools/call on https://api.prson.net/mcp/verify
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "create_verification",
"arguments": {
"title": "Confirm you are a real person to join the beta",
"requirements": [
{ "type": "fact", "fact": "verification_level_gte_5" }
]
}
}
}
Bank
Bank account, balance and income. Coming soon: Prson can't verify these yet, and asking for them is refused.
Has a verified bank account
Coming soon
has_verified_bank_account
Has a verified bank account.
Example
has_verified_bank_account (Has a verified bank account)
From
Bank linking (not available yet)
Limits
Coming soon: Prson can't verify this yet, so asking for it is refused.