Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions src/routes/changelog/(entries)/2026-04-10.markdoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
---
layout: changelog
title: "Public project APIs for platforms and API keys"
date: 2026-04-10
---

Appwrite now exposes **public project APIs** for managing platforms and API keys programmatically. Previously these resources could only be configured through the Console; now you can automate project setup entirely through the API or Server SDKs.

# Platforms API

Create, list, update, and delete platforms through dedicated endpoints per platform type: **web**, **apple**, **android**, **windows**, and **linux**. Each type uses its own identifier (hostname, bundle identifier, application ID, package identifier name, or package name).

The previous ~15 framework-specific platform types (`flutter-ios`, `flutter-android`, `apple-macos`, `react-native-ios`, etc.) have been consolidated into these 5 types. Existing platforms with deprecated types are mapped automatically when read.

# API keys API

Create, list, get, update, and delete API keys through the API. You can assign scopes and set expiration dates programmatically, enabling automated key rotation and infrastructure-as-code workflows.

# New scopes

Six new scope pairs are now available for API keys:

- `platforms.read` / `platforms.write` -- manage project platforms
- `keys.read` / `keys.write` -- manage project API keys
- `webhooks.read` / `webhooks.write` -- manage project webhooks
- `project.read` / `project.write` -- read and update project information

Comment on lines +21 to +27
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Incorrect scope pair count

The text says "Six new scope pairs" but the bullet list that follows enumerates exactly four pairs (platforms, keys, webhooks, project) — eight individual scopes in total. This matches the PR description ("8 new scopes") and the updated scopes table in the API keys docs, so the prose count is the error.

Suggested change
Six new scope pairs are now available for API keys:
- `platforms.read` / `platforms.write` -- manage project platforms
- `keys.read` / `keys.write` -- manage project API keys
- `webhooks.read` / `webhooks.write` -- manage project webhooks
- `project.read` / `project.write` -- read and update project information
Four new scope pairs are now available for API keys:

{% arrow_link href="/docs/advanced/platform/platforms" %}
Read the platforms docs
{% /arrow_link %}

{% arrow_link href="/docs/advanced/platform/api-keys" %}
Read the API keys docs
{% /arrow_link %}
5 changes: 5 additions & 0 deletions src/routes/docs/advanced/platform/+layout.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,11 @@
{
label: 'Dev keys',
href: '/docs/advanced/platform/dev-keys'
},
{
label: 'Platforms',
new: isNewUntil('10 Jul 2026'),
href: '/docs/advanced/platform/platforms'
}
]
},
Expand Down
4 changes: 4 additions & 0 deletions src/routes/docs/advanced/platform/+page.markdoc
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,10 @@ Create and manage API keys used by Server SDKs.
{% cards_item href="/docs/advanced/platform/dev-keys" title="Dev keys" %}
Create and manage dev keys used by Client SDKs in dev environments.
{% /cards_item %}

{% cards_item href="/docs/advanced/platform/platforms" title="Platforms" %}
Register and manage client platforms that can access your project.
{% /cards_item %}
{% /cards %}

# Plans {% #plans %}
Expand Down
64 changes: 63 additions & 1 deletion src/routes/docs/advanced/platform/api-keys/+page.markdoc
Original file line number Diff line number Diff line change
Expand Up @@ -148,9 +148,63 @@ let client = Client::new()
```
{% /multicode %}

When adding a new API Key, you can choose which [scopes](#scopes) to grant your application.
When adding a new API Key, you can choose which [scopes](#scopes) to grant your application.
If you need to replace your API Key, create a new key, update your app credentials and, once ready, delete your old key.

# Manage keys with the API {% #manage-keys-api %}

You can also create, list, update, and delete API keys programmatically using the project API. This is useful for automated key rotation, infrastructure-as-code workflows, or building custom admin tooling.

All key management endpoints require an API key with the `keys.read` or `keys.write` scope.

| Method | Endpoint | Scope |
|--------|---------------------------------|----------------|
| GET | `/v1/project/keys` | `keys.read` |
| POST | `/v1/project/keys` | `keys.write` |
| GET | `/v1/project/keys/:keyId` | `keys.read` |
| PUT | `/v1/project/keys/:keyId` | `keys.write` |
| DELETE | `/v1/project/keys/:keyId` | `keys.write` |

{% multicode %}
```server-nodejs
const sdk = require('node-appwrite');

