BuckhyDeveloper Platform

Reference

Form Capture API

The complete contract for POST /v1/capture: authentication, request body, field rules, responses, idempotency, rate limits and data retention.

Endpoint

Method URL Purpose
POST https://api.buckhy.com/v1/capture Store one form submission for the site the key belongs to

Requests and responses are JSON. Every response carries a success boolean; failures add a human-readable message (see Errors).

Authentication

POST /v1/capture HTTP/1.1
Host: api.buckhy.com
Content-Type: application/json
X-Api-Key: bk_live_…
Idempotency-Key: 5d3f0c2e-6a1b-4c8e-9e2f-0b1a2c3d4e5f
  • X-Api-Key carries the site key. The key is a secret: send it from your server only. X-Service-Key is accepted as an alias.
  • Keys are verified by hash; the plaintext is never stored.
  • The key must belong to a Form Capture site whose status is active.

Call the endpoint server to server. Browser requests from your own domain are refused by CORS (403, code CORS_ORIGIN_DENIED).

Request body

{
  "form": "partner",
  "page": "/partner?utm_source=ig",
  "fields": {
    "name": "Priya Sharma",
    "email": "priya@example.com",
    "company": "Midnight Strings",
    "message": "We'd like to perform at the September show."
  },
  "context": {
    "ip": "203.0.113.24",
    "userAgent": "Mozilla/5.0 (iPhone; CPU iPhone OS 17_5 like Mac OS X) …",
    "referrer": "https://www.instagram.com/",
    "landingPage": "/events/acoustic-show",
    "language": "en-IN",
    "timezone": "Asia/Kolkata",
    "screen": "390x844",
    "utm": { "source": "ig", "medium": "social", "campaign": "sept" }
  }
}
Property Type Required Rules
fields object yes At least one field. See Field rules.
form string no ≤ 40 characters. Defaults to the site's default form (contact unless changed).
page string no ≤ 200 characters. The page the form was submitted from.
context object no Visitor details; see Visitor context.

Unknown top-level properties are ignored.

Field rules

fields is a flat object of strings. Buckhy sanitises it before storing:

Rule Detail
Maximum fields 20 per submission — extra fields are dropped in object order.
Field names Trimmed to 40 characters; only A–Z a–z 0–9 _ - are kept. A name that becomes empty is dropped.
Values Converted to strings, trimmed, cut at 2,000 characters. null and undefined values are dropped.
Nested objects / arrays Stringified. Send flat fields.
Honeypots Not filtered here — drop your honeypot field on your server before posting.

Field names are free-form; the console searches every value regardless of the name and picks the contact from common names (name, fullName, email, company, …).

Visitor context

context is optional. Each property is validated independently and dropped if malformed.

Property Accepted Stored as
ip IPv4 or IPv6 literal Derived country / countryCode; the raw address is kept for 30 days, then removed.
userAgent ≤ 500 chars Derived device label plus the raw string.
referrer http(s):// URL ≤ 500 As sent.
landingPage Path beginning with / ≤ 300 As sent.
language BCP 47 tag As sent.
timezone IANA zone name As sent.
screen <w>x<h>, 2–5 digits each As sent.
utm source medium campaign term content, each ≤ 120 As sent; empty keys dropped.

Country lookup uses an offline database and fails open: if the address cannot be resolved the submission is still stored, with country: null.

Responses

Status When Body
201 Created Stored { "success": true, "id": "…" }
200 OK Replay of an Idempotency-Key with identical content { "success": true, "id": "…", "duplicate": true }
400 fields missing or empty { "success": false, "message": "fields are required" }
401 No key { "success": false, "message": "missing service key" }
401 Unknown or revoked key { "success": false, "message": "invalid or revoked developer key" }
403 Key is not a Form Capture key { "success": false, "message": "this key cannot capture form submissions" }
403 Site disabled { "success": false, "message": "capture site is not active" }
403 Browser request { "message": "Not allowed by CORS", "code": "CORS_ORIGIN_DENIED" }
409 Idempotency-Key reused with different content { "success": false, "message": "this idempotency key was already used with different content" }
429 Rate limit { "success": false, "message": "Too many form submissions, please try again later" }
503 Key verification unavailable { "success": false, "message": "key verification unavailable" } — retry with backoff

id is the submission's permanent identifier; it appears in the console's record drawer and CSV export.

Idempotency

Send an Idempotency-Key header to make retries safe.

  • Format: 8–100 characters from A–Z a–z 0–9 _ -. A UUID is ideal. Malformed keys are ignored, never rejected.
  • Scope: per site. The same key on two different sites is two different submissions.
  • Match: the key plus a fingerprint of form, page and fields (field order does not matter).
  • Same key, same content → 200 with the original id and duplicate: true. One email, one record.
  • Same key, different content → 409. Generate a new key when the visitor edits and resubmits.
  • Concurrent identical retries are safe: a unique index elects one winner and the other request returns the winner's record.

Generate the key once per submission attempt in the browser, pass it through your server, and reuse it when you retry after a network error.

Rate limits

Scope Limit Window
Per site key 40 requests 15 minutes

Limits are reported with standard headers on every authenticated response:

RateLimit-Limit: 40
RateLimit-Remaining: 37
RateLimit-Reset: 812

Over the limit, requests return 429 with the body shown above. Back off until RateLimit-Reset (seconds) has elapsed. If you expect more than 40 submissions per 15 minutes on one site, queue on your side and drain at a steady rate.

Data retention

Data Retention
Submission fields, form, page, time, derived device and country For the life of the site
Raw visitor IP (context.ip) 30 days, then removed by a scheduled job; the derived country remains
Site key Stored as a SHA-256 hash only; revoked keys are kept as revoked for audit

Exports from the console include everything retained for the filtered records.