Agencies and B2B

Answer the clients, and sort out everybody else first

Contact form messages and the email threads that follow, read for who is writing and what they want. ToxicFilter tells the buyer with a budget apart from the agency pitching you, the CV sent to the sales form and the founder who wants a whole platform for a slice of a company, and only acts where your rules say so.

What goes wrong on platforms like yours

Sales pitches in the sales inbox

"I came across your website", "we are an agency that specializes in", "book a quick call". The form you built for clients fills with people selling you SEO, developers and lead generation, and whoever answers it reads every one before finding the enquiry that pays.

Free work dressed as an opportunity

An idea, a share of a company that does not exist yet, no budget and a promise to pay once there is money. Nobody says it in one sentence: the equity is in one email, the missing budget in the next and the extra features in a third, and only the whole thread shows what is being asked.

The wrong door

A CV sent to the sales form, a student asking for a survey, a customer whose invoice did not arrive. None of them is abuse and none of them belongs in the pipeline either: they belong with somebody else.

Link spam and keyboard mash

Backlinks for sale, three shortened links and nothing else, a bot filling every field with noise. Cheap to send, and each one costs a person a minute.

What it decides, on content like yours

Judged right now by the engine the API uses, under the template for this kind of platform, with no model involved.

  1. 01 A platform for equity, over three emails
  2. 02 A cold agency pitch
  3. 03 A CV sent to the sales form
  4. 04 Backlinks for sale
  5. 05 A real enquiry with a budget

A platform for equity, over three emails POST /v1/conversation

founder Hi, I have an idea for a marketplace like Airbnb for boats.

agency Sounds interesting, what is your budget?

founder We don't have a budget yet. I can offer you equity, 2.5% of the company, and we will pay you when we make money. You build the whole product.

agency We usually work on a paid basis.

founder It should be easy, nothing complicated, and good for your portfolio.

review 28 ms

His messages score 0.90 as free work for equity, 0.70 as no budget and 0.70 as unrealistic expectations, and all three come back in leads. The contact form template holds free work for equity and no budget from 0.60 and never refuses them, so the thread waits for a person: answering, or declining politely, is your call.

The answer, abridged
{
  "decision": "review",
  "flagged": [
    "lead:free_work_for_equity",
    "lead:no_budget"
  ],
  "leads": {
    "free_work_for_equity": 0.9,
    "no_budget": 0.7,
    "unrealistic_expectations": 0.7
  },
  "signals": [],
  "model": {
    "read": false
  },
  "took_ms": 28
}

A cold agency pitch POST /v1/text

Hi, I came across your website and we are an agency that specializes in web development and SEO. Special offer until the end of the quarter: book a quick call and we will send our portfolio.

block 9 ms

An offer, a list of services, the outreach line and a deadline: four families of a pitch score 0.90, over the template's 0.85 block line for sales pitches. Two of them alone score 0.70 and are held for review instead.

The answer, abridged
{
  "decision": "block",
  "flagged": [
    "lead:sales_pitch"
  ],
  "leads": {
    "sales_pitch": 0.9
  },
  "signals": [],
  "model": {
    "read": false
  },
  "took_ms": 9
}

A CV sent to the sales form POST /v1/text

Hello, I am looking for a job as a front-end developer. Attached is my resume, and I have worked as a React developer for three years. Do you have any openings?

review 9 ms

Held, never refused: the template holds job seekers from 0.60 and has no block line for them, so the message can go to whoever hires instead of the bin.

The answer, abridged
{
  "decision": "review",
  "flagged": [
    "lead:job_seeker"
  ],
  "leads": {
    "job_seeker": 0.9
  },
  "signals": [],
  "model": {
    "read": false
  },
  "took_ms": 9
}

Backlinks for sale POST /v1/text

Hey! Cheap backlinks and guest posts, DA 90+, best price: https://seo-links.example https://seo-links.example/buy https://bit.ly/3xYz

block 8 ms
  • 3 links in about 20 words: mostly links, barely a message.
  • Uses a link shortener, which hides where the link goes.

Three links in twenty words, one of them shortened: that is spam on its own, settled by the free checks with no model. A single link in a real enquiry is not.

The answer, abridged
{
  "decision": "block",
  "flagged": [
    "spam"
  ],
  "scores": {
    "spam": 0.75
  },
  "leads": {
    "sales_pitch": 0.45
  },
  "signals": [
    {
      "category": "spam",
      "score": 0.75,
      "reason": "3 links in about 20 words: mostly links, barely a message.",
      "evidence": [
        "https://seo-links.example",
        "https://seo-links.example/buy",
        "https://bit.ly/3xYz"
      ]
    },
    {
      "category": "spam",
      "score": 0.7,
      "reason": "Uses a link shortener, which hides where the link goes.",
      "evidence": [
        "https://bit.ly/3xYz"
      ]
    }
  ],
  "model": {
    "read": false
  },
  "took_ms": 8
}

A real enquiry with a budget POST /v1/text