const client = new sdk.Client()
.setEndpoint('https://<REGION>.cloud.appwrite.io/v1')
.setProject('<YOUR_PROJECT_ID>')
.setKey('<YOUR_API_KEY>'); // Must have keys.write scope

const project = new sdk.Project(client);

const key = await project.createKey(
sdk.ID.unique(), // keyId
'My Server Key', // name
['databases.read', 'databases.write'], // scopes
'2026-12-31T23:59:59.000+00:00' // expire (optional)
);
```

```server-python
from appwrite.client import Client
from appwrite.services.project import Project
from appwrite.id import ID

client = Client()
client.set_endpoint('https://<REGION>.cloud.appwrite.io/v1')
client.set_project('<YOUR_PROJECT_ID>')
client.set_key('<YOUR_API_KEY>') # Must have keys.write scope

project = Project(client)

key = project.create_key(
key_id=ID.unique(),
name='My Server Key',
scopes=['databases.read', 'databases.write'],
expire='2026-12-31T23:59:59.000+00:00' # optional
)
```
{% /multicode %}

# Scopes {% #scopes %}

| Name | Description |
Expand Down Expand Up @@ -204,3 +258,11 @@ If you need to replace your API Key, create a new key, update your app credentia
| `assistant.read` | Access to read the Assistant service |
| `tokens.read` | Access to read your project's tokens |
| `tokens.write` | Access to create, update, and delete your project's tokens |
| `webhooks.read` | Access to read your project's webhooks |
| `webhooks.write` | Access to create, update, and delete your project's webhooks |
| `project.read` | Access to read your project's information |
| `project.write` | Access to update your project's information |
| `keys.read` | Access to read your project's API keys |
| `keys.write` | Access to create, update, and delete your project's API keys |
| `platforms.read` | Access to read your project's platforms |
| `platforms.write` | Access to create, update, and delete your project's platforms |
165 changes: 165 additions & 0 deletions src/routes/docs/advanced/platform/platforms/+page.markdoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
---
layout: article
title: Platforms
description: Manage your project's client platforms programmatically using the Appwrite Platforms API. Register web, Apple, Android, Windows, and Linux platforms to control which client applications can access your project.
---

Platforms define which client applications are allowed to access your Appwrite project. Each platform registers an identifier (such as a hostname or bundle ID) that Appwrite uses to validate requests from client SDKs. You can manage platforms through the Console or programmatically through the API.

# Platform types {% #platform-types %}

Appwrite supports five platform types. Each type uses a different identifier to validate client requests.

| Type | Identifier | Example |
|-------------|--------------------------|------------------------------|
| `web` | Hostname | `example.com` |
| `apple` | Bundle identifier | `com.example.myapp` |
| `android` | Application ID | `com.example.myapp` |
| `windows` | Package identifier name | `com.example.myapp` |
| `linux` | Package name | `com.example.myapp` |

{% info title="Consolidated types" %}
Earlier versions of Appwrite used framework-specific platform types such as `flutter-ios`, `flutter-android`, `apple-macos`, and `react-native-ios`. These have been consolidated into the five types above. Existing platforms with deprecated types are mapped automatically. See [migration notes](#migration-notes) for details.
{% /info %}

# Endpoints {% #endpoints %}

The platforms API is available under `/v1/project/platforms`. All endpoints require an API key with the appropriate scope.

## Create a platform {% #create-platform %}

Create a platform by calling the endpoint for its type. Each type requires a unique identifier.

| Method | Endpoint | Scope |
|--------|----------------------------------------|---------------------|
| POST | `/v1/project/platforms/web` | `platforms.write` |
| POST | `/v1/project/platforms/apple` | `platforms.write` |
| POST | `/v1/project/platforms/android` | `platforms.write` |
| POST | `/v1/project/platforms/windows` | `platforms.write` |
| POST | `/v1/project/platforms/linux` | `platforms.write` |

{% multicode %}
```server-nodejs
const sdk = require('node-appwrite');

