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_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

Request
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"}'
Answer
{
  "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

Request
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"}'
Answer
{
  "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

Request
curl -X POST https://www.urlert.com/api/v1/get_result -H "Content-Type: application/json" -H "Authorization: Bearer $TOKEN" -d '{"id":"id"}'
Answer
{
  "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

Request
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"}'
Answer
{
  "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

Request
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"}'
Answer
{
  "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