URLert API, v1
The URLert API, version 1 (a beta). It checks a link, a message or a page before a program or an AI assistant acts on it, with the same checks as the website. There are six operations, each a POST with a JSON body, with a token made in Account, then AI agents, sent as Authorization: Bearer <token>. There is no operation that deletes a check or an account or changes how you sign in.
The result
Every answer of a check has the same fields. Every field is always there, null or an empty list when it has nothing to say.
status
A closed list. Call get_result until it is done or failed; a failed check is still a 200 answer.
queuedrunningdonefailed
outcome
A closed list. Null until the check is done.
maliciousscamriskysuspiciousnothing_foundcant_tell
failure
An open list. Null unless the check failed.
unavailableour_limittoo_long
views[].state
An open list.
pictureblankhuman_checkprovider_warningrefusedunsupportedgonefilefailedno_responsecut_offslowno_dnscertnot_openedour_limitdaily_limitsite_error
Every call
Address
Every operation is a POST with a JSON body to https://www.urlert.com/api/v1/<operation>.
Token
Authorization: Bearer <token>, a token made in Account, then AI agents.
A call is POST /api/v1/<operation>. A check answers at once with status queued: call get_result every few seconds with its id until status is done or failed. A check that fails is still a 200 answer; read failure. The limit is 20 checks a day for each account, across the API and the AI assistants' tools together; get_result, get_guide and report_mistake don't count, and the count starts again at 00:00 UTC. RateLimit and RateLimit-Policy headers describe the API's call rate, not the daily limit. Send an Idempotency-Key with a check or a report: a repeat of the same call gives back the first answer and doesn't count again. This is a beta: a change that would break a program gets a version 2, and version 1 is retired with a date announced in advance.
Every failure is application/problem+json with status, code, detail (words for a person) and errors (the fields at fault). Branch on code. A 400 bad_request means fix the request. A 400 invalid_text means send the message's text. A 401 invalid_token means make a new token. A 403 insufficient_scope means the token isn't allowed this operation. A 404 not_found says "No check has this id. Checks are deleted after 30 days." and means stop polling. A 409 no_result_yet says "This check has no result to report yet" and means wait until the check is done. A 429 daily_limit says "This account has made 20 checks today. The limit is 20 a day. The count starts again at 00:00 UTC." and a 429 checks_paused says "Checks from assistants and programs are paused until 00:00 UTC. The website still works for people."; both send Retry-After, the seconds until 00:00 UTC, so wait that long and don't spread the calls over more accounts. A 429 rate_limited also sends Retry-After: slow down. A 500 or 503 is ours: retry with backoff, and the checks are safe to retry with an Idempotency-Key.
check_link
Checks one link before you open it or act on it. Answers at once with the check's id and status queued: call get_result with the id until its status is done or failed. Counts as one of the account's 20 checks a day. Can answer 400 bad_request (the link isn't one web link, or country isn't two capital letters), 429 daily_limit or 429 checks_paused.
link text
required
action text or null
optional
task text or null
optional
country text or null
optional
checks_paused 429
Checks from assistants and programs are paused until 00:00 UTC. The website still works for people.
daily_limit 429
This account has made 20 checks today. The limit is 20 a day. The count starts again at 00:00 UTC.
POST https://www.urlert.com/api/v1/check_link
curl -X POST https://www.urlert.com/api/v1/check_link -H "Content-Type: application/json" -H "Authorization: Bearer $TOKEN" -d '{"link":"link","action":"action","task":"task","country":"country"}'{
"id": "id",
"status": "queued",
"outcome": "malicious",
"outcome_name": "outcome_name",
"asks_for": [
"asks_for"
],
"reasons": [
{
"text": "text"
}
],
"sites": [
{
"host": "host",
"domain": "domain",
"age_days": 3,
"age_note": "age_note",
"anyone_can_publish": true,
"scam_lists": [
"scam_lists"
]
}
],
"opened_link": "opened_link",
"final_link": "final_link",
"views": [
{
"device": "device",
"state": "state"
}
],
"reused": true,
"checked_at": "2030-01-15T09:30:00.000Z",
"expires_at": "2030-01-15T09:30:00.000Z",
"failure": "failure",
"message": "message",
"shared_copy": true,
"result_url": "result_url"
}check_message
Checks the text of a message, and the links in it. Answers at once with the check's id: call get_result until its status is done or failed. Counts as one of the account's 20 checks a day. Can answer 400 bad_request (the message is over 5,000 characters, the sender over 200, or country isn't two capital letters), 400 invalid_text (send the message's text), 429 daily_limit or 429 checks_paused.
text text
required
sender text or null
optional
source text or null
optional
action text or null
optional
task text or null
optional
country text or null
optional
checks_paused 429
Checks from assistants and programs are paused until 00:00 UTC. The website still works for people.
daily_limit 429
This account has made 20 checks today. The limit is 20 a day. The count starts again at 00:00 UTC.
invalid_text 400
Send the message's text.
POST https://www.urlert.com/api/v1/check_message
curl -X POST https://www.urlert.com/api/v1/check_message -H "Content-Type: application/json" -H "Authorization: Bearer $TOKEN" -d '{"text":"text","sender":"sender","source":"source","action":"action","task":"task","country":"country"}'{
"id": "id",
"status": "queued",
"outcome": "malicious",
"outcome_name": "outcome_name",
"asks_for": [
"asks_for"
],
"reasons": [
{
"text": "text"
}
],
"sites": [
{
"host": "host",
"domain": "domain",
"age_days": 3,
"age_note": "age_note",
"anyone_can_publish": true,
"scam_lists": [
"scam_lists"
]
}
],
"opened_link": "opened_link",
"final_link": "final_link",
"views": [
{
"device": "device",
"state": "state"
}
],
"reused": true,
"checked_at": "2030-01-15T09:30:00.000Z",
"expires_at": "2030-01-15T09:30:00.000Z",
"failure": "failure",
"message": "message",
"shared_copy": true,
"result_url": "result_url"
}check_page
Checks a page from your own view of it, which we don't open. The views say not_opened. Counts as one of the account's 20 checks a day. Can answer 400 bad_request (the link isn't one web link, or page_text is empty or over 20,000 characters), 429 daily_limit or 429 checks_paused.
link text
required
page_text text
required
action text or null
optional
task text or null
optional
checks_paused 429
Checks from assistants and programs are paused until 00:00 UTC. The website still works for people.
daily_limit 429
This account has made 20 checks today. The limit is 20 a day. The count starts again at 00:00 UTC.
POST https://www.urlert.com/api/v1/check_page
curl -X POST https://www.urlert.com/api/v1/check_page -H "Content-Type: application/json" -H "Authorization: Bearer $TOKEN" -d '{"link":"link","page_text":"page_text","action":"action","task":"task"}'{
"id": "id",
"status": "queued",
"outcome": "malicious",
"outcome_name": "outcome_name",
"asks_for": [
"asks_for"
],
"reasons": [
{
"text": "text"
}
],
"sites": [
{
"host": "host",
"domain": "domain",
"age_days": 3,
"age_note": "age_note",
"anyone_can_publish": true,
"scam_lists": [
"scam_lists"
]
}
],
"opened_link": "opened_link",
"final_link": "final_link",
"views": [
{
"device": "device",
"state": "state"
}
],
"reused": true,
"checked_at": "2030-01-15T09:30:00.000Z",
"expires_at": "2030-01-15T09:30:00.000Z",
"failure": "failure",
"message": "message",
"shared_copy": true,
"result_url": "result_url"
}get_result
A check's result by its id. Does not count against the day's 20 checks. Answers 404 not_found for an id nobody has, or one whose 30 days are over.
id text
required
POST https://www.urlert.com/api/v1/get_result
curl -X POST https://www.urlert.com/api/v1/get_result -H "Content-Type: application/json" -H "Authorization: Bearer $TOKEN" -d '{"id":"id"}'{
"id": "id",
"status": "queued",
"outcome": "malicious",
"outcome_name": "outcome_name",
"asks_for": [
"asks_for"
],
"reasons": [
{
"text": "text"
}
],
"sites": [
{
"host": "host",
"domain": "domain",
"age_days": 3,
"age_note": "age_note",
"anyone_can_publish": true,
"scam_lists": [
"scam_lists"
]
}
],
"opened_link": "opened_link",
"final_link": "final_link",
"views": [
{
"device": "device",
"state": "state"
}
],
"reused": true,
"checked_at": "2030-01-15T09:30:00.000Z",
"expires_at": "2030-01-15T09:30:00.000Z",
"failure": "failure",
"message": "message",
"shared_copy": true,
"result_url": "result_url"
}get_guide
The steps for someone who already acted, most urgent first, or one scam guide. Does not count against the day's 20 checks.
did a list of one of
optional
moneycardinstalledremotepasswordidrepliedassistantopened
scam one of
optional
how-scams-pretendparcel-toll-tax-feesbank-and-card-alertssafe-account-scamsfake-invoicesprizes-and-refundsjobs-and-paid-tasksfake-shopsmarketplaceinvestmentscrypto-walletsthreats-and-blackmailcodes-and-sign-in-requestsfake-sign-in-pagesqr-codesfake-downloadsfake-verify-humantech-supportid-thefthi-mom-new-numberonline-romancecall-or-replyai-assistants
POST https://www.urlert.com/api/v1/get_guide
curl -X POST https://www.urlert.com/api/v1/get_guide -H "Content-Type: application/json" -H "Authorization: Bearer $TOKEN" -d '{"did":["money"],"scam":"how-scams-pretend"}'{
"title": "title",
"steps": [
{
"head": "head",
"body": "body",
"link": "link"
}
],
"good_to_know": [
{
"head": "head",
"body": "body",
"link": "link"
}
],
"guides": [
{
"key": "key",
"title": "title"
}
],
"scam": {
"key": "key",
"title": "title",
"summary": "summary",
"examples": [
"examples"
],
"signs": [
{
"head": "head",
"body": "body",
"link": "link"
}
],
"steps": [
{
"head": "head",
"body": "body",
"link": "link"
}
],
"link": "link"
},
"scams": [
{
"key": "key",
"title": "title"
}
]
}report_mistake
Tells us a result is wrong. One report for each check from each account: a second answers 200 with the first one's sent_at. Does not count against the day's 20 checks. Can answer 404 not_found, or 409 no_result_yet while the check has no result.
id text
required
choice one of
required
missedfalse_alarmother
details text or null
optional, 1 to 1000 characters
no_result_yet 409
This check has no result to report yet
POST https://www.urlert.com/api/v1/report_mistake
curl -X POST https://www.urlert.com/api/v1/report_mistake -H "Content-Type: application/json" -H "Authorization: Bearer $TOKEN" -d '{"id":"id","choice":"missed","details":"details"}'{
"id": "id",
"sent_at": "2030-01-15T09:30:00.000Z"
}Errors
checks_paused 429
Checks from assistants and programs are paused until 00:00 UTC. The website still works for people.
daily_limit 429
This account has made 20 checks today. The limit is 20 a day. The count starts again at 00:00 UTC.
invalid_text 400
Send the message's text.
no_result_yet 409
This check has no result to report yet
invalid_token 401
The token is unknown, revoked or expired: make another on the app's agents page.
insufficient_scope 403
The token is limited to other operations.
outside_token_record 403
The token works within one record, and this would change something outside it: outside it, the token reads only what someone signed out reads.
first_step 403
Its person hasn't taken the app's first step yet, such as agreeing to its terms: detail says where they take it, in the app.
step_up 403
The caller is a member of a record or a holder of an app role that asks more of a sign-in than this session or token showed: need says what, second (a second factor), google (a Google sign-in) or enrol (the person has no second factor yet). Sign in again with it, then make a new token: a token keeps what the sign-in that made it showed.
token_record_left 403
The token works within a record its person no longer belongs to, or that's gone. It works again if they rejoin.
rate_limited 429
Too many calls: wait the seconds Retry-After says, then try again.
idempotency_key_in_use 409
A call with this Idempotency-Key is still running: try again in a second.
idempotency_key_reused 422
This Idempotency-Key was used with another body: a new request needs a new key.
idempotency_unkept 409
The first call with this Idempotency-Key succeeded, but its answer held a secret, which is never kept: read the result with a query, or make a new request with a new key if repeating it is safe.
cursor_mismatch 400
after came from another operation or other params: start again without it.
version_retired 410
The version was retired: move to the newest one.
bad_request 400
unauthorized 401
payment_required 402
forbidden 403
not_found 404
conflict 409
gone 410
unprocessable_content 422
too_many_requests 429
internal_server_error 500
service_unavailable 503