const client = new sdk.Client()
.setEndpoint('https://<REGION>.cloud.appwrite.io/v1')
.setProject('<YOUR_PROJECT_ID>')
.setKey('<YOUR_API_KEY>');

const project = new sdk.Project(client);

// Create a web platform
const platform = await project.createWebPlatform(
sdk.ID.unique(), // platformId
'My Website', // name
'example.com' // hostname
);
```

```server-python
from appwrite.client import Client
from appwrite.services.project import Project
from appwrite.id import ID

client = Client()
client.set_endpoint('https://<REGION>.cloud.appwrite.io/v1')
client.set_project('<YOUR_PROJECT_ID>')
client.set_key('<YOUR_API_KEY>')

project = Project(client)

# Create a web platform
platform = project.create_web_platform(
platform_id=ID.unique(),
name='My Website',
hostname='example.com'
)
```
{% /multicode %}

## List platforms {% #list-platforms %}

Retrieve all platforms registered in your project.

| Method | Endpoint | Scope |
|--------|-----------------------------|--------------------|
| GET | `/v1/project/platforms` | `platforms.read` |

{% multicode %}
```server-nodejs
const platforms = await project.listPlatforms();
```

```server-python
platforms = project.list_platforms()
```
{% /multicode %}

## Get a platform {% #get-platform %}

Retrieve a single platform by its ID.

| Method | Endpoint | Scope |
|--------|-----------------------------------------|--------------------|
| GET | `/v1/project/platforms/:platformId` | `platforms.read` |

## Update a platform {% #update-platform %}

Update a platform by calling the endpoint for its type.

| Method | Endpoint | Scope |
|--------|-------------------------------------------------|---------------------|
| PUT | `/v1/project/platforms/web/:platformId` | `platforms.write` |
| PUT | `/v1/project/platforms/apple/:platformId` | `platforms.write` |
| PUT | `/v1/project/platforms/android/:platformId` | `platforms.write` |
| PUT | `/v1/project/platforms/windows/:platformId` | `platforms.write` |
| PUT | `/v1/project/platforms/linux/:platformId` | `platforms.write` |

## Delete a platform {% #delete-platform %}

Delete a platform by its ID.

| Method | Endpoint | Scope |
|--------|-----------------------------------------|---------------------|
| DELETE | `/v1/project/platforms/:platformId` | `platforms.write` |

# Scopes {% #scopes %}

Two scopes control access to the platforms API.

| Scope | Description |
|--------------------|--------------------------------------------------------------------|
| `platforms.read` | Access to read your project's platforms |
| `platforms.write` | Access to create, update, and delete your project's platforms |

Assign these scopes when [creating an API key](/docs/advanced/platform/api-keys).

# Migration notes {% #migration-notes %}

In Appwrite 1.9.x, platform types were consolidated from ~15 framework-specific types into 5 general types. If your project has platforms created with older types, be aware of the following.

## Deprecated type mapping {% #deprecated-type-mapping %}

| Deprecated type | Maps to |
|-------------------------|-------------|
| `flutter-web` | `web` |
| `unity` | `web` |
| `flutter-ios` | `apple` |
| `flutter-macos` | `apple` |
| `apple-ios` | `apple` |
| `apple-macos` | `apple` |
| `apple-watchos` | `apple` |
| `apple-tvos` | `apple` |
| `react-native-ios` | `apple` |
| `flutter-android` | `android` |
| `react-native-android` | `android` |
| `flutter-windows` | `windows` |
| `flutter-linux` | `linux` |

## What you need to know {% #what-you-need-to-know %}

- **Reading**: When you list or get platforms, deprecated types are automatically returned as their new consolidated type. No action is needed on your part.
- **Creating**: New platforms must use one of the five current types (`web`, `apple`, `android`, `windows`, `linux`). The deprecated type names are not accepted for new platforms.
- **Existing platforms**: Platforms already registered with deprecated types continue to work. The mapping is applied transparently on read.
- **Client SDK validation**: Origin validation for client requests works the same regardless of whether the platform was created with a deprecated or current type.
Loading