Documentation
Everything you need to collect, manage, and retrieve form submissions with Drapi.dev.
Introduction
Drapi.dev is the easiest way to add a backend to a form. You point any HTML form (or fetch call) at a unique endpoint URL, and Drapi.dev stores the submissions, filters spam, and emails you when new entries arrive — no server code required on your side.
Everything is organized in a simple hierarchy: a project groups related forms and holds shared settings like allowed domains and usage quotas, and each form has its own endpoint, notification settings, and API key.
Quick start
- 1Sign up and create a project from the dashboard.
- 2Create a form inside the project and copy its endpoint URL.
- 3Point your HTML form's
actionat that URL withmethod="POST". - 4Submit the form — the entry appears in your dashboard and you get an email notification.
<form action="https://drapi.dev/f/{form-id}" method="POST">
<!-- Honeypot (leave empty) -->
<input type="hidden" name="_honeypot" value="" style="display:none">
<input type="text" name="name" placeholder="Your name" required>
<input type="email" name="email" placeholder="Email" required>
<textarea name="message" placeholder="Message" required></textarea>
<button type="submit">Send</button>
</form>Creating a project
Projects are the top-level container. Each project has its own allowed domains, monthly submission quota, and analytics.
- 1Go to Projects in the dashboard sidebar.
- 2Click New project and give it a name (e.g. "Portfolio site").
- 3Open the project to add forms and configure allowed domains.
Allowed domains
Allowed domains restrict where submissions can come from. When a request hits your form endpoint, its Origin / Refererheaders are checked against the project's domain list. Requests from other origins are rejected with 403 DOMAIN_NOT_ALLOWED.
- 1Open your project and go to its Settings tab.
- 2Add each domain your forms live on, e.g.
example.com. - 3Subdomains are matched automatically —
blog.example.comis covered byexample.com.
localhost and 127.0.0.1 are always allowed, so local development keeps working.Creating a form
Each form gets a unique public ID and an endpoint URL of the shape https://drapi.dev/f/{form-id}.
- 1Inside a project, click New form and name it (e.g. "Contact form").
- 2Optionally configure email notifications and a redirect URL.
- 3Copy the endpoint URL from the top of the form's page. Its Setup tab has ready-made examples for HTML, React, fetch and cURL.
Posting submissions
Send a POST request to your form endpoint. No authentication is needed — the request is validated by origin, rate limits, and spam checks. Accepted content types: application/json, application/x-www-form-urlencoded, and multipart/form-data.
curl -X POST 'https://drapi.dev/f/{form-id}' \
-H 'Content-Type: application/json' \
-d '{"name":"Jane Doe","email":"jane@example.com","message":"Hello!"}'All fields in the body are stored as the submission payload, with two rules:
| Field | Behavior |
|---|---|
_honeypot | Spam trap. Must be empty or absent — a non-empty value rejects the submission. Include it as a hidden field that real users never fill. |
_* | Any field starting with an underscore is treated as internal and stripped before the payload is stored. |
A successful submission returns:
{
"success": true,
"id": "665f1c2e8b3a4d0012ab34cd",
"redirectUrl": "https://yoursite.com/thank-you" // only if configured
}Fetching submissions
Besides accepting submissions, every form exposes a read API — useful for building an admin page on your own site that lists everything the form has received. Requests are authenticated with the form's API key, sent as a Bearer token.
curl 'https://drapi.dev/f/{form-id}/submissions?page=1&limit=25' \
-H 'Authorization: Bearer inb_your_api_key'Query parameters:
| Parameter | Default | Description |
|---|---|---|
page | 1 | Page number, newest submissions first. |
limit | 25 | Results per page, maximum 100. |
from | — | Only submissions created at or after this ISO date. |
to | — | Only submissions created at or before this ISO date. |
{
"form": { "id": "a1b2c3d4-...", "name": "Contact form" },
"submissions": [
{
"id": "665f1c2e8b3a4d0012ab34cd",
"data": { "name": "Jane Doe", "email": "jane@example.com", "message": "Hello!" },
"createdAt": "2026-07-08T09:30:00.000Z"
}
],
"pagination": { "page": 1, "limit": 25, "total": 1, "totalPages": 1 }
}Example: fetching submissions from your own server to render an admin page.
const res = await fetch('https://drapi.dev/f/{form-id}/submissions?limit=50', {
headers: { Authorization: `Bearer ${process.env.INBOUND_API_KEY}` },
})
const { submissions, pagination } = await res.json()API keys
The read API is protected by a secret per-form API key (prefixed inb_). The form's public ID appears in your website's HTML, so it can never grant read access on its own.
- 1Open your form and go to the Settings tab.
- 2In the API access card, click Generate API key.
- 3Copy the key and store it somewhere safe, e.g. an environment variable on your server.
From the same card you can regenerate the key (the old one stops working immediately) or revoke it to disable read access entirely.
Rolling the form ID
If your endpoint URL leaks or starts attracting spam, you can rotate the form's public ID. This generates a brand-new endpoint URL and permanently invalidates the old one — existing submissions are kept.
- 1Open your form's Settings tab.
- 2In the Danger zone, click Rotate next to Rotate endpoint and confirm.
- 3Update every website that posts to the form with the new URL — the old URL returns
404immediately.
Email notifications
When enabled, every new submission triggers an email. Configure this in the form's Settings tab:
| Setting | Description |
|---|---|
| Recipient emails | Up to 2 addresses. Defaults to your account email when empty. |
| Email subject | Custom subject line. Defaults to "New submission on [form name]". |
| Sender name | The name shown in the From field. |
| Redirect URL | Where the submitter is sent after a successful submission: HTML form posts get a 303 redirect, JavaScript requests get it as redirectUrl in the JSON. Leave blank to return JSON. |
Pausing submissions
You can temporarily stop accepting submissions without deleting anything. While paused, the endpoint responds with 503 FORM_PAUSED and nothing is stored.
- 1Open the form in your dashboard.
- 2Switch Accepting off in the page header. Switch it back on anytime to resume.
Rate limits & quotas
| Limit | Value | Scope |
|---|---|---|
| Posting submissions | 10 requests / minute | Per IP |
| Reading submissions | 60 requests / minute | Per IP |
| Payload size | 100 KB | Per submission |
| Monthly submissions | 100 / month (free plan) | Per project |
| Forms | 1 (free plan) | Per project |
When a rate limit is hit the API returns 429 with a Retry-After header. The monthly quota resets on the first day of each month (UTC).
Error reference
All errors share the same shape:
{ "error": "ERROR_CODE", "message": "Human-readable description." }Posting submissions:
| Code | HTTP | Meaning |
|---|---|---|
NOT_FOUND | 404 | Form ID is invalid or the form does not exist. |
PAYLOAD_TOO_LARGE | 413 | Body exceeds the 100 KB limit. |
RATE_LIMITED | 429 | More than 10 submissions per minute from one IP. |
FORM_PAUSED | 503 | The form is currently paused. |
DOMAIN_NOT_ALLOWED | 403 | Origin/Referer is not in the project’s allowed domains. |
SPAM_DETECTED | 400 | The honeypot field was filled in. |
QUOTA_EXCEEDED | 429 | The project’s monthly submission quota is used up. |
Fetching submissions:
| Code | HTTP | Meaning |
|---|---|---|
UNAUTHENTICATED | 401 | No Bearer token in the Authorization header. |
INVALID_API_KEY | 401 | The key is wrong or has been revoked. |
NOT_FOUND | 404 | Form ID is invalid or the form does not exist. |
RATE_LIMITED | 429 | More than 60 requests per minute from one IP. |
