SPAMADIN / DEVELOPERS

A clear path from
submission to decision.

Connect your backend to Spamadin. Keep your Spamadin API key on your server. Save submissions in your own system before making a classification request.

Build with your coding assistant

Give your coding assistant our integration reference and OpenAPI specification to build a server-side connection for your website.

Integration reference · OpenAPI specification · AI documentation index

WordPress plugin

Install Spamadin in WordPress and paste your account API key into Settings → Spamadin. Use the same key on every website in your plan. Connecting adds the website automatically within your plan’s limit and securely stores the key on your WordPress server.

Download the WordPress plugin

Comments and supported contact forms are protected by default. Contact Form 7, WPForms, Gravity Forms, Fluent Forms and Elementor Pro are supported. You can change protection and optional browser evidence in the plugin settings.

Spam comments stay in WordPress’s spam queue; uncertain or unavailable checks go to moderation. Held form messages stay privately in Settings → Spamadin for up to 30 days. Review them there and contact legitimate senders directly; form actions are not replayed. Corrections share only a check reference and label, never the message body.

Disconnecting the plugin stops local checks. Block the website in your Spamadin dashboard to stop its API requests and free its website slot. Reconnecting cannot unblock it. Rotating your account key requires updating every integration.

1. Create an account and key

Verify your email, choose a subscription in the dashboard, and create one account API key. Reuse it across all your websites. Each allowed hostname uses one website slot; example.com and www.example.com count separately. Keys are shown once and stored using Argon2id.

Your Spamadin key authenticates requests to this service and is separate from our internal AI provider credentials. Your subscription includes classification; you do not need an OpenRouter account or key.

2. Check a submission

Describe your website when connecting it. Spamadin uses AI to categorize it and includes that context in future checks. Disable a website in your dashboard to stop its requests and free a website slot. After a downgrade, the oldest enabled websites within your plan limit stay active; disable an older website to enable another.

POST /api/v1/check · JSON body · Authorization: Bearer YOUR_SERVER_KEY

curl https://spamadin.com/api/v1/check \
  -H 'Authorization: Bearer YOUR_SERVER_KEY' \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: 45573012-1f18-4eaf-97a1-29702376ea21' \
  -d '{
    "type": "contact",
    "siteUrl": "https://example.com",
    "content": "Can you send a quote for our new website?",
    "context": { "title": "Website design", "language": "en" },
    "signals": { "elapsedMs": 8500, "honeypotFilled": false }
  }'

Bulk checks

Send up to 20 submissions to POST /api/v1/check/bulk using your account API key. Items can belong to different websites in your account. Each item needs a unique UUID id and a submission object. Responses preserve order and include each item’s status and result. Retry with the same id and unchanged submission. Website limits, blocks and the shared monthly allowance apply to every item.

{
  "checks": [
    {
      "id": "45573012-1f18-4eaf-97a1-29702376ea21",
      "submission": {
        "type": "contact",
        "siteUrl": "https://example.com",
        "content": "Can you send a quote?"
      }
    }
  ]
}

Form-specific context

Create a form profile in your dashboard using its purpose, field labels, and relevant public text. Review and save the suggested summary, then include its formId in single or bulk checks. Use reader_comment profiles with comment submissions and other profiles with contact submissions. Profiles provide context, not an automatic permission to send promotional messages.

{
  "formId": "d495b23a-cf83-4c3d-bd63-6973297ec401",
  "type": "contact",
  "siteUrl": "https://example.com",
  "content": "Can you send a quote?"
}

Use a fresh UUID Idempotency-Key per submission. Retry the same payload with the same key after network errors. A completed retry returns the existing decision without a second charge. Keys are retained with check metadata for 30 days; do not retry older submissions.

FieldPurposeLimit
contentOriginal message text; required1–12,000 characters
typecontact or comment; requiredExact enum
siteUrlWebsite URL; required. New sites register automatically within your plan limit.HTTP(S), 2,048 characters
context.title / descriptionRelevant page context provided by your server200 / 1,000 characters
context.language / tagsSite language and up to ten topic tags35 / 50 characters
signals.elapsedMsTime between form display and submission0–86,400,000 ms
signals.honeypotFilledWhether a hidden field was filledBoolean
signals.userAgent / userIpOptional integration metadata; not sent to models512 characters / valid IP

Derive context and behavior on your server. Browser timestamps can be forged. For future CMS plugins, sign the form-render timestamp and validate it on submission, use a honeypot with an accessibility-safe implementation, and hook into the CMS’s server-side comment/form lifecycle. Do not forward cookies, authorization headers, passwords, full environment variables, or other secrets.

3. Preserve the uncertain

{
  "id": "c18dd105-5d52-4939-a63e-0d52b2c0606d",
  "verdict": "allow",
  "score": 0,
  "reasons": ["clear_legitimate_context"],
  "degraded": false,
  "latencyMs": 420,
  "charged": true
}

This is an illustrative response, not a latency guarantee. Score is an ordinal risk indicator: 0 (allow), 50 (review), or 100 (strong spam agreement). It is not a calibrated probability.

