Store an ordinary contact request after Turnstile verification. Enterprise enquiries use the configured Topolo Forms collector.
Action app_topolo_one.marketing.contact.create · POST /api/contact. Intended audience: public.
Catalog flags: readOnly=False, requiresConfirmation=True, destructive=False, agentAccess=confirm. HTTP method and empty permission fields do not override the actual effects or authority below.
Authority and prerequisites
- Declared authorization mode=public, requiredPermission=empty; actual source identity/resource checks below remain mandatory.
- Discover the actual identifier and current intended state within existing authority. Examples grant no access and are not executable probes.
Identifiers
- Obtain a fresh Turnstile token through the intended human surface. Retain only the returned random contactId for receipt lookup; do not enumerate contacts.
Input
email: type="string"; pattern="^(?!\.)(?!.\.\.)([A-Za-z0-9_'+\-\.])[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\-]*\.)+[A-Za-z]{2,}$". Required.name: type="string"; minLength=2; maxLength=100. Required.company: type="string"; maxLength=100. Optional.subject: type="string"; minLength=1; maxLength=100. Required.message: type="string"; minLength=10; maxLength=1000. Required.topic: type="string"; maxLength=80. Optional.source: type="string"; maxLength=80. Optional.turnstileToken: type="string"; minLength=1. Required.
The exact native input/output schemas are retained in the hidden paired layer for this version. Top-level undeclared fields are rejected. Nested open records and semantic prerequisites still need source checks.
Effects and important boundaries
- Stores one contact request for up to one year after verifying Turnstile.
- Uses the existing optional contact email delivery. A stored receipt does not prove delivery. No subscription, grant or charge is created.
- Requires a valid fresh human Turnstile token verified through the intended flow, plus strict required contact fields. Placeholder tokens in examples are unusable. Do not automate challenge circumvention.
- Stores the contact and a salted IP hash in BOOKING_KV, with a random contactId and record expiry. Then attempts contact email delivery when configured. Sending this action can therefore message people.
- The receipt is prepared after storage and can still return success if the email attempt fails. A receipt proves accepted storage semantics, not email delivery.
- This ordinary contact route does not create a subscription or charge. Enterprise enquiries use the configured Forms collector from marketing.pricing.get; this is a different consent/data flow.
- Keep personal contact data minimal. On uncertain submission retain any contactId and check that receipt under separate authority before considering a duplicate submission.
Refusals, failures and recovery
- 400
VALIDATION_ERROR: Correct the required fields or obtain a fresh Turnstile token through the intended human verification flow. No contact is stored before successful verification. - 503
CONTACT_UNAVAILABLE: Contact storage is not configured. Preserve the sanitized failure and retry after service restoration. - 500
CONTACT_FAILED: Retain any returned contactId and inspect its receipt before retrying. A write failure can leave its outcome uncertain.
An enquiry is not a purchase. No public undo action exists; contact Topolo with the reference to withdraw it. Do not retry a successful submission.
Verification
- Read app_topolo_one.marketing.contact.get with the returned contactId to verify the stored receipt. The receipt does not prove email delivery.
- Retain actual request/receipt identifiers securely, preserve UNKNOWN effects and reconcile before any retry.
Run a reviewed request
Discover the current action and its resource requirements before running it. Save the approved input as reviewed-input.json; replace synthetic examples with values obtained through the intended authorized workflow. If discovery requires a resource binding, provide its published type and resolved ID separately on both plan and call. Stop if validation fails or the plan is not executable.
topolo actions get app_topolo_one.marketing.contact.create --json
topolo actions validate app_topolo_one.marketing.contact.create --data @reviewed-input.json --json
topolo actions plan app_topolo_one.marketing.contact.create --data @reviewed-input.json --confirm --json
topolo actions call app_topolo_one.marketing.contact.create --data @reviewed-input.json --confirm --json
--confirm must represent approval of the actual request and its effects. The examples do not supply that approval.
Worked examples
All examples are synthetic and unrun. They cannot authorize access, create human consent, prove media/provider success or establish financial/customer state. Placeholder tokens are unusable. No contact, payment, notification, provisioning or business read was executed.
Stored contact receipt illustration
SOURCE-AUTHORED SYNTHETIC, UNRUN. Output assessment: PASS_STRUCTURAL_ONLY_UNRUN.
Input:
{
"email": "owner@example.test",
"name": "Example Owner",
"subject": "Contact Topolo",
"message": "Please contact us about our team requirements.",
"turnstileToken": "replace-with-real-human-verification-token"
}
Output illustration or error excerpt:
{
"success": true,
"contactId": "00000000-0000-4000-8000-000000000001",
"message": "Feedback received."
}
200 hypothetical stored receipt; no real submission or email occurred.
Refusal or failure
SOURCE-AUTHORED SYNTHETIC, UNRUN. Source-derived error-code excerpt only; messages/envelope can differ by layer or locale. Not a captured response. Output assessment: ERROR_EXCERPT_NOT_SUCCESS_SCHEMA.
Input:
{
"email": "owner@example.test",
"name": "Example Owner",
"subject": "Contact Topolo",
"message": "Please contact us about our team requirements.",
"turnstileToken": "replace-with-real-human-verification-token"
}
Output illustration or error excerpt:
{
"error": "VALIDATION_ERROR"
}
Failed human verification stores no contact.
Invalid input: stop at schema validation
SOURCE-AUTHORED SYNTHETIC, UNRUN. null is a no-response sentinel, not returned JSON null. Output assessment: NOT_APPLICABLE_NO_REQUEST.
Input:
{
"name": "Example Owner",
"subject": "Contact Topolo",
"message": "Please contact us about our team requirements.",
"turnstileToken": "replace-with-real-human-verification-token"
}
Output illustration or error excerpt:
null
Intentionally invalid input; no request was issued and no HTTP response/status is asserted.
Boundary: stored receipt despite email failure
SOURCE-AUTHORED SYNTHETIC, UNRUN. Output assessment: PASS_STRUCTURAL_ONLY_UNRUN.
Input:
{
"email": "owner@example.test",
"name": "Example Owner",
"subject": "Contact Topolo",
"message": "Please contact us about our team requirements.",
"turnstileToken": "replace-with-real-human-verification-token"
}
Output illustration or error excerpt:
{
"success": true,
"contactId": "00000000-0000-4000-8000-000000000001",
"message": "Feedback received."
}
The handler can return the stored receipt even after email failure. Do not infer delivery or send a duplicate to test it.
Source and verification limits
Reviewed against cb18601dad6735f8140a4c81e9650d9fc3599f9a at apps/marketing/worker/engagement-routes.js and the published action schema on 2026-10-20. Examples are synthetic and unrun. Source review and schema validation do not prove current deployed behavior, provider completion or business delivery. Response excerpts are labelled where incomplete.
Change log
- 2026-10-20: Prepared the action guide with paired agent schemas, permission and effect boundaries, worked examples, verification and recovery instructions. Independently checked the pinned source; publication and runtime verification remain separate.