A customer signs up to your platform and a project is created for them. Right now it is wide open: every authentication method is enabled, every service is exposed on the API, and nothing is constrained to the way you run things. Before that customer ever logs in, you want their project to match the baseline that every project on your platform shares.
The Project API lets you encode that baseline once and apply it from your backend or a CI step, so onboarding a customer is a script you run, not a checklist someone works through in the Console. The sections below follow that script in the order it runs:
- Register the customer's app.
- Narrow the sign-in methods to the ones they use.
- Close down the services and protocols they don't.
- Seed the variables their code expects.
Each call uses a Server SDK with an API key.
Required scopes
The API key used for these calls needs the project.write and platforms.write scopes. See API keys to create one.
Register the customer's app
Nothing can talk to a project until you register the apps allowed to reach it. Set up the client once, then register the customer's web app by its hostname, so requests from their domain are accepted and everything else is rejected.
import { Client, Project, ID } from 'node-appwrite';
const client = new Client()
.setEndpoint('https://<REGION>.cloud.appwrite.io/v1')
.setProject('<PROJECT_ID>')
.setKey('<YOUR_API_KEY>');
const project = new Project(client);
const result = await project.createWebPlatform({
platformId: ID.unique(),
name: 'Customer web app',
hostname: 'app.customer.example'
});
If the customer ships native apps too, register them the same way with createAndroidPlatform, createApplePlatform, createLinuxPlatform, or createWindowsPlatform. Each takes the identifier for that target, such as an Android application ID or an Apple bundle identifier.
Enable the required auth methods
A fresh project leaves every sign-in method enabled. Trim that down to the methods the customer's app offers, so you are not exposing flows they never built a UI for. If they sign their users in over SMS, turn phone authentication on.
const result = await project.updateAuthMethod({
methodId: ProjectAuthMethodId.Phone,
enabled: true
});
Pass enabled: false to switch a method off. The method ID is one of email-password, magic-url, email-otp, anonymous, invites, jwt, or phone.
Disable unused services and protocols
Every service the customer will never call is attack surface you can remove. If their app has no client-side Functions, take Functions off the client API to shrink that surface.
const result = await project.updateService({
serviceId: ProjectServiceId.Functions,
enabled: false
});
Server SDKs keep access
Disabling a service only removes it from the client-facing API. A Server SDK using an API key can still reach the service, including to turn it back on later, so your own backend keeps working while client apps lose the route.
Apply the same reasoning to API protocols. If nothing in the customer's stack speaks GraphQL, disable it and leave REST and Realtime in place.
const result = await project.updateProtocol({
protocolId: ProjectProtocolId.Graphql,
enabled: false
});
The protocol ID is one of rest, graphql, or websocket.
Seed project variables
The last step before the project is ready is to drop in the constants and secrets the customer's functions and sites read at build and runtime, so their first deploy finds everything it needs already in place.
const result = await project.createVariable({
variableId: ID.unique(),
key: 'TENANT_TIER',
value: 'pro',
secret: false // optional
});
Next steps
Wrap these calls in a single function keyed to the customer and every project you bring online starts identical, which is what keeps the next thousand projects manageable. With the baseline in place, the rest of the project's life uses the same Project API:
- Issue and rotate API keys for the integrations that run against the project.
- Brand its transactional emails so they come from the customer's domain.