---
title: "Send a message from the public marketing contact form"
method: POST
path: "/api/v1/contact_submissions"
tags: ["contact_submissions"]
---

# Send a message from the public marketing contact form

`POST /api/v1/contact_submissions`

## Request

- Base URL: `https://composal.com` (the document declares no server; this is the origin it was published from)
- URL: `https://composal.com/api/v1/contact_submissions`
- Auth: none required

Unauthenticated and CSRF-exempt: the marketing site posts this straight from a browser with no Vex session. Rate limited per IP (5 per minute). `website` is a honeypot — a field no human sees. When it is filled in the response is an ordinary 201 and nothing is stored, so a bot learns nothing from the reply.

## Request body

- ContactSubmissionRequest
  - `name` string, required
  - `email` string, required: Stored downcased and stripped.
  - `company` string, nullable
  - `message` string, required
  - `website` string, nullable: Honeypot. Render it hidden and leave it empty; any value discards the submission.

## Response `201`

The message was accepted (or silently discarded as spam).

- ContactSubmissionCreated
  - `id` string, required: Public id (`contact_submission_…`).
  - `created_at` string, required: ISO8601 timestamp.

## Other responses

- `400`: A required field was missing from the request body.
- `422`: A field failed validation.
- `429`: Too many submissions from this IP.

---

[API](https://skmtc.dev/composal/apis/vex-api.md) - [All operations](https://skmtc.dev/composal/apis/vex-api/llms.txt) - [OpenAPI document](https://skmtc.dev/composal/apis/vex-api/revisions/19698ba051dc?raw)
