Send website inquiries to CRM
Request and response reference for submitting website forms.
Send website inquiries to CRM
This is the reference for the developer wiring a website form into a Workspace
CRM inbox. A submission creates an Inquiry that Owners and Managers review,
respond to, and manage in Backoffice.
Before using this, an Owner needs to create a key and set up inquiry types.
See Connect your website to CRM for that.
Base path:
https://backoffice.mindfulltechnologies.com
Submission modes
The endpoint accepts two credential modes. Use exactly one per request.
1. Browser form submissions
Send the public formKey in the JSON body. This is safe in website JavaScript
because the backend validates the form key, the Workspace CRM capability, and the
allowed origins configured for that key. Send the browser Origin header.
POST /api/public/v1/inquiries
Content-Type: application/json
Origin: https://hotel.example.com
X-External-Submission-Id: contact-form-2026-06-26-001
{
"formKey": "mf_form_public_abc123",
"typeSlug": "general",
"contact": {
"name": "Anu Mathew",
"email": "anu@example.com",
"phone": "+91 99999 99999"
},
"subject": "Question about rooms",
"message": "Do you have parking available?",
"additionalDetails": {
"page": "/contact",
"campaign": "monsoon-offer"
}
}
2. Server-to-server submissions
Send the secret API key as a bearer token and omit formKey from the body. Do
not expose this key in browser JavaScript.
POST /api/public/v1/inquiries
Content-Type: application/json
Authorization: Bearer mf_live_secret_value
X-External-Submission-Id: room-form-2026-08-12-anu
{
"typeSlug": "rooms",
"contact": {
"name": "Anu Mathew",
"email": "anu@example.com",
"phone": "+91 99999 99999"
},
"message": "We would like two rooms if available.",
"startsAt": "2026-08-12",
"endsAt": "2026-08-15",
"arrivalTime": "18:30",
"guestCount": 4,
"additionalDetails": {
"sourceSystem": "wordpress",
"roomType": "Deluxe"
}
}
Request fields
| Field | Required | Notes |
|---|---|---|
formKey | Browser form submissions only | Required when no bearer API key is sent. Omit for server-to-server submissions. |
typeId | Optional | Inquiry type id. Omit to use the Workspace default type. |
typeSlug | Optional | Inquiry type slug, such as rooms or events. Omit to use the default. |
contact.name | Optional | Customer or guest name. |
contact.email | Required unless phone is present | Must be a valid email if provided. Used for contact matching. |
contact.phone | Required unless email is present | Stored on the CRM contact. |
contact.company | Optional | Useful for business accounts. |
subject | Optional | Short summary shown in the inquiry list. |
message | Optional | Customer message. |
startsAt | Optional | ISO date such as 2026-08-12. |
endsAt | Optional | ISO date such as 2026-08-15. |
arrivalTime | Optional | HH:mm format, 24 hour. |
guestCount | Optional | Positive integer. |
additionalDetails | Optional | Object of custom form fields. Do not send secrets. |
Inquiry type slugs come from Settings then Inquiry types in Backoffice. A
submission that sends neither typeId nor typeSlug is filed under the
Workspace default type, General.
Retries and email notification matching
Send the X-External-Submission-Id header so a retry does not create a duplicate
inquiry for the same Workspace:
X-External-Submission-Id: canoeville-contact-a1b2c3d4e5f678901234567890abcdef
Use a unique, stable value per submission.
If your website also sends a notification email about the same submission to a
connected CRM email channel, put an X-External-Submission-Id header with the
identical value on that email. The email then attaches to the inquiry this API
created instead of arriving as a second, separate inquiry.
Responses
A new inquiry returns 201.
{
"inquiry": {
"id": "inquiry_123",
"workspaceId": "workspace_123",
"type": {
"id": "type_rooms",
"name": "Rooms",
"slug": "rooms",
"isDefault": false
},
"status": "NEW",
"source": "WEBSITE_FORM",
"sourceName": "Hotel website",
"subject": null,
"message": "We would like two rooms if available.",
"preferredStartAt": "2026-08-12T00:00:00.000Z",
"preferredEndAt": "2026-08-15T00:00:00.000Z",
"arrivalTime": "18:30",
"guestCount": 4,
"receivedAt": "2026-06-26T10:00:00.000Z",
"updatedAt": "2026-06-26T10:00:00.000Z",
"contact": {
"id": "contact_123",
"name": "Anu Mathew",
"email": "anu@example.com",
"phone": "+91 99999 99999"
},
"assignedMember": null
}
}
A retry with an already-used X-External-Submission-Id returns 200 with
idempotent: true. Treat it as success.
{
"inquiry": {
"id": "inquiry_123"
},
"idempotent": true
}
If the notification email reached CRM before this request did, the existing email
inquiry is filled in with the form's details rather than duplicated. That returns
200 with upgraded: true. Treat it as success too.
{
"inquiry": {
"id": "inquiry_123"
},
"upgraded": true
}
Errors
Errors return a JSON object with an error holding a code and a message. The
message is safe to log; do not show it to your website visitors, since it
describes the integration rather than what they did.
{
"error": {
"code": "VALIDATION_FAILED",
"message": "Contact email is invalid"
}
}
| Status | Meaning |
|---|---|
400 | A field is missing or malformed. |
401 | The form key or API key is missing, unknown, or disabled. |
403 | The Origin is not on the key's allowed list, or CRM is off for the Workspace. |
500 | Unexpected server error. Safe to retry with the same submission id. |
Versioning
This endpoint is versioned under /v1. New fields may appear in responses, so
ignore fields you do not recognise. Breaking changes will use a new version path.