API Endpoints

Reference for the REST API of the platform DevOur generates for your project.

Authentication

When your project has Firebase configured, requests need the signed-in user's Firebase ID token:

Authorization: Bearer <firebase-id-token>

These endpoints don't need a token:

A missing token returns 401 with EMPTY_BEARER_TOKEN. An invalid or revoked token returns 401 with UNABLE_VERIFY_TOKEN.

Errors

Most errors use this shape:

{
  "status": false,
  "error_key": "RESOURCE_NOT_FOUND",
  "message": "...",
  "code": 404,
  "details": {}
}

Endpoints that answer differently say so below.

Each client can send up to 100 requests per minute, and 5 per minute to GET /api/users/registered. Past that, the API returns 429 with details.error set to RATE_LIMIT_EXCEEDED.

Which Endpoints Your Platform Has

Users

A user has these fields: id, createdAt, updatedAt, uid, email, isVerified, customerID, requirePlan, and role.

GET /api/users

Get the signed-in user, with their subscription status.

Returns 200 with {"user": {...}}. The user also includes hasSubscription, subscriptionExpired, planID, and usageLimits: for each usage limit, its name, the max of the customer's plan, and how many records they have used. Without a plan, usageLimits is empty and hasSubscription is false. When the signed-in person has no user record yet, returns 200 with {"error": "NO_USER_FOUND"}.

POST /api/users/create

Create the user record for the signed-in Firebase user, or return the existing one. No body.

Returns 200 with {"user": {...}}.

POST /api/users/validate

Check that the token is valid. No body. Returns 200 with {}.

GET /api/users/registered

Check whether an email address has an account. No token needed.

Query parameterDescription
emailEmail address to check

Returns 200 with {"message": "REGISTERED"}, or 200 with {"error": "NO_USER"} when there's no account.

DELETE /api/users

Delete the signed-in user's account and their Firebase identity. Returns 200 with {}.

GET /api/users/all

List all users. Admins only.

Returns 200 with {"users": [...]}, or 401 with PERMISSION_DENIED for other users.

POST /api/users/{id}

Save a user. Admins only. Send the user object in the body.

Returns 200 with {"user": {...}}, or 403 with {"error": "PERMISSION_DENIED"} for other users.

Products

A product has these fields: ID, productID, maxUsage, limits, name, description, descriptor, features, priceID, currency, interval, intervalCount, amount, and active.

GET /api/products/all

List your project's products with their Stripe prices.

Returns 200 with {"products": [...], "stripeProducts": [...]}.

GET /api/products/{id}

Get one product. id is the Stripe product ID.

Returns 200 with {"product": {...}}, or 404 with RESOURCE_NOT_FOUND.

POST /api/products/payment-link

Create a Stripe payment link for a price. After checkout, Stripe sends the user back to returnURL.

Body fieldTypeDescription
priceIDstringStripe price ID
returnURLstringWhere to send the user afterwards

Returns 200 with {"paymentLink": "https://..."}.

Collections

An entity has these fields: id, createdAt, updatedAt, name, collectionId, ownerId, and properties. ownerId is the user who created it.

In a collection whose records are private to each customer, a signed-in user without the admin role only lists, reads, updates, and deletes the entities they created. Anyone else's entity returns 404 with RESOURCE_NOT_FOUND. Admins reach every entity. In a shared collection, every signed-in user reaches every entity. Deleting a user's account also deletes the entities they own in private collections.

In a collection linked to a usage limit, a signed-in user without the admin role needs a plan to create, update, or delete entities. Without one, those return 403 with PLAN_REQUIRED. Creating also returns 403 with USAGE_LIMIT_REACHED once the entities they own across every collection linked to that limit reach their plan's number. Reading is never limited. See Usage Limits and What They Cap.

GET /api/collections/{collectionId}/entities

List a collection's entities, a page at a time.

Query parameterDefaultDescription
page1Page number
perPage12Entities per page

Returns 200 with {"entities": [...], "page": 1, "perPage": 12, "totalItems": 0, "totalPages": 0}.

POST /api/collections/{collectionId}/entities/new

Create an entity.

Body fieldTypeDescription
namestringEntity name, 1 to 256 characters
propertiesobjectProperty values

The entity goes into the collection in the path and is owned by the signed-in user. Returns 200 with {"entity": {...}}.

GET /api/collections/{collectionId}/entities/{entityId}

Get one entity. Returns 200 with {"entity": {...}}, or 404 with RESOURCE_NOT_FOUND.

POST /api/collections/{collectionId}/entities/{entityId}

Update an entity's name and properties. Returns 200 with {"entity": {...}}, or 404 with RESOURCE_NOT_FOUND.

DELETE /api/collections/{collectionId}/entities/{entityId}

Delete an entity. Returns 200 with {}, or 404 with RESOURCE_NOT_FOUND.

Forms

POST /api/forms/{form-slug}

Submit a form. Each form has its own endpoint, named after the form: its words in lowercase, joined with -. A form called "Contact Us" is at POST /api/forms/contact-us.

The body has one key per field, named after the field's label in camelCase, so "Email Address" becomes emailAddress. Values depend on the field type:

Field typeValue
Numbernumber
Toggle, checkboxboolean
Address, address with country{"street", "city", "postalCode", "province", "country"}
Phone number{"number", "extension"}
Any other typestring

Returns 201 with {"submission": {...}}. Returns 400 when a required text field is empty or doesn't match its pattern.

Mail

These endpoints send emails through Resend in the requested language. They don't need a token. Each needs locale, or it returns 400.

POST /api/mail/send-password-reset

Body fieldDescription
emailAddress to send the reset email to
resetLinkPage of your platform that handles the reset
localeLanguage code of the email, such as en

Returns 200 with {"message": "Password reset email sent!"}.

POST /api/mail/send-email-verification

Body fieldDescription
emailAddress to verify
verifyLinkPage of your platform that handles verification
localeLanguage code of the email

Returns 200 with {"message": "Verification email sent!"}.

POST /api/mail/send-sign-in-link

Send a passwordless sign-in link.

Body fieldDescription
emailAddress of an existing account
signInLinkPage of your platform that completes sign-in
localeLanguage code of the email

Returns 200 with {"message": "Sign-in link sent!"}, or 400 with EMAIL_NOT_FOUND when the address has no account.

Uploads

POST /api/upload-image

Upload an image as multipart/form-data in the image field. Returns 200 with {"url": "/uploads/..."}.

POST /api/upload-file

Upload a file as multipart/form-data in the file field. Returns 200 with {"url": "/uploads/..."}.

Theme

GET /api/theme/bundle and GET /api/theme/css

Serve the files of your project's theme when it uses a theme from the marketplace. Your platform loads them itself. They return 404 when the project uses the default theme.

Webhooks

POST /webhook/stripe

Receives Stripe events. See Webhooks.

Health

GET /health

In the production build, returns 200 with ok.