API endpoints

Open a takedown case, get one case, and list your cases. Every field, status code and header.


All paths are relative to https://openbait.com/api/v1/ext. Every request needs Authorization: Bearer <key> (Authentication).

The Case object

Every endpoint returns cases in this shape.

json
{
  "id": "d3a9m7f05n8u7r1m4r20",
  "url": "https://example-copy.shop/checkout",
  "domain": "example-copy.shop",
  "status": "opened",
  "createdAt": "2026-10-22T12:00:00Z",
  "updatedAt": "2026-10-22T12:05:00Z",
  "offlineAt": null,
  "consoleUrl": "https://openbait.com/console/takedown/d3a9m7f05n8u7r1m4r20",
  "blocklistOnly": false
}
FieldTypeDescription
idstringThe case ID. Use it with GET /cases/{id}; webhooks call it caseId
urlstringThe URL the case was opened for
domainstringThe site's domain name, as plain text
statusstringWhere the case stands. One of the values in Case statuses
createdAtstring (RFC 3339)When the case was opened
updatedAtstring (RFC 3339)When the case last changed
offlineAtstring (RFC 3339) or nullWhen the site was last seen going offline. null while it is online, including after it comes back (re-emerged)
consoleUrlstringThe case page in the console, for people on your team
blocklistOnlybooleantrue when the case was opened after the month's takedowns were used up: the site was added to the browser warning lists only, and no takedown was used. A takedown can be added on the case page in the console. false for a case with a takedown

Case statuses

StatusWhat it means
openedThe case is open and the takedown is under way. The site is still online
blockedThe site has been added to the blocklists that Chrome, Safari and Firefox use, so visitors see a warning when they open it. The site is still online and the takedown continues
downThe site stopped loading. We keep checking it for a week in case it comes back
watchingThe site can't be reached, but its domain is still registered and could come back, so we keep checking it
resolvedThe site stayed offline for a week, the page was removed, or the case was closed. If a site that stayed offline for a week comes back, the case becomes re-emerged
domain-removedThe domain has been deleted, so this site can't come back. The case is closed
re-emergedThe site is loading again after being offline. The case page in the console shows whether you need to confirm it again

A case usually moves opened → blocked → down → resolved, but it can skip steps. Only domain-removed is final: a site resolved after a week offline that comes back online becomes re-emerged; a closed case stays resolved. New statuses may be added in /v1, so handle an unknown value as "still in progress".

Open a case

http
POST /cases

Opens a takedown case for a URL, the same as reporting a fake site in the console and confirming it. A new case uses one of the month's takedowns.

Request headers

HeaderRequiredDescription
AuthorizationYesBearer <key>
Content-TypeYesapplication/json
Idempotency-KeyNo1 to 255 characters. Makes retries safe; see Idempotency

Request body

FieldTypeRequiredDescriptionExample
urlstringYesThe page to take down. http or https, at most 2,048 bytes"https://example-copy.shop/checkout"
notestringNoA note for your team, kept with the case. At most 1,000 characters"Seen in a customer complaint, ticket 4521"

The URL must be a public website. These are refused with 400 invalid_request, and the message says which:

Reasonmessage
An IP address instead of a domain nameurl must use a domain name, not an IP address
An address on a private or internal networkurl points to a private or internal address
One of your own domainsurl is on one of your own domains
A well-known platform (a social network, a marketplace and the like)url is on a well-known platform and cannot be taken down as a fake site
A domain that doesn't existurl's domain does not exist
Nothing a takedown can be filed againsturl has nothing a takedown can be filed against
bash
curl -X POST https://openbait.com/api/v1/ext/cases \
  -H "Authorization: Bearer $OPENBAIT_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: ticket-4521" \
  -d '{"url": "https://example-copy.shop/checkout", "note": "Ticket 4521"}'

Responses

StatusBodyWhen
201 CreatedCaseA new case was opened. One takedown used
200 OKCaseYour organization already has an open case for this site. You get that case; no takedown is used
400 Bad RequestError invalid_requestA field is missing or not valid; the message names it
402 Payment RequiredError quota_exhaustedThis month's takedowns are used up. To take the site down now, report the URL in the console, then add a $199 takedown on its case page. Or wait for next month
409 ConflictError idempotency_conflictA request with this Idempotency-Key is still being processed, or the key was already used with a different body. The message says which; see Idempotency

A 201 or 200 case with blocklistOnly: true was added to the browser warning lists only and used none of the month's takedowns (for example, an open case the console opened after the takedowns ran out).

Any endpoint can also answer 401, 403, 413, 429 or 500, and 404 not_found for an unknown path or 405 invalid_request for a method a path doesn't take. A request that takes longer than 30 seconds can get 504 Gateway Timeout without a JSON body, so check the status code and Content-Type before you parse the body. See Errors.

Idempotency

Send an Idempotency-Key so that a retry after a timeout can't open a second case.

  • The key is remembered for 24 hours, per organization.
  • Same key and same body: you get the first response again, with the same status code and an Idempotent-Replayed: true header. Nothing new happens.
  • While the first request with a key is still being processed, another request with the same key gets 409 idempotency_conflict (message: a request with this Idempotency-Key is still being processed). Wait a few seconds and retry with the same key.
  • Same key and a different body: 409 idempotency_conflict (message: this Idempotency-Key was used with a different request body). Use a new key only for a new request.
  • A 5xx response is not kept: a retry with the same key is processed again.
  • Use something unique to the request, such as your ticket ID or a UUID.

Even without the header, sending the same URL twice doesn't use two takedowns: the second call returns 200 with the open case.

Get a case

http
GET /cases/{id}
Path parameterTypeDescription
idstringThe case ID
bash
curl https://openbait.com/api/v1/ext/cases/d3a9m7f05n8u7r1m4r20 \
  -H "Authorization: Bearer $OPENBAIT_API_KEY"
StatusBodyWhen
200 OKCase
404 Not FoundError not_foundNo case with this ID in your organization

List cases

http
GET /cases?status=&limit=&cursor=

Newest first.

Query parameterTypeRequiredDescription
statusstringNoOnly cases with this status, for example down. One of the Case statuses (awaiting_confirmation is a webhook-only value and is refused here)
limitintegerNo1 to 100. Default 20
cursorstringNoThe nextCursor from the previous page. Leave it out for the first page
bash
curl "https://openbait.com/api/v1/ext/cases?status=down&limit=50" \
  -H "Authorization: Bearer $OPENBAIT_API_KEY"
json
{
  "data": [
    {
      "id": "d3a9m7f05n8u7r1m4r20",
      "url": "https://example-copy.shop/checkout",
      "domain": "example-copy.shop",
      "status": "down",
      "createdAt": "2026-10-22T12:00:00Z",
      "updatedAt": "2026-10-23T08:40:00Z",
      "offlineAt": "2026-10-23T08:40:00Z",
      "consoleUrl": "https://openbait.com/console/takedown/d3a9m7f05n8u7r1m4r20",
      "blocklistOnly": false
    }
  ],
  "nextCursor": "eyJ0IjoiMjAyNi0xMC0yMlQxMjowMDowMFoifQ"
}
FieldTypeDescription
dataarray of CaseThis page of cases
nextCursorstring or nullPass it as cursor to get the next page. null on the last page

The cursor is opaque: don't build or change one yourself. To poll for changes, a webhook is better than listing over and over.