Automatic spam classification starts in shadow mode until the operator enables an evaluated blocking policy. If your network call fails or returns any non-2xx status, save for review rather than discarding or retrying indefinitely.

4. Report a correction

POST /api/v1/feedback with the same Bearer API key and JSON {"id":"CHECK_UUID","label":"legitimate"} or label spam. Feedback is restricted to checks created by that key. It records a correction for evaluation; it does not modify shared training or immediately whitelist a sender.

You can also record a correction in your dashboard and contact support with the check reference. We can adjust context and caution for your website. Do not email private submission contents, passwords, or API keys. Check references remain available for 30 days.

Limits and error handling

Report a classification mistake

Report a genuine message marked as spam to POST /api/v1/reports/false-positive, or missed spam to POST /api/v1/reports/missed-spam. Send only the returned check ID using your account API key. Reports share no message content and use no spam checks. The latest correction wins; reports do not instantly retrain a model.

{
  "id": "c18dd105-5d52-4939-a63e-0d52b2c0606d"
}

Privacy by default

Routine checks retain metadata and a keyed input digest for 30 days, without storing message bodies. Common email and phone patterns are redacted before AI processing; this is minimization, not complete anonymization. Voluntarily shared training examples are stored separately under the privacy policy.

Optional invisible form checks

Call POST /api/v1/form-token from your server with siteUrl, type, and an optional saved formId. Tokens expire after 30 minutes. Issuing a token does not consume a spam check and requires active website access.

Send the returned token in signals.formToken and use the returned idempotencyKey as your Idempotency-Key header. In bulk checks, use it as the item id. Retries must preserve the original request exactly. Use a new token for a new submission.

Load /spamadin-behavior.js on your website and attach it to your form. Your same-origin token endpoint calls Spamadin from your server and returns only the public form token response. Never expose your API key or embed shared tokens in cached pages.

SpamadinBehavior.attach(document.querySelector("#contact-form"), {
  tokenEndpoint: "/form-evidence/token"
});

The helper adds a hidden spamadin_evidence field containing token, idempotencyKey, and browser evidence. Validate that field on your server, map browser to signals.browser, and forward token as signals.formToken. Browser evidence uses version 1, jsExecuted, focusCount, editCount, pasteCount, keyboardUsed, pointerUsed, and optional firstInteractionMs. Your server may also send honeypotFilled and the visitor IP.

These signals support classification; they never establish spam by themselves. Pasting, autofill, missing JavaScript, and assistive technology can all be legitimate. Timing measures time since token issuance, not proof of human activity. Missing or expired tokens do not automatically reject messages.

The helper does not record typed text, clipboard contents, mouse trails, or cookies. Tokens and interaction summaries are not stored in check history or sent as credentials to AI providers. Checks with browser evidence always run classification rather than reusing a cached verdict.

Repeat recognition

Repeat recognition is scoped to each website. Fingerprints expire after 24 hours and contain no saved message text. Similar wording supports classification; it never establishes spam on its own. Turn recognition off in website settings to clear its history and approved campaign signals. Blocking a website or reporting a correction also clears its recent fingerprint history.

Eligible identical checks may reuse a recent genuine-message verdict only when that feature has been evaluated and enabled. Reuse is limited to five minutes and requires unchanged submission data, website and form settings, model configuration, and detection policy. Fuzzy matches never bypass AI. Every completed check still counts once toward your allowance, including a reused verdict; failed provider checks remain uncharged.

Share a corrected training example

POST /api/v1/training with the original key, checkId, corrected label, unchanged original submission object, and both sharing acknowledgments set to true. The check must be completed and less than 30 days old. Sharing is optional, does not consume a spam check, and does not immediately retrain a model. Keep this request on your backend and provide the required notices and lawful authority before sharing visitor content.

{
  "checkId": "c18dd105-5d52-4939-a63e-0d52b2c0606d",
  "label": "legitimate",
  "submission": {
    "type": "contact",
    "siteUrl": "https://example.com",
    "content": "Can you send a quote?"
  },
  "consent": {
    "authorizedToShare": true,
    "useForSpamImprovement": true
  }
}

GET /api/v1/training lists your account’s shared-example references. Use ?after=EXAMPLE_UUID for the next page or ?id=EXAMPLE_UUID to retrieve a minimized example. DELETE the same endpoint with the example id to withdraw it. Your dashboard also lets you withdraw examples after your account key is revoked.

Examples expire after 90 days. Limits: 500 examples or 2 MiB of encrypted payload per account, 16 KiB of original message text per example, and 24 KiB of minimized content and context before compression. Requests remain limited to 32 KiB. A full account returns 429; temporary platform capacity or unavailable encryption returns 503. No example is stored when a limit rejects the request. Do not retry indefinitely or send private attachments. Redaction is best-effort, not anonymization.

The API never visits submitted URLs. Optional visitor IPs support short-term, website-scoped burst evidence; user agents do not affect classification. Neither is sent to models. Use our WordPress plugin or connect other CMS platforms through the server API.

Create your account ↗