Hi, we are a 20-person logistics company in Leeds looking for an agency to build a customer portal. Our budget is around 40,000 GBP and we would like to start in January. Could you send us a quote?

allow 8 ms

Who they are, what they want, a budget and a date. Nothing scores, on any axis, and the free checks answer in about a millisecond.

The answer, abridged
{
  "decision": "allow",
  "flagged": [],
  "signals": [],
  "model": {
    "read": false
  },
  "took_ms": 8
}

What it decides, on content like yours

Judged right now by the engine the API uses, under the template for this kind of platform, with no model involved.

A platform for equity, over three emails POST /v1/conversation

founder Hi, I have an idea for a marketplace like Airbnb for boats.

agency Sounds interesting, what is your budget?

founder We don't have a budget yet. I can offer you equity, 2.5% of the company, and we will pay you when we make money. You build the whole product.

agency We usually work on a paid basis.

founder It should be easy, nothing complicated, and good for your portfolio.

review 28 ms

His messages score 0.90 as free work for equity, 0.70 as no budget and 0.70 as unrealistic expectations, and all three come back in leads. The contact form template holds free work for equity and no budget from 0.60 and never refuses them, so the thread waits for a person: answering, or declining politely, is your call.

The answer, abridged
{
  "decision": "review",
  "flagged": [
    "lead:free_work_for_equity",
    "lead:no_budget"
  ],
  "leads": {
    "free_work_for_equity": 0.9,
    "no_budget": 0.7,
    "unrealistic_expectations": 0.7
  },
  "signals": [],
  "model": {
    "read": false
  },
  "took_ms": 28
}

A cold agency pitch POST /v1/text

Hi, I came across your website and we are an agency that specializes in web development and SEO. Special offer until the end of the quarter: book a quick call and we will send our portfolio.

block 9 ms

An offer, a list of services, the outreach line and a deadline: four families of a pitch score 0.90, over the template's 0.85 block line for sales pitches. Two of them alone score 0.70 and are held for review instead.

The answer, abridged
{
  "decision": "block",
  "flagged": [
    "lead:sales_pitch"
  ],
  "leads": {
    "sales_pitch": 0.9
  },
  "signals": [],
  "model": {
    "read": false
  },
  "took_ms": 9
}

A CV sent to the sales form POST /v1/text

Hello, I am looking for a job as a front-end developer. Attached is my resume, and I have worked as a React developer for three years. Do you have any openings?

review 9 ms

Held, never refused: the template holds job seekers from 0.60 and has no block line for them, so the message can go to whoever hires instead of the bin.

The answer, abridged
{
  "decision": "review",
  "flagged": [
    "lead:job_seeker"
  ],
  "leads": {
    "job_seeker": 0.9
  },
  "signals": [],
  "model": {
    "read": false
  },
  "took_ms": 9
}

Backlinks for sale POST /v1/text

Hey! Cheap backlinks and guest posts, DA 90+, best price: https://seo-links.example https://seo-links.example/buy https://bit.ly/3xYz

block 8 ms
  • 3 links in about 20 words: mostly links, barely a message.
  • Uses a link shortener, which hides where the link goes.

Three links in twenty words, one of them shortened: that is spam on its own, settled by the free checks with no model. A single link in a real enquiry is not.

The answer, abridged
{
  "decision": "block",
  "flagged": [
    "spam"
  ],
  "scores": {
    "spam": 0.75
  },
  "leads": {
    "sales_pitch": 0.45
  },
  "signals": [
    {
      "category": "spam",
      "score": 0.75,
      "reason": "3 links in about 20 words: mostly links, barely a message.",
      "evidence": [
        "https://seo-links.example",
        "https://seo-links.example/buy",
        "https://bit.ly/3xYz"
      ]
    },
    {
      "category": "spam",
      "score": 0.7,
      "reason": "Uses a link shortener, which hides where the link goes.",
      "evidence": [
        "https://bit.ly/3xYz"
      ]
    }
  ],
  "model": {
    "read": false
  },
  "took_ms": 8
}

A real enquiry with a budget POST /v1/text

Hi, we are a 20-person logistics company in Leeds looking for an agency to build a customer portal. Our budget is around 40,000 GBP and we would like to start in January. Could you send us a quote?

allow 8 ms

Who they are, what they want, a budget and a date. Nothing scores, on any axis, and the free checks answer in about a millisecond.

The answer, abridged
{
  "decision": "allow",
  "flagged": [],
  "signals": [],
  "model": {
    "read": false
  },
  "took_ms": 8
}

What it looks for

Each a score of its own, with its own lines, and the reason in a sentence whenever one acts.

The template you start from

Pick it when you create a policy and these rules are written for you, ready to edit. Everything it does not mention keeps following our defaults.

  • Spam holds at 0.35 · refuses at 0.65
  • Filter evasion holds at 0.35 · refuses at 0.70
  • Gibberish holds at 0.45 · never refuses
  • Off-topic language holds at 0.35 · never refuses
  • Toxicity holds at 0.60 · never refuses
  • Harassment holds at 0.60 · refuses at 0.90
  • Hate speech holds at 0.55 · refuses at 0.80
  • Violence holds at 0.55 · refuses at 0.85
  • Sales pitch holds at 0.60 · refuses at 0.85
  • Job seeker holds at 0.60 · never refuses
  • Free work for equity holds at 0.60 · never refuses
  • No budget holds at 0.60 · never refuses

