# dontlosedata: a database in one URL > Save and load your app's data with a single web address. No server to set up, no database to manage, nothing to install. Built for people making apps with AI tools, and for developers who want storage in seconds. - Get a free endpoint instantly: https://dontlosedata.site - Endpoint URL: `https://dontlosedata.site/api/v1/` - This document as plain text (for AI assistants): https://dontlosedata.site/llms.txt ## What it is dontlosedata gives you a private web address, called an **endpoint**, that works like a small online notebook for your app. Your app can write information to it, read it back, change it and delete it, from any device and any website. You don't need to rent a server, install a database or learn a backend framework. If your app can load a web page, it can use dontlosedata. ## The problem it solves Building an app has never been easier. Tools like Lovable, Replit, ChatGPT, Claude and v0 can make a working screen in minutes. But as soon as the app needs to *remember* something (a todo, a high score, a product price), you hit a wall: - **The data disappears.** It only lives in the browser, so it's gone on reload, and nobody else can see it. - **"Now set up a backend."** The usual answer is a database service with accounts, tables, permissions, keys and settings. That takes hours, and it's the part AI tools most often get wrong. - **Errors you can't fix.** Messages about CORS, missing keys or failed connections stop non-developers cold. dontlosedata removes that wall. You get one URL, your AI gets one short set of instructions, and saving data just works. ## What you can build - **Todo lists, notes and habit trackers** that stay in sync between your phone and laptop. - **Game leaderboards** and saved progress. - **Product lists, menus and price lists** you edit from the dashboard instead of rebuilding the site. - **Expense, workout and reading logs** that follow you from phone to laptop. - **Site content you can change without republishing**: announcements, opening hours, FAQs, portfolio projects, on/off switches for features. - **Event schedules and timetables** that you update in one place. - **Internal tools** for a team: stock counts, checklists, equipment lists. - **Prototypes, demos and hackathon projects** that need real data today, not after a week of setup. - **Classroom projects** where students should focus on the app, not on servers. Ideas by audience: [Restaurants & cafés](https://dontlosedata.site/for/restaurants) · [Small shops & makers](https://dontlosedata.site/for/shops) · [Personal tools](https://dontlosedata.site/for/personal) · [Creators & freelancers](https://dontlosedata.site/for/creators) · [Teachers & tutors](https://dontlosedata.site/for/teachers) · [Events & communities](https://dontlosedata.site/for/events) · [Gyms, studios & coaches](https://dontlosedata.site/for/fitness) · [Game makers](https://dontlosedata.site/for/games) ## Where it works Anywhere that can send a web request: - **AI app builders**: Lovable, Replit, v0, Bolt - **AI assistants and editors**: ChatGPT, Claude, Cursor - **Websites**: plain HTML pages, and site builders that let you add a custom form or code - **Automation tools** that can call a URL, such as Zapier, Make or n8n - **Mobile apps, scripts and servers** in any programming language ## Features - **Ready in one click.** Open the homepage and your endpoint already exists. No account needed to try it. - **Made for AI builders.** Copy one ready-made prompt that contains your endpoint and the rules. Paste it into your AI tool and describe what you want. - **Read, add, change and delete** any part of your data. Find items by any field, filter, sort and page through long lists. - **Forms without code.** Point any HTML form at your endpoint and every submission is saved. A built-in trap catches spam bots. - **Works from any website.** No CORS errors. If you want, allow only your own websites. - **Lock it down when you need to.** Add API keys so that only your app can change the data, or so that nobody can read it without a key. - **A dashboard for your data.** Browse and edit what's stored, see every request as it happens, and track daily and monthly usage. - **Clear error messages.** Every error says what went wrong and how to fix it, so your AI assistant can correct itself. - **Sign in with Google** to keep your endpoints, create more and manage them in one place. ## Getting started 1. Open https://dontlosedata.site. Your endpoint is created right away. 2. Click **Copy my prompt** and paste it into Lovable, Replit, ChatGPT, Claude, v0, Bolt or Cursor. 3. Tell your AI what to build. Everything your app saves goes to your endpoint. 4. Want to keep it? Sign in with Google and the endpoint moves into your account. Prefer to write code yourself? Skip to the [technical reference](#technical-reference). ## Good to know - **Is my data private?** Your endpoint address contains a long random ID that can't be guessed, but anyone who has the address can use it. Don't store personal details (names, email addresses, phone numbers), passwords, payment details, health records or other sensitive information. Add an API key to protect an endpoint. - **I changed a setting. Does my AI need to know?** Yes. When you add an API key or limit which websites can use an endpoint, the dashboard gives you an updated prompt. Paste it into your AI and it updates your app. - **What does it cost?** It's free during beta, with no credit card. Paid plans with higher limits are coming. - **Do I need an account?** No. Endpoints made without an account work right away, but they are deleted if unused for 3 hours, or after 30 days without use. Sign in to keep them. - **Can I use it for a real product?** For small apps, prototypes, catalogs and internal tools, yes. It's a simple data store, not a replacement for a full database, so keep your own copy of anything important. --- ## Technical reference Each endpoint stores **one JSON value** (an object or an array). Read and change it with plain HTTP from any website, app or AI tool. No SDK, no backend, CORS enabled. ## 1. The idea The **uuid is your endpoint**. Everything after it in the URL is a *path* into your JSON: ``` https://dontlosedata.site/api/v1/ the whole JSON https://dontlosedata.site/api/v1//openingHours the "openingHours" key of an object https://dontlosedata.site/api/v1//id/101 the item with id 101 in a list ``` A new endpoint is empty: `GET` returns `null` until you write something. Send JSON with `Content-Type: application/json`. Responses are always JSON (the raw value, no wrapper). In the examples below, `xyz` means `https://dontlosedata.site/api/v1/`. ## 2. Path rules | The data at this point is… | Path part | Means | |---|---|---| | an object | `/openingHours` | the value of key `openingHours` | | an object | `/opening*` | every key matching the `*` wildcard (returns an object) | | a list | `/id/101` | the **first** item whose field `id` equals `101` | | a list | `/title/B*` | **all** items whose `title` matches `B*` (returns a list) | | a list | `/0`, `/1`, … | the item at that position (digits only) | | a list | `/*/title` | `title` from every item (returns a list) | - **Rule of thumb: an exact path returns one thing; any `*` returns a list.** - Values are compared as text: `/id/101` matches `101` and `"101"`; `/done/true` matches `true`. - Nested fields use dots: `/details.color/red`. - Wildcards ignore upper/lower case: `/title/wat*` matches `Water plants`. - Paths can continue after a match: `xyz/id/101/title` returns `"Buy milk"`. ## 3. Example: an object Stored JSON: ```json { "announcement": "Summer sale this week!", "openingHours": ["Mon-Fri 9-17", "Sat 10-14"], "theme": "dark" } ``` | Request | Body | Result | |---|---|---| | `GET xyz` | | the whole object | | `GET xyz/openingHours` | | `["Mon-Fri 9-17","Sat 10-14"]` | | `GET xyz/openingHours/1` | | `"Sat 10-14"` | | `GET xyz/announcement` | | `"Summer sale this week!"` | | `PUT xyz/announcement` | `"Free shipping today"` | the banner text changes | | `PUT xyz/settings/fontSize` | `16` | creates `{"settings":{"fontSize":16}}` | | `POST xyz/openingHours` | `"Sun closed"` | appends: `["Mon-Fri 9-17","Sat 10-14","Sun closed"]` | | `PATCH xyz` | `{"theme":"light","announcement":null}` | merges: theme changes, announcement is removed | | `DELETE xyz/openingHours/0` | | removes `"Mon-Fri 9-17"` | | `DELETE xyz/theme` | | removes the key | | `DELETE xyz` | | clears the whole endpoint | ## 4. Example: a list Stored JSON: ```json [ { "id": 101, "title": "Buy milk", "done": false, "dueDate": "2026-01-01" }, { "id": 102, "title": "Water plants", "done": true, "dueDate": "2026-01-02" } ] ``` | Request | Body | Result | |---|---|---| | `GET xyz` | | the whole list | | `GET xyz/id/101` | | `{"id":101,"title":"Buy milk","done":false,"dueDate":"2026-01-01"}` | | `GET xyz/id/101/title` | | `"Buy milk"` | | `GET xyz/0` | | the first item | | `GET xyz/title/W*` | | `[{"id":102,…}]` | | `GET xyz/*/title` | | `["Buy milk","Water plants"]` | | `POST xyz` | `{"title":"Read a book"}` | appends `{"id":"k3j9x2m1ab7q","title":"Read a book"}` (an `id` is added) | | `PUT xyz/id/101` | `{"id":101,"title":"Buy oat milk","done":false}` | replaces item 101 | | `PUT xyz/id/105` | `{"title":"Bake bread"}` | item 105 doesn't exist, so it is **created** with `"id":105` | | `PATCH xyz/id/101` | `{"done":true}` | merges into item 101 | | `PATCH xyz/title/*` | `{"done":false}` | merges into every item | | `DELETE xyz/id/101` | | removes item 101, returns `{"deleted":1}` | | `DELETE xyz/done/true` | | removes the first finished item, returns `{"deleted":1}` | | `DELETE xyz/title/W*` | | removes every match, returns `{"deleted":n}` | ## 5. Methods - **GET**: read the value at the path. `404` if nothing is there. - **POST**: append the body to the **list** at the path. If the path is empty or missing, a new list is created, so the very first `POST xyz` turns an empty endpoint into `[item]`. Objects without an `id` get a unique `id` (turn this off with `?_auto_id=false`). Returns the saved item with `201`. POST on an object returns `409`; use PUT or PATCH there. - **PUT**: replace the value at the path. Missing keys are created. `PUT xyz//` creates the item if no item matches (upsert). `PUT xyz` replaces everything. - **PATCH**: merge a JSON object into the object(s) at the path ([JSON Merge Patch](https://www.rfc-editor.org/rfc/rfc7396)): keys are added or replaced, nested objects are merged, and `null` removes a key. - **DELETE**: remove the value at the path, or every match of a wildcard. `DELETE xyz` clears the endpoint. Returns `{"deleted": n}`. ## 6. Filtering, sorting and paging lists Add query parameters to any `GET` that returns a list: | Query | Meaning | |---|---| | `?done=true` | field equals value | | `?category=home&category=work` | either value | | `?title=Bu*` | wildcard, ignores case | | `?details.color=red` | nested field | | `?price_gt=10` `_gte` `_lt` `_lte` | number or text comparison | | `?status_ne=archived` | not equal | | `?_sort=-dueDate,title` | sort; `-` means newest/biggest first | | `?_limit=20&_offset=40` | paging | | `?_page=3&_limit=20` | paging by page number | The number of matches before paging is in the `X-Total-Count` response header. ## 7. JavaScript ```js const url = "https://dontlosedata.site/api/v1/"; // add const saved = await fetch(url, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ title: "Buy milk", done: false }), }).then((r) => r.json()); // list const todos = await fetch(url).then((r) => r.json()); // null if empty // update await fetch(`${url}/id/${saved.id}`, { method: "PATCH", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ done: true }), }); // delete await fetch(`${url}/id/${saved.id}`, { method: "DELETE" }); ``` ## 8. HTML forms Any HTML form can post to `https://dontlosedata.site/f/`. Each submission is **appended** as an item (with an `id`). Add a path to collect submissions under a key, e.g. `/f//products`. A small "add a product" form is all a shop owner needs to update their catalog without touching code: ```html
``` Each submission is saved like `{"id":"…","name":"Blue mug","price":"12.50","category":"Kitchen"}`. Form values always arrive as text, so `price` is `"12.50"`; send JSON with `fetch` if you need real numbers. Without `_redirect` the visitor sees a simple "Thanks" page. Requests with `Accept: application/json` get the saved item as JSON. File uploads are not supported. Avoid collecting personal details such as names or email addresses: endpoints are not meant for personal data. ## 9. API keys (optional) Endpoints are public by default: anyone with the URL can use them. After signing in you can create API keys and assign them to endpoints. Then choose what needs a key: - **Everything needs a key** - **Reading is public, changing needs a key** - **Form submissions are public, everything else needs a key** Send the key as `Authorization: Bearer ` or `X-API-Key: `. Keys placed in browser code are visible to visitors, so prefer "reading is public" or "forms are public" for websites, and keep full keys on servers. ## 10. CORS and allowed websites CORS is open: every website can call the API directly from the browser, including with `credentials: "include"`, and with any custom headers. Error responses carry CORS headers too, so you always see the real error message. Optionally, in the dashboard, add **allowed websites** (for example `https://myapp.com`, `*.lovable.app`, `localhost:*`). Calls from other websites then get `403 origin_not_allowed`. This stops other sites from using your endpoint in a browser; it is not a replacement for an API key. ## 11. Errors Errors always look like this: ```json { "error": { "code": "path_not_found", "message": "Nothing found at '/id/999'.", "hint": "…", "docs": "https://dontlosedata.site/llms.txt" } } ``` | Status | Code | Meaning | |---|---|---| | 400 | `invalid_json`, `missing_body`, `incomplete_path`, `wildcard_not_allowed` | the request is malformed | | 401 | `api_key_required`, `invalid_api_key` | protected endpoint | | 403 | `origin_not_allowed`, `blocked`, `endpoint_blocked`, `endpoint_limit` | not allowed | | 404 | `endpoint_not_found`, `path_not_found` | nothing there | | 409 | `not_a_list`, `not_an_object`, `cannot_go_deeper` | the method doesn't fit the data type | | 413 | `payload_too_large`, `endpoint_full`, `storage_full` | size limits | | 422 | `body_must_be_object`, `files_not_supported` | wrong body | | 429 | `rate_limited`, `quota_exceeded` | slow down; see `Retry-After` | ## 12. Limits Every response includes `X-RateLimit-Limit` and `X-RateLimit-Remaining`. Endpoints created without an account allow 30 requests per minute, 1,000 per day, 32 KB per request and 256 KB of data. They are deleted if unused for 180 minutes, or after 30 days without requests. Sign in for higher limits and to keep endpoints.