IDAP
12 endpoints from the published OpenAPI import.
IDAP health check
Liveness probe for the IDAP router. Unauthenticated. Returns the list of supported resource_types (businesses, people, leads, ...) backed by norm_cli_* per-client tables.
Try it
Examples
cURL
curl -X GET 'https://spideriq.ai/api/v1/idap/health' \
-H 'Authorization: Bearer <token>'Python
import httpx
resp = httpx.get(
"https://spideriq.ai/api/v1/idap/health",
headers={"Authorization": "Bearer <token>"},
)
resp.raise_for_status()
print(resp.json())JavaScript
const resp = await fetch("https://spideriq.ai/api/v1/idap/health", {
method: "GET",
headers: { "Authorization": "Bearer <token>" }
});
const data = await resp.json();
console.log(data);Go
package main
import (
"net/http"
)
func main() {
req, _ := http.NewRequest("GET", "https://spideriq.ai/api/v1/idap/health", nil)
req.Header.Set("Authorization", "Bearer <token>")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
}Responses
| Status | Description |
|---|---|
200 | Successful Response |
Batch-fetch resources by IDAP ref
Resolve many IdapRef entries (type + id) in a single call. Missing or unauthorized refs are returned in the errors map; successful lookups populate results. Scoped to the authenticated client's norm_cli_* tables.
Try it
Examples
cURL
curl -X POST 'https://spideriq.ai/api/v1/idap/batch' \
-H 'Authorization: Bearer <token>' \
-H 'Content-Type: application/json' \
-d '{
"refs": [
"string"
],
"fields": "string",
"include": "string"
}'Python
import httpx
resp = httpx.post(
"https://spideriq.ai/api/v1/idap/batch",
headers={"Authorization": "Bearer <token>", "Content-Type": "application/json"},
json={"refs": ["string"], "fields": "string", "include": "string"},
)
resp.raise_for_status()
print(resp.json())JavaScript
const resp = await fetch("https://spideriq.ai/api/v1/idap/batch", {
method: "POST",
headers: { "Authorization": "Bearer <token>", "Content-Type": "application/json" },
body: JSON.stringify({"refs": ["string"], "fields": "string", "include": "string"})
});
const data = await resp.json();
console.log(data);Go
package main
import (
"net/http"
"strings"
)
func main() {
body := strings.NewReader(`{"refs": ["string"], "fields": "string", "include": "string"}`)
req, _ := http.NewRequest("POST", "https://spideriq.ai/api/v1/idap/batch", body)
req.Header.Set("Authorization", "Bearer <token>")
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
}Responses
| Status | Description |
|---|---|
200 | Request succeeded |
401 | Authentication failed |
404 | Resource not found in the authenticated client's tenant-scoped tables |
422 | Validation error (invalid resource_type, cursor, filter, or flag payload) |
429 | Rate limit exceeded |
Proxy media binary from SeaweedFS
Stream a media file (image/video/document) from SeaweedFS through the API, enforcing tenant scoping. Supports conditional requests (If-None-Match, If-Modified-Since → 304), ?thumb=1 for a 400px thumbnail, and ?download=1 to force Content-Disposition: attachment.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
media_id | path | string | true | |
thumb | query | boolean | false | Return 400px thumbnail |
download | query | boolean | false | Set Content-Disposition: attachment |
Try it
Examples
cURL
curl -X GET 'https://spideriq.ai/api/v1/idap/media/{media_id}' \
-H 'Authorization: Bearer <token>'Python
import httpx
resp = httpx.get(
"https://spideriq.ai/api/v1/idap/media/{media_id}",
headers={"Authorization": "Bearer <token>"},
)
resp.raise_for_status()
print(resp.json())JavaScript
const resp = await fetch("https://spideriq.ai/api/v1/idap/media/{media_id}", {
method: "GET",
headers: { "Authorization": "Bearer <token>" }
});
const data = await resp.json();
console.log(data);Go
package main
import (
"net/http"
)
func main() {
req, _ := http.NewRequest("GET", "https://spideriq.ai/api/v1/idap/media/{media_id}", nil)
req.Header.Set("Authorization", "Bearer <token>")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
}Responses
| Status | Description |
|---|---|
200 | Request succeeded |
401 | Authentication failed |
404 | Resource not found in the authenticated client's tenant-scoped tables |
422 | Validation error (invalid resource_type, cursor, filter, or flag payload) |
429 | Rate limit exceeded |
304 | Not modified (conditional-request hit) |
Full-text search within a resource type
Full-text search across the authenticated client's norm_cli_* table for the given resource_type. Use q for the query, fields for column projection, flags to filter by flag keys, and ?format=json|yaml|md|llm for AI-agent-friendly output.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
resource_type | path | string | true | |
q | query | string | true | Search query |
limit | query | integer | false | |
fields | query | any | false | |
format | query | any | false | Response format. json (default) and llm return JSON; yaml returns text/yaml; md returns text/markdown. Any other value is a 422. |
flags | query | any | false |
Try it
Examples
cURL
curl -X GET 'https://spideriq.ai/api/v1/idap/{resource_type}/search' \
-H 'Authorization: Bearer <token>'Python
import httpx
resp = httpx.get(
"https://spideriq.ai/api/v1/idap/{resource_type}/search",
headers={"Authorization": "Bearer <token>"},
)
resp.raise_for_status()
print(resp.json())JavaScript
const resp = await fetch("https://spideriq.ai/api/v1/idap/{resource_type}/search", {
method: "GET",
headers: { "Authorization": "Bearer <token>" }
});
const data = await resp.json();
console.log(data);Go
package main
import (
"net/http"
)
func main() {
req, _ := http.NewRequest("GET", "https://spideriq.ai/api/v1/idap/{resource_type}/search", nil)
req.Header.Set("Authorization", "Bearer <token>")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
}Responses
| Status | Description |
|---|---|
200 | Request succeeded |
401 | Authentication failed |
404 | Resource not found in the authenticated client's tenant-scoped tables |
422 | Validation error (invalid resource_type, cursor, filter, or flag payload) |
429 | Rate limit exceeded |
Aggregate stats for a resource type
Dashboard-oriented aggregates for the authenticated client's norm_cli_{resource_type} table: total count, per-flag-key counts, recency buckets. Cheap — pre-aggregated on read. Supports ?format=json|yaml|md|llm for AI-agent-friendly output.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
resource_type | path | string | true | |
format | query | any | false | Response format. json (default) and llm return JSON; yaml returns text/yaml; md returns text/markdown. Any other value is a 422. |
Try it
Examples
cURL
curl -X GET 'https://spideriq.ai/api/v1/idap/{resource_type}/stats' \
-H 'Authorization: Bearer <token>'Python
import httpx
resp = httpx.get(
"https://spideriq.ai/api/v1/idap/{resource_type}/stats",
headers={"Authorization": "Bearer <token>"},
)
resp.raise_for_status()
print(resp.json())JavaScript
const resp = await fetch("https://spideriq.ai/api/v1/idap/{resource_type}/stats", {
method: "GET",
headers: { "Authorization": "Bearer <token>" }
});
const data = await resp.json();
console.log(data);Go
package main
import (
"net/http"
)
func main() {
req, _ := http.NewRequest("GET", "https://spideriq.ai/api/v1/idap/{resource_type}/stats", nil)
req.Header.Set("Authorization", "Bearer <token>")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
}Responses
| Status | Description |
|---|---|
200 | Request succeeded |
401 | Authentication failed |
404 | Resource not found in the authenticated client's tenant-scoped tables |
422 | Validation error (invalid resource_type, cursor, filter, or flag payload) |
429 | Rate limit exceeded |
Resolve a resource by external identifier
Look up a single resource by an external id (Google place_id, email domain, etc.) within the authenticated client's tenant scope. Returns the canonical IDAP record without requiring the internal UUID. Exactly one external identifier query param must be supplied.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
resource_type | path | string | true | |
place_id | query | any | false | Google Place ID (e.g. 0x47e66fdad6f1cc73:0x341211b3fccd79e1) |
domain | query | any | false | Domain name (e.g. mariospizzeria.com) |
email | query | any | false | Email address (e.g. info@example.com) |
url | query | any | false | LinkedIn URL or other URL identifier (linkedin_profiles only) |
linkedin | query | any | false | LinkedIn profile URL on a contact (e.g. https://linkedin.com/in/jane) |
twitter | query | any | false | Twitter profile URL on a contact |
vat | query | any | false | VAT number (e.g. DE123456789, GB123456789) |
registration_number | query | any | false | National registration number (e.g. UK Companies House 00445790) |
lei | query | any | false | Legal Entity Identifier (20-char ISO 17442 code) |
tax_id | query | any | false | National tax id (e.g. US EIN, DE Steuernummer) |
source_id | query | any | false | Registry-provided source id (admin/dev path — composite UNIQUE with source, seq-scans) |
pin_name | query | any | false | VayaPin PIN name (e.g. 'BB:TAPAS') — pins only |
pin_data_set_id | query | any | false | VayaPin data set UUID — pins only (natural key) |
account_id | query | any | false | VayaPin account UUID — pins only |
pin_subscription_id | query | any | false | VayaPin subscription UUID — pins only |
include | query | any | false | Comma-separated related types to include (e.g. 'emails,phones') |
fields | query | any | false | Comma-separated field projection |
format | query | any | false | Response format. json (default) and llm return JSON; yaml returns text/yaml; md returns text/markdown. Any other value is a 422. |
Try it
Examples
cURL
curl -X GET 'https://spideriq.ai/api/v1/idap/{resource_type}/resolve' \
-H 'Authorization: Bearer <token>'Python
import httpx
resp = httpx.get(
"https://spideriq.ai/api/v1/idap/{resource_type}/resolve",
headers={"Authorization": "Bearer <token>"},
)
resp.raise_for_status()
print(resp.json())JavaScript
const resp = await fetch("https://spideriq.ai/api/v1/idap/{resource_type}/resolve", {
method: "GET",
headers: { "Authorization": "Bearer <token>" }
});
const data = await resp.json();
console.log(data);Go
package main
import (
"net/http"
)
func main() {
req, _ := http.NewRequest("GET", "https://spideriq.ai/api/v1/idap/{resource_type}/resolve", nil)
req.Header.Set("Authorization", "Bearer <token>")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
}Responses
| Status | Description |
|---|---|
200 | Request succeeded |
401 | Authentication failed |
404 | Resource not found in the authenticated client's tenant-scoped tables |
422 | Validation error (invalid resource_type, cursor, filter, or flag payload) |
429 | Rate limit exceeded |
Find duplicate resources sharing a common external key
Return clusters of resources in the authenticated client's tenant that share the same value for a whitelisted external key (e.g. two or more businesses rows with the same google_place_id). Each cluster has count >= 2 — single-occurrence values are filtered out by HAVING COUNT(*) > 1. Used in dedupe workflows: surface the candidates here, then call DELETE /idap/<resource_type>/{id} (Wave D.2) to remove the duplicate. Whitelisted key values for businesses (Wave D.1): google_place_id, domain, phone_e164 (direct columns), vat, registration_number, lei, tax_id (joined via company_registry.business_id).
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
resource_type | path | string | true | |
key | query | string | true | Whitelisted clustering key. Allowed values depend on resource_type — see endpoint description. Free strings outside the whitelist return 400. |
limit | query | integer | false | Max clusters to return (1..500). Default 100. |
Try it
Examples
cURL
curl -X GET 'https://spideriq.ai/api/v1/idap/{resource_type}/duplicates' \
-H 'Authorization: Bearer <token>'Python
import httpx
resp = httpx.get(
"https://spideriq.ai/api/v1/idap/{resource_type}/duplicates",
headers={"Authorization": "Bearer <token>"},
)
resp.raise_for_status()
print(resp.json())JavaScript
const resp = await fetch("https://spideriq.ai/api/v1/idap/{resource_type}/duplicates", {
method: "GET",
headers: { "Authorization": "Bearer <token>" }
});
const data = await resp.json();
console.log(data);Go
package main
import (
"net/http"
)
func main() {
req, _ := http.NewRequest("GET", "https://spideriq.ai/api/v1/idap/{resource_type}/duplicates", nil)
req.Header.Set("Authorization", "Bearer <token>")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
}Responses
| Status | Description |
|---|---|
200 | Request succeeded |
401 | Authentication failed |
404 | Resource not found in the authenticated client's tenant-scoped tables |
422 | Validation error (invalid resource_type, cursor, filter, or flag payload) |
429 | Rate limit exceeded |
Bulk add/remove flags on many resources
Apply flag writes (add/remove) to many resources of the same type in one call. Per-row failures are returned in errors; successful writes go in results. Scoped to the authenticated client's tenant tables.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
resource_type | path | string | true |
Try it
Examples
cURL
curl -X POST 'https://spideriq.ai/api/v1/idap/{resource_type}/flags/bulk' \
-H 'Authorization: Bearer <token>' \
-H 'Content-Type: application/json' \
-d '{
"updates": [
{
"resource_id": "string",
"add": [
"string"
],
"remove": [
"string"
]
}
],
"flagged_by": "string",
"reason": "string"
}'Python
import httpx
resp = httpx.post(
"https://spideriq.ai/api/v1/idap/{resource_type}/flags/bulk",
headers={"Authorization": "Bearer <token>", "Content-Type": "application/json"},
json={"updates": [{"resource_id": "string", "add": ["string"], "remove": ["string"]}], "flagged_by": "string", "reason": "string"},
)
resp.raise_for_status()
print(resp.json())JavaScript
const resp = await fetch("https://spideriq.ai/api/v1/idap/{resource_type}/flags/bulk", {
method: "POST",
headers: { "Authorization": "Bearer <token>", "Content-Type": "application/json" },
body: JSON.stringify({"updates": [{"resource_id": "string", "add": ["string"], "remove": ["string"]}], "flagged_by": "string", "reason": "string"})
});
const data = await resp.json();
console.log(data);Go
package main
import (
"net/http"
"strings"
)
func main() {
body := strings.NewReader(`{"updates": [{"resource_id": "string", "add": ["string"], "remove": ["string"]}], "flagged_by": "string", "reason": "string"}`)
req, _ := http.NewRequest("POST", "https://spideriq.ai/api/v1/idap/{resource_type}/flags/bulk", body)
req.Header.Set("Authorization", "Bearer <token>")
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
}Responses
| Status | Description |
|---|---|
200 | Request succeeded |
401 | Authentication failed |
404 | Resource not found in the authenticated client's tenant-scoped tables |
422 | Validation error (invalid resource_type, cursor, filter, or flag payload) |
429 | Rate limit exceeded |
Add or remove flags on a single resource
Write one or more flag changes (add/remove) against a single resource in the authenticated client's tenant scope. The response returns the resulting full flag state. Use /flags/bulk when batching across many resources of the same type.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
resource_type | path | string | true | |
resource_id | path | string | true |
Try it
Examples
cURL
curl -X POST 'https://spideriq.ai/api/v1/idap/{resource_type}/{resource_id}/flags' \
-H 'Authorization: Bearer <token>' \
-H 'Content-Type: application/json' \
-d '{
"add": [
"string"
],
"remove": [
"string"
],
"flagged_by": "string",
"reason": "string"
}'Python
import httpx
resp = httpx.post(
"https://spideriq.ai/api/v1/idap/{resource_type}/{resource_id}/flags",
headers={"Authorization": "Bearer <token>", "Content-Type": "application/json"},
json={"add": ["string"], "remove": ["string"], "flagged_by": "string", "reason": "string"},
)
resp.raise_for_status()
print(resp.json())JavaScript
const resp = await fetch("https://spideriq.ai/api/v1/idap/{resource_type}/{resource_id}/flags", {
method: "POST",
headers: { "Authorization": "Bearer <token>", "Content-Type": "application/json" },
body: JSON.stringify({"add": ["string"], "remove": ["string"], "flagged_by": "string", "reason": "string"})
});
const data = await resp.json();
console.log(data);Go
package main
import (
"net/http"
"strings"
)
func main() {
body := strings.NewReader(`{"add": ["string"], "remove": ["string"], "flagged_by": "string", "reason": "string"}`)
req, _ := http.NewRequest("POST", "https://spideriq.ai/api/v1/idap/{resource_type}/{resource_id}/flags", body)
req.Header.Set("Authorization", "Bearer <token>")
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
}Responses
| Status | Description |
|---|---|
200 | Request succeeded |
401 | Authentication failed |
404 | Resource not found in the authenticated client's tenant-scoped tables |
422 | Validation error (invalid resource_type, cursor, filter, or flag payload) |
429 | Rate limit exceeded |
Fetch a single resource by ID
Return the canonical IDAP record for a single resource in the authenticated client's tenant. Supports fields projection, include (comma-separated related-resource expansions), and ?format=json|yaml|md|llm for AI-agent-friendly output. An invalid UUID is treated as a 404 rather than a 500.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
resource_type | path | string | true | |
resource_id | path | string | true | |
fields | query | any | false | Comma-separated field projection |
include | query | any | false | Comma-separated related types to include (e.g. 'emails,phones') |
format | query | any | false | Response format. json (default) and llm return JSON; yaml returns text/yaml; md returns text/markdown. Any other value is a 422. |
Try it
Examples
cURL
curl -X GET 'https://spideriq.ai/api/v1/idap/{resource_type}/{resource_id}' \
-H 'Authorization: Bearer <token>'Python
import httpx
resp = httpx.get(
"https://spideriq.ai/api/v1/idap/{resource_type}/{resource_id}",
headers={"Authorization": "Bearer <token>"},
)
resp.raise_for_status()
print(resp.json())JavaScript
const resp = await fetch("https://spideriq.ai/api/v1/idap/{resource_type}/{resource_id}", {
method: "GET",
headers: { "Authorization": "Bearer <token>" }
});
const data = await resp.json();
console.log(data);Go
package main
import (
"net/http"
)
func main() {
req, _ := http.NewRequest("GET", "https://spideriq.ai/api/v1/idap/{resource_type}/{resource_id}", nil)
req.Header.Set("Authorization", "Bearer <token>")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
}Responses
| Status | Description |
|---|---|
200 | Request succeeded |
401 | Authentication failed |
404 | Resource not found in the authenticated client's tenant-scoped tables |
422 | Validation error (invalid resource_type, cursor, filter, or flag payload) |
429 | Rate limit exceeded |
List resources of a given type (paged, sync-friendly)
List resources within the authenticated client's tenant, with since/until timestamp filters for incremental sync, cursor-based pagination, fields projection, include expansion, flags filtering, and ?format=json|yaml|md|llm output. Designed so external systems (OPVS board-sync, CRMs) can incrementally pull new/changed records.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
resource_type | path | string | true | |
since | query | any | false | Return resources modified after this timestamp |
until | query | any | false | Return resources modified before this timestamp |
limit | query | integer | false | |
cursor | query | any | false | |
fields | query | any | false | |
include | query | any | false | Comma-separated related types to include (e.g. 'emails,phones') |
format | query | any | false | Response format. json (default) and llm return JSON; yaml returns text/yaml; md returns text/markdown. Any other value is a 422. |
campaign_id | query | any | false | |
source | query | any | false | |
flags | query | any | false | |
sort | query | string | false | |
order | query | string | false |
Try it
Examples
cURL
curl -X GET 'https://spideriq.ai/api/v1/idap/{resource_type}' \
-H 'Authorization: Bearer <token>'Python
import httpx
resp = httpx.get(
"https://spideriq.ai/api/v1/idap/{resource_type}",
headers={"Authorization": "Bearer <token>"},
)
resp.raise_for_status()
print(resp.json())JavaScript
const resp = await fetch("https://spideriq.ai/api/v1/idap/{resource_type}", {
method: "GET",
headers: { "Authorization": "Bearer <token>" }
});
const data = await resp.json();
console.log(data);Go
package main
import (
"net/http"
)
func main() {
req, _ := http.NewRequest("GET", "https://spideriq.ai/api/v1/idap/{resource_type}", nil)
req.Header.Set("Authorization", "Bearer <token>")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
}Responses
| Status | Description |
|---|---|
200 | Request succeeded |
401 | Authentication failed |
404 | Resource not found in the authenticated client's tenant-scoped tables |
422 | Validation error (invalid resource_type, cursor, filter, or flag payload) |
429 | Rate limit exceeded |
Delete a business record + cascade across per-tenant tables
🔴 Destructive. Hard-deletes the business row in norm_cli_<client>.businesses AND cascades to linked tables (pins, business_contacts, business_registry, company_registry, contacts, phones, domains, linkedin_profiles). Transactional — all or nothing. Audit row written to public.idap_deletions_audit in the same transaction.
Does NOT touch cs.vayapin.com. VayaPin pin pages are permanent per VayaPin §10. Response includes vayapin_pins_remain_external + the orphaned pin_data_set_ids so the caller knows what external state remains.
Does NOT cascade emails. That table is a tenant-wide canonical store keyed on email UNIQUE — multiple businesses share verification rows. The business_contacts join row is what gets removed; the email's verification metadata stays.
booking_flows + services auto-cascade via Postgres ON DELETE CASCADE FK; counts surface in auto_cascaded.
bookings is a blocker. If any bookings row references this business or its contacts, the call returns 409 with the blocking booking IDs — caller resolves those first.
Tenant-owner auth only: caller's client_id IS the tenant scope. Idempotent: second call on the same UUID returns 404.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
business_id | path | string | true | UUID of the business to delete. Resolve alternate keys via GET /idap/businesses/resolve first. |
Try it
Examples
cURL
curl -X DELETE 'https://spideriq.ai/api/v1/idap/businesses/{business_id}' \
-H 'Authorization: Bearer <token>' \
-H 'Content-Type: application/json' \
-d '{
"reason": "string"
}'Python
import httpx
resp = httpx.delete(
"https://spideriq.ai/api/v1/idap/businesses/{business_id}",
headers={"Authorization": "Bearer <token>", "Content-Type": "application/json"},
json={"reason": "string"},
)
resp.raise_for_status()
print(resp.json())JavaScript
const resp = await fetch("https://spideriq.ai/api/v1/idap/businesses/{business_id}", {
method: "DELETE",
headers: { "Authorization": "Bearer <token>", "Content-Type": "application/json" },
body: JSON.stringify({"reason": "string"})
});
const data = await resp.json();
console.log(data);Go
package main
import (
"net/http"
"strings"
)
func main() {
body := strings.NewReader(`{"reason": "string"}`)
req, _ := http.NewRequest("DELETE", "https://spideriq.ai/api/v1/idap/businesses/{business_id}", body)
req.Header.Set("Authorization", "Bearer <token>")
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
}Responses
| Status | Description |
|---|---|
200 | Business + child rows deleted; audit row written. Response body reports per-table cascade counts + the VayaPin pin IDs that remain external (cs.vayapin.com pages are permanent per VayaPin §10 — we delete OUR record only). |
401 | Authentication failed |
404 | Business UUID not found in the caller's tenant schema. Also returned on idempotent re-DELETE of an already-deleted ID. |
422 | Validation error (invalid resource_type, cursor, filter, or flag payload) |
429 | Rate limit exceeded |
409 | One or more bookings rows reference this business or its contacts via ON DELETE NO ACTION FK. Body lists the blocking booking IDs (up to 50). Caller must re-point or delete the bookings before re-trying. |