Set by the template

One call before you publish

Send the text with where it will appear, and act on the decision.

The request

curl https://toxicfilter.com/api/v1/text \
  -H "Authorization: Bearer $TOXICFILTER_KEY" \
  -d content="Hi, I have an idea for a marketplace like Airbnb for boats." \
  -d surface=comment
The full reference →

A month, in numbers

Items checked
3,000
Read by the model
600
Images
0
Credits, about
7,200

Fits in the Plus plan. See the plans →

A guide to qualifying leads from a contact form

What to check, how lead types are scored and how to write the rules, for contact forms and the email threads that follow them.

How to filter spam and sales pitches from a contact form

Call the API when the form is submitted and act on one of three answers: send it to the pipeline, hold it for a person, or drop it. Link spam, words disguised to get past a filter and the same message sent forty times from one script are findings in spam and evasion, and the contact form template holds or refuses them depending on how strong they are. Keyboard mash lands in gibberish, which the template holds and never refuses. The address on the form can go to /v1/email, which reports throwaway providers.

Classifying leads by type: who is writing to you

A lead type is not a harm and not a subject, so it lives on its own axis, leads, beside scores and topics. Every answer measures all eleven types, and none of them decides anything until a policy gives it a line. The contact form template writes four: sales_pitch held from 0.60 and refused from 0.85, and job_seeker, free_work_for_equity and no_budget held from 0.60 and never refused. Scope creep, free consulting and the rest are measured and reported, and acting on them is a rule you add.

How a lead type is scored

One family of phrases is how honest people write, so it scores 0.45. Two families score 0.70 and three or more 0.90, so a line around 0.60 acts on the shape and not on a word. Some types need their defining family: free work for equity needs the equity or the missing pay, because an idea alone is not a request for free work, and free consulting needs the missing budget, because a request for proposal with a budget is a real one. Wording that settles the question silences a type ("salary plus equity" is a job), and pressure ("I have invested years", "you only care about money") adds 0.10 to free work and no budget when they are already there. Longer phrases match loosely, in any order and with any ending, while negations are kept, so "no budget" never turns into its opposite.

Reading the whole thread, not one message

Nobody asks for free work in one sentence. Send the thread to /v1/conversation with an author on each message and the person being judged is read across everything they wrote, while your replies are left out. Missed calls are counted once per message of theirs. Nothing about the thread is stored: what is kept is the verdict on the last message.

Two readers, and the messages rather than the person

The phrase lists settle the familiar shapes in about a millisecond, in eight languages, and a single family scores 0.45, which means very little on its own, so honest enquiries are left alone. When you allow it, the model reads the thread for what the wording leaves to context. A lead type is never a finding about the person, only about what the messages ask for.

Setting the rules for your inbox

Start from the contact form template. Look at a month of leads on your own traffic before you write a rule for another type, then try it as a second policy running beside the one in force: both verdicts are computed, only one acts, and the dashboard shows where they disagree before you switch.

Frequently asked questions

How do I stop sales pitches arriving through my contact form?

Send each message to the API and act on the answer. The pitch is recognised by its families: an offer ("we are an agency", "we specialize in"), services (web development, SEO, lead generation, backlinks), outreach ("I came across your website", "book a call") and scarcity ("special offer", "free audit"). Two families score 0.70 and the contact form template holds them; three or more score 0.90 and it refuses them.

What lead types can it recognise?

Eleven: free work for equity, no budget, unrealistic expectations, free consulting, scope creep, never turns up, sales pitch, partnership offer, job seeker, student or survey, and support request. Each is scored on its own, because one person is often several at once, and returned in leads with every answer.

Will it refuse a real client who happens to run an agency?

A buyer's own words silence the pitch check: "we need a", "we are looking for a", "looking to hire", "how much would it cost" and "request a quote" mean the person is asking to buy. A sales pitch is also never decided by one word: one family alone scores 0.45, under every line the template sets.

Can it read a whole email thread?

Yes, through /v1/conversation with an author on each message. It reads only the messages of the person being judged, so your own replies never count against them. Missed calls are counted per message: one apology is normal, two is 0.70 and three is 0.90.

Does the model read lead types too?

When you allow it, the model reads the earlier messages of the thread and scores every lead type for the person writing, in the same call and at no extra cost; the higher of its score and the phrase lists wins. In a conversation it reads when the free checks found something, when a lead type is half there, or every fifth message, rather than on every reply.

Which languages does it work in?

The phrase lists for lead types cover English, Spanish, Portuguese, French, Italian, German, Catalan and Dutch. The model reads many more. Outside those eight, the model is what reads them, and effort high brings it in.

Try it on your own traffic

2,000 credits a month on the free plan, no card. Enough to send a week of your own content and see what it says about it.