Grawt API Documentation
Overview
The Grawt API allows you to programmatically manage pages, discover domains, and manage leads, tags, and custom fields in your Grawt account. This RESTful API uses JSON for request and response bodies.
Base URL: https://grawt.app/api/v1
Authentication
All API requests require authentication using an API key. Include your API key in the request header.
| Header | Value |
|---|---|
X-API-Key |
Your API key |
Example:
curl -H "X-API-Key: your-api-key" https://grawt.app/api/v1/leads/fields
Error Responses
| Status Code | Description |
|---|---|
| 400 | Missing API key |
| 401 | Invalid API key |
Leads
Add Lead
Creates a new lead in your account.
Endpoint: POST /api/v1/leads
Request Body:
| Field | Type | Required | Description |
|---|---|---|---|
email |
string | Yes | Lead's email address |
fields |
object | Yes | Lead data fields (use Get Lead Fields to see available fields) |
Example Request:
{
"email": "john@example.com",
"fields": {
"first_name": "John",
"last_name": "Doe",
"phone": "+1234567890"
}
}
Success Response (201):
{
"success": true,
"message": "Lead added successfully."
}
Update Lead
Updates an existing lead by email address.
Endpoint: PUT /api/v1/leads/{email}
URL Parameters:
| Parameter | Type | Description |
|---|---|---|
email |
string | Lead's email address |
Request Body:
| Field | Type | Required | Description |
|---|---|---|---|
fields |
object | Yes | Lead data fields to update |
Example Request:
{
"fields": {
"first_name": "Jonathan",
"phone": "+1987654321"
}
}
Success Response (200):
{
"success": true,
"message": "Lead successfully updated."
}
Error Response (404):
{
"success": false,
"message": "Lead not found."
}
Sync Lead
Creates a new lead or updates an existing one based on the email address. This is useful for upsert operations where you want to ensure the lead exists with the latest data.
Endpoint: POST /api/v1/leads/sync
Request Body:
| Field | Type | Required | Description |
|---|---|---|---|
email |
string | Yes | Lead's email address |
fields |
object | Yes | Lead data fields |
add_tags |
array | No | Array of tag IDs to apply to the lead |
remove_tags |
array | No | Array of tag IDs to remove from the lead |
Example Request:
{
"email": "john@example.com",
"fields": {
"first_name": "John",
"last_name": "Doe",
"phone": "+1234567890"
},
"add_tags": [1, 5, 12],
"remove_tags": [3]
}
Success Response (200):
{
"success": true,
"message": "Lead successfully created."
}
or
{
"success": true,
"message": "Lead successfully updated."
}
Delete Lead
Permanently deletes a lead by email address.
Endpoint: DELETE /api/v1/leads/{email}
URL Parameters:
| Parameter | Type | Description |
|---|---|---|
email |
string | Lead's email address |
Success Response (200):
{
"success": true,
"message": "Lead deleted successfully."
}
Error Response (404):
{
"success": false,
"message": "Lead not found."
}
Error Response (422):
{
"success": false,
"message": "The email ID is required and must be a valid email address."
}
Apply Tags to Lead
Applies one or more tags to an existing lead.
Endpoint: POST /api/v1/leads/{email}/tags
URL Parameters:
| Parameter | Type | Description |
|---|---|---|
email |
string | Lead's email address |
Request Body:
| Field | Type | Required | Description |
|---|---|---|---|
tags |
array | Yes | Array of tag IDs to apply |
Example Request:
{
"tags": [1, 5, 12]
}
Success Response (200):
{
"success": true,
"message": "Tags applied successfully."
}
Error Response (404):
{
"success": false,
"message": "Lead not found."
}
Remove Tags from Lead
Removes one or more tags from an existing lead.
Endpoint: DELETE /api/v1/leads/{email}/tags
URL Parameters:
| Parameter | Type | Description |
|---|---|---|
email |
string | Lead's email address |
Request Body:
| Field | Type | Required | Description |
|---|---|---|---|
tags |
array | Yes | Array of tag IDs to remove |
Example Request:
{
"tags": [3, 7]
}
Success Response (200):
{
"success": true,
"message": "Tags removed successfully."
}
Error Response (404):
{
"success": false,
"message": "Lead not found."
}
Get Lead Fields
Retrieves all available custom fields for leads in your account.
Endpoint: GET /api/v1/leads/fields
Success Response (200):
{
"success": true,
"user_lead_fields": [
{
"key": "first_name",
"label": "First Name",
"type": "text"
},
{
"key": "last_name",
"label": "Last Name",
"type": "text"
},
{
"key": "phone",
"label": "Phone",
"type": "text"
}
]
}
Tags
Get Tags
Retrieves all tags in your account.
Endpoint: GET /api/v1/tags
Success Response (200):
{
"success": true,
"tags": [
{
"id": 1,
"name": "Customer"
},
{
"id": 5,
"name": "Newsletter"
},
{
"id": 12,
"name": "VIP"
}
]
}
Domains
Domains are read-only in this API. Both endpoints return the built-in Grawt domain (id: -1) and/or verified custom domains belonging to the authenticated account. Alias domains are excluded.
| Method | Endpoint | Response (200) |
|---|---|---|
| GET | /api/v1/domains |
{ "domains": [...] } |
| GET | /api/v1/domains/{domain_id} |
{ "domain": {...} } |
Each domain contains only id, domain (hostname), account_id, is_primary, is_dns_configured, created_at, and updated_at. The built-in domain has is_dns_configured: 1 and null timestamps because it has no separate domain record. Use its id as domain_id when creating a page. A missing or unavailable domain returns 404.
Pages
The Page API manages settings and publishing. It supports custom head and body code, but does not accept or return builder design content, generated page HTML, blocks, or version IDs. Every operation is scoped to the API key's account; do not send account_id.
| Method | Endpoint | Purpose |
|---|---|---|
| GET | /api/v1/pages |
List account pages with pagination (200) |
| POST | /api/v1/pages |
Create an empty page (201) |
| GET | /api/v1/pages/{page_id} |
Read settings and publish status (200) |
| PATCH | /api/v1/pages/{page_id} |
Update supplied settings (200) |
| POST | /api/v1/pages/{page_id}/publish |
Publish the current working design (200) |
List Pages
GET /api/v1/pages?domain_id=-1&page=1 returns pages belonging to the API key's account, on the required domain, across all publish statuses, ordered by descending page ID (newest first).
| Query parameter | Default | Allowed values |
|---|---|---|
domain_id |
Required | An available domain ID from GET domains; -1 selects the built-in Grawt domain |
page |
1 | Integer from 1 to 2147483647 |
Each page contains up to 20 items; the page size is fixed. In the response, data contains page objects with the same settings, URL, and status as Get Page; current_page, total, and last_page describe pagination. next_page_url, prev_page_url, and pagination links preserve domain_id as you navigate the results. Design content is excluded. An empty domain or a page beyond the final page returns an empty data array with status 200. Missing or malformed domain_id and invalid pagination values return 422. A domain that is unavailable or belongs to another account returns 404.
curl 'https://grawt.app/api/v1/pages?domain_id=-1&page=1' \
-H 'X-API-Key: your-api-key'
Shared Create and Update Fields
POST and PATCH accept the same settings keys. Creation requires name and domain_id; PATCH leaves omitted fields unchanged. An explicitly supplied null clears a nullable field.
| Field | Type | Description |
|---|---|---|
name |
string | Required on creation; 1–254 characters |
domain_id |
integer | Required on creation; use an ID from GET domains, including -1 for the built-in domain. On PATCH it may be omitted or match the current domain; moving pages between domains is not supported. |
slug |
string or null | Up to 255 characters; letters, numbers, hyphens, and single slashes. Leading/trailing slashes are removed. Null, empty, or omitted on creation means the domain homepage. Must be unique within the account/domain and not a reserved path. |
title |
string or null | SEO title; up to 255 characters |
meta_description |
string or null | SEO description; up to 255 characters |
og_title |
string or null | Social title; up to 255 characters |
og_description |
string or null | Social description; up to 255 characters |
og_image |
string or null | HTTP(S) image URL; up to 255 characters |
custom_code_head |
string or null | Custom head HTML/scripts; up to 131,070 characters per field. Null clears the saved code. |
custom_code_body |
string or null | Custom body HTML/scripts; up to 131,070 characters per field. Null clears the saved code. |
is_index_enabled |
boolean | Allow search-engine indexing |
is_redirection_enabled |
boolean | Enable redirection |
redirection_url |
string or null | HTTP(S) destination; required whenever the resulting settings enable redirection |
Unknown fields are rejected with 422. The request cannot set publication status; use the publish endpoint.
Create an Empty Page
curl -X POST 'https://grawt.app/api/v1/pages' \
-H 'X-API-Key: your-api-key' \
-H 'Content-Type: application/json' \
-d '{"name":"My page","domain_id":-1,"slug":"my-page","title":"My page title"}'
Creation returns a draft with working and published version records. Neither version has body sections or default stacks. Internal editor settings are initialized so the empty page can be opened in the builder and published.
Successful create, get, update, and publish operations return { "page": {...} }; listing returns the paginated response described above. The page contains the settings above plus id, domain (hostname), url, and status (draft, generating, or published). Design data and internal version records are omitted.
Update Settings
curl -X PATCH 'https://grawt.app/api/v1/pages/123' \
-H 'X-API-Key: your-api-key' \
-H 'Content-Type: application/json' \
-d '{"title":"Updated title","is_index_enabled":true}'
Settings are saved immediately. This does not modify the working or published design.
Publish a Page
curl -X POST 'https://grawt.app/api/v1/pages/123/publish' \
-H 'X-API-Key: your-api-key'
No body is required. Publishing snapshots and renders the current working version, sets the status to published, clears cached page content, and triggers the existing publication event. The working design remains editable. Empty pages can be published; pages still generating or missing a working version return 422. The latest 15 published snapshots are retained.
Page and Domain Errors
Missing pages, unavailable domains, and resources outside the authenticated account return 404 with { "error": "Page not found." } or { "error": "Domain not found." }.
Page settings validation returns 422:
{
"error": {
"slug": ["The page URL already exists under this domain."]
}
}
Error Handling
Validation response formats are documented per endpoint; page settings use the error field shown above.
Validation Errors (422)
When request validation fails:
{
"message": "The email field is required.",
"errors": {
"email": ["The email field is required."]
}
}
Common Error Codes
| Status Code | Description |
|---|---|
| 400 | Bad Request - Missing API key |
| 401 | Unauthorized - Invalid API key |
| 404 | Not Found - Resource doesn't exist |
| 422 | Unprocessable Entity - Validation error |
| 500 | Internal Server Error |
Rate Limiting
API requests are subject to rate limiting. If you exceed the limit, you'll receive a 429 Too Many Requests response.
Best Practices
Security
- Never expose your API key in client-side code (JavaScript, React, Vue, etc.)
- Store your API key in environment variables on your server
- Use server-to-server communication for API calls
Recommended Architecture
[Client Browser] → [Your Backend Server] → [Grawt API]
Your frontend should submit data to your own backend, which then makes authenticated requests to the Grawt API.
Quick Reference
| Endpoint | Method | Description |
|---|---|---|
/api/v1/leads |
POST | Add a new lead |
/api/v1/leads/{email} |
PUT | Update an existing lead |
/api/v1/leads/sync |
POST | Create or update a lead (upsert) |
/api/v1/leads/{email} |
DELETE | Delete a lead |
/api/v1/leads/{email}/tags |
POST | Apply tags to a lead |
/api/v1/leads/{email}/tags |
DELETE | Remove tags from a lead |
/api/v1/leads/fields |
GET | Get available lead fields |
/api/v1/tags |
GET | Get all tags |
/api/v1/domains |
GET | List available domains |
/api/v1/domains/{domain_id} |
GET | Get an available domain |
/api/v1/pages |
GET | List account pages with pagination |
/api/v1/pages |
POST | Create an empty page |
/api/v1/pages/{page_id} |
GET | Get page settings |
/api/v1/pages/{page_id} |
PATCH | Update page settings |
/api/v1/pages/{page_id}/publish |
POST | Publish the working page design |