Files
supabase/apps/docs/content/guides/api/creating-routes.mdx
T
Miranda Limonczenko d7f1a44e53 docs: restructure the API keys guide by information type (#49796)
## I have read the
[CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md)
file.

YES

## What kind of change does this PR introduce?

Docs update. Restructure, mostly moved lines, plus a tense fix in a
shared partial.

## What is the current behavior?

Context, procedure, and reference material are interleaved, so
background reading interrupts the action path.

- The page never states which key to use as an answer. You infer it from
a five-column reference table.
- Finding a key is a fragment inside an admonition, placed above the
page's own definition of an API key.
- Rotating a leaked key, the only procedure on the page, is the last H3.
- The "Changes to API keys" notice narrates a past change in future
tense, and "They will be deprecated" has no antecedent in its paragraph.

## What is the new behavior?

Group the guide into context, procedure, and reference sections, per
CONTRIBUTING § Guides on mixed information types.

- Lead with "Which key do you use?", a decision table keyed on where the
code runs. Section navigation sits directly below the intro.
- Collect the conceptual sections under "How API keys work" and give
publishable and secret keys parallel headings.
- Promote both procedures into "Find and use your keys". Rotation is now
an ordered procedure.
- Move the enumerated secret key rules into "Security reference",
grouped under bold labels by the kind of mistake each prevents, and
leave a short danger admonition where secret keys are introduced.
- Promote the five-sentence coexistence admonition to its own section.
Admonitions are for short warnings.
- Rewrite the shared deprecation partial for timeless documentation:
present tense, no dangling "They", no "now". The partial renders on five
pages.
- Pin a stable anchor on the rotation heading and update the one inbound
link, in the rotating-anon-service-and-jwt-secrets troubleshooting
entry.
- Align link text across docs for this guide. Twenty-one links pointed
at it under fourteen labels, including two that named the wrong
destination. Rule: when a link means the guide, the text is "API keys";
when it means a specific key or section, the specific text stays. Twelve
now share "API keys", up from three.

Review with `git diff --color-moved=zebra`.

## Additional context

PR 2 of 4. Base is #49795. Includes the link-text alignment previously
opened as #49866.

## Manual testing

1. Open the API keys guide on the deploy preview.
2. Check the table of contents. It shows three groups: How API keys
work, Find and use your keys, Security reference.
3. Open the rotating-anon-service-and-jwt-secrets troubleshooting entry
and follow "Rotate a leaked or compromised key" under Further readings.
It lands on the renamed heading.
4. Open the Realtime Broadcast guide and check the "Changes to API keys"
notice. It reads in present tense there too.


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

- **Documentation**
- Updated API key guidance to explain the transition from legacy `anon`
and `service_role` keys to publishable and secret keys by the end of
2026.
- Reorganized the API keys guide with clearer key-selection guidance,
security recommendations, usage examples, and rotation steps.
- Updated troubleshooting references to point to the revised leaked-key
rotation guidance.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-09-01 14:40:54 -07:00

136 lines
4.6 KiB
Plaintext

---
id: 'creating-routes'
title: 'Creating API Routes'
description: 'API routes are automatically created when you create Postgres Tables, Views, or Functions.'
---
API routes are automatically created when you create Postgres Tables, Views, or Functions.
## Create a table
Create your first API route by creating a table called `todos` to store tasks.
This creates a corresponding route `todos` which can accept `GET`, `POST`, `PATCH`, & `DELETE` requests.
<Tabs
scrollable
size="small"
type="underlined"
defaultActiveId="dashboard"
queryGroup="database-method"
>
<TabPanel id="dashboard" label="Dashboard">
1. Go to the [Table editor](/dashboard/project/_/editor) page in the Dashboard.
1. Click **New Table** and create a table with the name `todos`.
1. Click **Save**.
1. Click **New Column** and create a column with the name `task` and type `text`.
1. Click **Save**.
1. In the [**Integrations > Data API**](/dashboard/project/_/integrations/data_api/settings) section of the Dashboard, expose specific tables like `todos` or the functions you want to access. To automatically grant access for new tables and functions in `public`, enable **Default privileges for new entities**.
</TabPanel>
<TabPanel id="sql" label="SQL">
```sql
-- Create a table called "todos" with a column to store tasks.
create table
todos (
id bigint generated by default as identity primary key,
task text check (char_length(task) > 3)
);
-- Enable Data API access with least-privilege grants
-- Allow read-only access for anonymous clients
grant select on public.todos to anon;
-- Allow full CRUD for authenticated clients
grant select, insert, update, delete on public.todos to authenticated;
-- Allow full CRUD for the server-side service role
grant select, insert, update, delete on public.todos to service_role;
-- Important: enable Row Level Security and create appropriate policies
-- before granting write access to client roles (see RLS guide)
```
</TabPanel>
</Tabs>
<Admonition type="note" title="What it means to expose tables or functions via the API">
Granting privileges (like `select` or `execute`) to roles such as `anon` or `authenticated` makes those tables or functions accessible through the Data API. Behind the scenes, the API checks your Postgres permissions—only objects with explicit grants are exposed, and all other access is denied by default.
</Admonition>
## API URL and keys
Every Supabase project has a unique API URL. Your API is secured behind an API gateway which requires an API Key for every request.
{/* TODO: Further consolidate partial */}
To do this, you need to get the Project URL and key from [the project's **Connect** dialog](/dashboard/project/_?showConnect=true).
<$Partial path="api_keys_deprecation.mdx" variables={{ "framework": "{{ .framework }}", "tab": "{{ .tab }}" }} />
See [API keys](/docs/guides/getting-started/api-keys) for a full explanation of all key types and their uses.
The REST API is accessible through the URL `https://<project_ref>.supabase.co/rest/v1`
Both of these routes require the key to be passed through an `apikey` header.
## Using the API
You can interact with your API directly via HTTP requests, or you can use the client libraries which we provide.
See how to make a request to the `todos` table which we created in the first step,
using the API URL (`SUPABASE_URL`) and Key (`SUPABASE_PUBLISHABLE_KEY`) we provided:
<Tabs
scrollable
size="small"
type="underlined"
defaultActiveId="javascript"
queryGroup="language"
>
<TabPanel id="javascript" label="JavaScript">
```javascript
// Initialize the JS client
import { createClient } from '@supabase/supabase-js'
const supabase = createClient(SUPABASE_URL, SUPABASE_PUBLISHABLE_KEY)
// Make a request
const { data: todos, error } = await supabase.from('todos').select('*')
```
</TabPanel>
<$Show if="sdk:csharp">
<TabPanel id="csharp" label="C#">
```c#
// Initialize the client
var supabase = new Supabase.Client(SUPABASE_URL, SUPABASE_PUBLISHABLE_KEY);
await supabase.InitializeAsync();
// Make a request
var todos = await supabase.From<Todo>().Get();
```
</TabPanel>
</$Show>
<TabPanel id="curl" label="cURL">
```bash
# Append /rest/v1/ to your URL, and then use the table name as the route
curl '<SUPABASE_URL>/rest/v1/todos' \
-H "apikey: <SUPABASE_PUBLISHABLE_KEY>" \
-H "Authorization: Bearer <SUPABASE_PUBLISHABLE_KEY>"
```
</TabPanel>
</Tabs>
JS Reference: [`select()`](/docs/reference/javascript/select),
[`insert()`](/docs/reference/javascript/insert),
[`update()`](/docs/reference/javascript/update),
[`upsert()`](/docs/reference/javascript/upsert),
[`delete()`](/docs/reference/javascript/delete),
[`rpc()`](/docs/reference/javascript/rpc) (call Postgres functions).