serpยทbase API Documentation

Forms: one tool, three modes

Read a form before you touch it, send an application, or send it and solve the captcha on the way. The mode is a parameter, not a separate endpoint.

inspect $1.00 · submit $2.00 / 1,000 POST /v1/query read mode sends nothing

Overview

Sending a form blind is how people get blocked, accused of spam, or post an empty request to a client. So the tool starts in the safest mode and only does more when you ask.

modeWhat happensPrice / 1,000
inspect (default) Finds the forms on the page and returns their schema: action, method, every field with its HTML type, required flags, choices, hidden CSRF fields — and a captcha verdict with the recognised type and sitekey. Nothing is submitted. $1.00
submit Sends one form with the values you provide, then checks whether it was actually accepted (success phrase, changed URL, or JSON echo of the fields). $2.00
submit_captcha Same as submit, but solves the captcha first and injects the token into the field the form expects. The captcha solution is billed as a separate line — it costs about ten times the form call, so you see it. $2.00 + captcha

What we refuse to send — in code, not in policy text

Fields you pass that are not part of the form are ignored, and so is a reset button. Hidden fields (CSRF tokens) are forwarded exactly as the page provides them. Missing required fields are rejected before anything is sent (and before any captcha is paid for).

curl -X POST https://api.serp-base.com/v1/query \
  -H "Content-Type: application/json" \
  -d '{"tool": "form_action", "query": "https://example.com/contact", "mode": "inspect"}'

Parameters

FieldTypeRequiredDescriptionExample
urlstringyesPage with the form (absolute http/https URL). query is an alias.https://example.com/contact
modestringnoinspect (default) · submit · submit_captcha.submit
valuesobjectfor submitField name to value. Only fields that exist in the form are sent.{"name": "Ivan"}
form_indexintnoWhich form on the page (default 0). Use mode=inspect to list them.0
robotsboolnoRespect robots.txt. Default true.true

Code examples

Read the form first (recommended)

import requests

BASE = "https://api.serp-base.com/v1/query"

# 1) read โ€” finds fields, required flags and any captcha
r = requests.post(BASE, json={
    "tool": "form_action",
    "query": "https://example.com/contact",
    "mode": "inspect",
})
data = r.json()["data"]
print(data["forms_found"], "forms, captcha:", data["captcha"])
for form in data["forms"]:
    print(form["method"], form["action"], "submit_allowed:", form["submit_allowed"])
    for f in form["fields"]:
        print("  ", f["name"], f["type"], "required" if f.get("required") else "")

# 2) send โ€” only once you know what the form wants
r = requests.post(BASE, json={
    "tool": "form_action",
    "query": "https://example.com/contact",
    "mode": "submit",
    "values": {"name": "Ivan", "email": "[email protected]", "message": "Hello"},
})
print(r.json()["data"]["status"])

cURL — submit with captcha

curl -X POST https://api.serp-base.com/v1/query \
  -H "Content-Type: application/json" \
  -d '{"tool": "form_action", "query": "https://example.com/contact",
       "mode": "submit_captcha",
       "values": {"name": "Ivan", "email": "[email protected]", "message": "Hello"}}'

JavaScript

const r = await fetch('https://api.serp-base.com/v1/query', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    tool: 'form_action',
    query: 'https://example.com/contact',
    mode: 'inspect',
  }),
});
const { data } = await r.json();
console.log(data.forms_found, data.captcha);

PHP

$ch = curl_init('https://api.serp-base.com/v1/query');
curl_setopt_array($ch, [
  CURLOPT_POST => true,
  CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
  CURLOPT_POSTFIELDS => json_encode([
    'tool' => 'form_action',
    'query' => 'https://example.com/contact',
    'mode' => 'inspect',
  ]),
  CURLOPT_RETURNTRANSFER => true,
]);
$data = json_decode(curl_exec($ch), true)['data'];

Response

mode=inspect — the form schema, nothing sent:

{
  "ok": true,
  "data": {
    "url": "https://example.com/contact",
    "forms_found": 1,
    "forms": [
      { "index": 0, "action": "https://example.com/contact", "method": "POST",
        "fields_count": 4, "submit_allowed": true, "blocked_reason": null,
        "fields": [
          { "name": "name",    "type": "text",     "required": true },
          { "name": "email",   "type": "email",    "required": true },
          { "name": "message", "type": "textarea", "required": true },
          { "name": "csrf_token", "type": "hidden", "value_prefill": "a1b2c3" }
        ] }
    ],
    "captcha": null,
    "submit_requires_captcha": false,
    "note": "This is READ mode: nothing was submitted."
  }
}

mode=submit — the verdict:

{
  "ok": true,
  "data": {
    "status": "submitted",
    "http_status": 200,
    "final_url": "https://example.com/thanks",
    "sent_fields": ["csrf_token", "email", "message", "name"],
    "ignored_fields": [],
    "detail": "success marker found in the response"
  }
}

mode=submit_captcha — adds the captcha and a transparent price split:

{
  "ok": true,
  "data": {
    "status": "submitted",
    "captcha": { "type": "recaptcha", "token_field": "g-recaptcha-response", "token_length": 2510 },
    "cost_breakdown": {
      "form_call": 0.19,
      "captcha_solution": 1.9,
      "note": "captcha solution is billed as a separate line - it costs ~10x the form call"
    }
  }
}

status values: submitted (a real confirmation signal was found), submitted_rejected (the response carries a rejection marker), submitted_unconfirmed (HTTP 200 but no proof either way — not charged).

Payment

modePrice / 1,000Charged when
inspect$1.00the page was read and the schema returned
submit$2.00the submission is confirmed
submit_captcha$2.00 + captchaconfirmed + the captcha solution, shown separately

Refusals (password, payment, captcha refused, missing required fields) are free and carry a reason. Reading costs less than sending because it does less.

Errors

CodeMeaningAction
402Payment requiredSign the payment and retry with X-PAYMENT
400Bad parametersCheck url, mode, values
422Refused or unconfirmedThe error text explains why — nothing charged
503Tool temporarily unavailableRetry later — nothing charged

Related tools

Scraping: URL to data · Captcha: reCAPTCHA V2 · Extract data by schema

Proxy routing

Requests to the target site never leave from our infrastructure address. Each call is routed through a proxy: your own if you set one, a proxy you buy from us, or our system proxy which is included and needs no setup. Set your own once with POST /v1/proxy/own, or buy a dedicated IPv4 by country and period via POST /v1/proxy/buy. See Proxies.

Pay-per-request data APIs. Built for agents and developers.