Docs · Reference
Management REST API
Everything the console does, over HTTP. The 315 endpoints are read from the router (rest.ts) and the operations (operations.ts) and become this page and the OpenAPI document. This list is generated from the server code, so new features appear here as soon as they exist.
Getting started
Base URL
https://end.blackall.ai/api/v1
Authentication
Every request needs an Authorization: Bearer <token> header. The token is a bwk_… personal token made in the console under Account, API and MCP tokens, or the access token an MCP client received through OAuth.
curl https://end.blackall.ai/api/v1/me \
-H "Authorization: Bearer $ONEEND_TOKEN"
Scopes and roles
Tokens carry the read and write scopes. Endpoints that only read need read; anything that changes something needs write. A token has its owner’s role and no more, so a write token still gets a 403 where its owner’s role is not enough.
Language
Error messages and note follow ?lang=en, ?lang=ja or the Accept-Language header, and are Korean otherwise. The rest of a reply is data and does not change with the language.
Limits
Request bodies are accepted up to 256 KiB by default. Routes that take larger bodies, such as migrations and function deploys, list their own limit. This API has no per-token request rate limit. CORS is open to every origin.
OpenAPI 3.1
The same content as an OpenAPI 3.1 document, for code generators and Postman.
Download openapi.json · https://end.blackall.ai/docs/api/openapi.json
Status codes
A failure answers with one of the status codes below and {"error": {"message": "…"}}. The message is written for a person and says what to do next.
{ "error": { "message": "…" } }
A note, when present, is a sentence saying what to do next.
Account and regions
GET /api/v1/
API version Returns the name and version of this API. Useful to check that a token is accepted.
curl "https://end.blackall.ai/api/v1/" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/', {
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
GET /api/v1/me
My account Tells you whose token this is and what it may do. operator says whether the operator tools are open to it (active) and, when not, this account's reasons (refused: not_listed, token_bound, no_second_factor). Call it first when you are not sure where to start.
curl "https://end.blackall.ai/api/v1/me" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/me', {
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
GET /api/v1/regions
Regions Returns the regions. You can create a project now only where can_create is true; where it is false the region is being prepared and is listed, but cannot be chosen yet. A region is chosen once when a project is created and cannot be changed later, so check this before create_project.
curl "https://end.blackall.ai/api/v1/regions" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/regions', {
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
POST /api/v1/regions/requests
Request a region Records that you need a region that is not open yet (one where can_create is false). A person from our team will contact you. No date is promised. A region that is already open is not something to request: create the project there with create_project.
curl -X POST "https://end.blackall.ai/api/v1/regions/requests" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"region":"kr"}'
const response = await fetch('https://end.blackall.ai/api/v1/regions/requests', {
method: 'POST',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"region": "kr"
}),
})
const result = await response.json()
GET /api/v1/server-sizes
Server sizes and prices Each server size (memory) with its Google machine, CPUs and monthly price per region (monthly_minor). With no currency, the organisation's billing currency. KRW is in won with VAT included; USD is in cents with tax added at checkout. A size whose included_in is pro is included in the Pro plan. A region whose region_status is planned is coming soon and cannot be chosen. listed false means the sizes are not on sale yet and sizes is empty.
curl "https://end.blackall.ai/api/v1/server-sizes?region=kr¤cy=KRW" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/server-sizes?region=kr¤cy=KRW', {
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
GET /api/v1/imports/sources
Import sources The same as Import from another server in the console. For each source account connected to this organisation (Supabase, Vercel, PostgreSQL), its projects, and the imports so far. Accounts are connected in the console (connect_url), so a token is never pasted into a chat.
curl "https://end.blackall.ai/api/v1/imports/sources?org=value" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/imports/sources?org=value', {
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
POST /api/v1/imports
Start an import The same as [Start import] in the console. Starts an import split in the console (import), or a new one from import_sources' connection and project, split one new project per group. New projects are made; the source is never changed. A Supabase source needs its session pooler connection string in address, used for this run only and then deleted. Starting a stopped import again passes over finished destinations and moves only what changed. Owners, admins and developers only.
curl -X POST "https://end.blackall.ai/api/v1/imports?org=value" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{}'
const response = await fetch('https://end.blackall.ai/api/v1/imports?org=value', {
method: 'POST',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({}),
})
const result = await response.json()
GET /api/v1/imports/{id}
Import progress The same as the import progress page in the console. For each destination the state and counts of each step (schema, sign-in users, data, files, scheduled jobs...), what is not moved and why, and what is worth checking.
curl "https://end.blackall.ai/api/v1/imports/ID?org=value" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/imports/ID?org=value', {
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
Projects
GET /api/v1/projects
Projects Returns the projects on this account and the API address of each. status is ready (usable), provisioning (the database is being made, a few seconds), failed (retry_provisioning) or paused.
curl "https://end.blackall.ai/api/v1/projects" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects', {
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
POST /api/v1/projects
Create a project Creates a new project with a database, sign-in and file storage. Leave the region empty for the default region. The region cannot be changed after the project is created. The price is the same in every region. With several organizations, org chooses which one to create it in (only its owners, admins and developers can, within the number of projects its plan allows). The database is ready a few seconds later: when status is provisioning, pass wait (seconds) or use tables and keys once status in list_projects is ready.
curl -X POST "https://end.blackall.ai/api/v1/projects?wait=0" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"name":"my-name","region":"kr","org":"value","wait":0,"tier":"value"}'
const response = await fetch('https://end.blackall.ai/api/v1/projects?wait=0', {
method: 'POST',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"name": "my-name",
"region": "kr",
"org": "value",
"wait": 0,
"tier": "value"
}),
})
const result = await response.json()
GET /api/v1/projects/{ref}
One project Returns the one entry of the project list with this ref.
curl "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst', {
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
PATCH /api/v1/projects/{ref}
Rename Changes the project name, the organisation name, or both. The identifier (ref) and the addresses do not change. Only owners and admins can do this.
curl -X PATCH "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"name":"my-name","organisation":"My team"}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst', {
method: 'PATCH',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"name": "my-name",
"organisation": "My team"
}),
})
const result = await response.json()
POST /api/v1/projects/{ref}/pause
Pause a project Stops everything the project does: the site, API and functions return 503, realtime connections are refused, and scheduled jobs and new deployments stop. Data and files stay, and resume_project brings it straight back. Paused for over 90 days, the database moves to archive storage (get_project_archive). Only owners and admins can do this.
curl -X POST "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/pause" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/pause', {
method: 'POST',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
POST /api/v1/projects/{ref}/resume
Resume a project Starts a paused project again, including one the Free plan paused after 3 unused days (a new deployment also starts it). Scheduled jobs do not catch up on missed runs; they run from the next scheduled time.
curl -X POST "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/resume" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/resume', {
method: 'POST',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
GET /api/v1/projects/{ref}/archive
Database archive status A database that has been unusable for 90 days (a failed payment, the Free plan, a pause) is moved to archive storage. Returns where this project stands: state (none, scheduled, archiving, archived, restoring, purged), reason, archive_at (when it moves), purge_at (when the archive and the files are deleted, a year after the move), restore_blocked_by.
curl "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/archive" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/archive', {
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
POST /api/v1/projects/{ref}/archive/restore
Restore an archived database Makes the database in archive storage again, exactly as it was archived. Usually a few minutes; a paused project starts again with the restore. Refused while a payment is outstanding or on the Free plan (restore_blocked_by). If the archive was already deleted, creates a new, empty database. Owners and admins only.
curl -X POST "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/archive/restore" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/archive/restore', {
method: 'POST',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
POST /api/v1/projects/{ref}/archive/download
Archive download address Creates a signed address the archived database (pg_dump format; restore it with pg_restore) can be downloaded from for an hour. Needs a reason, which is kept in the access records. Owners and admins only.
curl -X POST "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/archive/download" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"reason":"value"}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/archive/download', {
method: 'POST',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"reason": "value"
}),
})
const result = await response.json()
DELETE /api/v1/projects/{ref}
Delete a project Permanently deletes the project's tables, users, files, functions, scheduled jobs, environment variables and domains. This cannot be undone. Use it only when the user clearly asks, and put the project name exactly in confirm. The last remaining project cannot be deleted. Only owners and admins can do this.
curl -X DELETE "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"confirm":"my-project"}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst', {
method: 'DELETE',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"confirm": "my-project"
}),
})
const result = await response.json()
POST /api/v1/projects/{ref}/retry-provisioning
Retry a project that failed to set up Sets up again a project whose database could not be created. Use it when another tool refuses with "could not create". Do not create a new project: this continues setting up the same one, and a new one only doubles the bill.
curl -X POST "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/retry-provisioning" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/retry-provisioning', {
method: 'POST',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
Keys and signing
GET /api/v1/projects/{ref}/keys
Get API keys Returns the project address and its two keys. The publishable key is for browsers. The secret key bypasses every access rule, so use it only on a server. Only a token with write access can call this. When you need values for frontend code, call it with only: "publishable": you get the address and the publishable key only, so the secret key never enters the conversation or the code (a read-only token can do this).
curl "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/keys?only=publishable" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/keys?only=publishable', {
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
GET /api/v1/projects/{ref}/api-keys
Named API keys The name, kind, prefix, last use and revoked state of each bw_publishable_ and bw_secret_ key made for a purpose. The value of a secret key is never returned. The value of a publishable key is.
curl "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/api-keys" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/api-keys', {
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
POST /api/v1/projects/{ref}/api-keys
Create an API key Creates one named key. publishable is for browsers (follows access rules); secret is for servers (bypasses access rules). The value of a secret key is in this response only and cannot be seen again. Only owners and admins can create keys, up to 20 per project.
curl -X POST "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/api-keys" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"kind":"publishable","name":"my-name"}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/api-keys', {
method: 'POST',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"kind": "publishable",
"name": "my-name"
}),
})
const result = await response.json()
DELETE /api/v1/projects/{ref}/api-keys/{id}
Revoke an API key Revokes one named key. Requests with that key are refused within 30 seconds. Other keys are not affected. This cannot be undone.
curl -X DELETE "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/api-keys/ID" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/api-keys/ID', {
method: 'DELETE',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
GET /api/v1/projects/{ref}/signing
Token signing Shows whether sign-in tokens are signed with HS256 or ES256, and the old keys still accepted for now (keys in their grace period).
curl "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/signing" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/signing', {
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
PUT /api/v1/projects/{ref}/signing
Change token signing With ES256, new sign-ins are signed with an asymmetric key and other servers can check tokens with the public keys (JWKS). Tokens already issued keep working until they expire. Only owners and admins can do this.
curl -X PUT "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/signing" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"alg":"HS256"}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/signing', {
method: 'PUT',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"alg": "HS256"
}),
})
const result = await response.json()
POST /api/v1/projects/{ref}/signing/rotate
Rotate the key Creates a new key for signing the publishable and secret keys. The old key is still accepted for grace_hours (0, 1, 24, 168); 0 (or empty) makes it invalid at once (when it leaked). With 0 every app using it stops within 30 seconds, so put the project name (name from list_projects) exactly in confirm. Every key put in an app has to be replaced, so use this only when the user clearly asks. Only owners and admins can do this.
curl -X POST "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/signing/rotate" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"grace_hours":0,"confirm":"my-project"}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/signing/rotate', {
method: 'POST',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"grace_hours": 0,
"confirm": "my-project"
}),
})
const result = await response.json()
DELETE /api/v1/projects/{ref}/signing/keys/{kid}
Retire an old key Ends an old key in its grace period now. kid is one in the keys of get_jwt_signing whose state is rotating. Only owners and admins can do this.
curl -X DELETE "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/signing/keys/KEY_ID" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/signing/keys/KEY_ID', {
method: 'DELETE',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
Database
GET /api/v1/projects/{ref}/advisors
Security and performance check Looks for security and performance problems in the project's database structure: tables with RLS off, rules that let anyone write, views that bypass access rules, security definer functions with no fixed search_path, views that expose the users table, foreign keys with no index, tables with no primary key, duplicate indexes, and rules that call uid() for every row. Where there is SQL that fixes an item (remedy), it is included. No data is read. Call this after creating tables or changing rules.
curl "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/advisors" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/advisors', {
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
GET /api/v1/projects/{ref}/tables/{table}/csv
Export a table as CSV Returns a table's rows as CSV (the first line holds the column names), as the console table editor's export does. Up to 1MB comes back; past that it is cut at a whole row and truncated is true. Then split the range with filters and fetch it in several calls. An empty field is NULL and "" is an empty string.
curl "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/tables/notes/csv?sort=value&desc=true" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/tables/notes/csv?sort=value&desc=true', {
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
POST /api/v1/projects/{ref}/tables/{table}/csv
Import CSV into a table Puts CSV rows into a table, as the console table editor's import does. The first line names the columns, and each goes into the column of the same name (columns changes that). If any row cannot go in, nothing goes in, and the line numbers and reasons come back. Up to 2MB and 10,000 rows. An unquoted empty field is NULL or the column's default. Split anything larger into several calls.
curl -X POST "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/tables/notes/csv" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"csv":"value"}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/tables/notes/csv', {
method: 'POST',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"csv": "value"
}),
})
const result = await response.json()
GET /api/v1/projects/{ref}/tables
Tables Returns the project's tables with their columns, an approximate row count and the state of their access rules. If rules are on and there are none, the publishable key sees nothing.
curl "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/tables" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/tables', {
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
GET /api/v1/projects/{ref}/policies
Access rules Returns which action on which table is open to whom.
curl "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/policies" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/policies', {
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
GET /api/v1/projects/{ref}/rows/{table}
Read a table Reads the first rows of a table as they are. For checking; when you need conditions, use run_sql.
curl "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/rows/notes?limit=1" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/rows/notes?limit=1', {
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
GET /api/v1/projects/{ref}/migrations
Migration history Returns the version, name and time applied of each migration applied with apply_migrations, oldest first. The record is kept in the project's oneend_migrations table.
curl "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/migrations" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/migrations', {
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
POST /api/v1/projects/{ref}/migrations
Apply migrations Runs the migrations not yet applied, in version order, each in a transaction of its own, and records them. Versions already applied are skipped. If one fails, only that one is rolled back and applying stops; the ones before it stay applied. Use this instead of run_sql when changing the schema, and you can apply the same changes to other projects exactly as they are. Files from supabase/migrations can be sent as they are: Supabase names such as public., auth.uid(), storage. and to authenticated are run in this project's names and reported in translated (Supabase name translation). The ledger keeps each file as written.
curl -X POST "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/migrations" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"migrations":[{"version":"20260101000000","name":"my-name","sql":"select 1"}]}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/migrations', {
method: 'POST',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"migrations": [
{
"version": "20260101000000",
"name": "my-name",
"sql": "select 1"
}
]
}),
})
const result = await response.json()
DELETE /api/v1/projects/{ref}/migrations/{version}
Remove a migration record Marks one migration as not applied. Only the record is removed; what the migration made is left as it is.
curl -X DELETE "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/migrations/20260101000000" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/migrations/20260101000000', {
method: 'DELETE',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
GET /api/v1/projects/{ref}/schema
The schema as SQL Returns the project's schema (types, sequences, tables and constraints, foreign keys, indexes, functions, views, triggers, RLS and rules) as SQL that builds it again. Row data and privileges are not included.
curl "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/schema" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/schema', {
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
GET /api/v1/projects/{ref}/types/typescript
Generate TypeScript types Makes the Database type for supabase-js's createClient<Database>() from the project's tables, views, functions and enums. Call it again after changing the schema.
curl "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/types/typescript?schema=value" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/types/typescript?schema=value', {
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
POST /api/v1/projects/{ref}/sql/query
Query SQL (read-only) Runs one query (SELECT and the like) on the project's PostgreSQL database in a read-only transaction and returns the rows. A statement that changes data or structure is refused; use run_sql for that. A read-only token can call it. It does not open Vault secrets (decrypted_secret in vault.decrypted_secrets is empty). SQL follows the PostgreSQL 16 documentation (https://www.postgresql.org/docs/16/sql-commands.html).
curl -X POST "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/sql/query" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"sql":"select 1"}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/sql/query', {
method: 'POST',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"sql": "select 1"
}),
})
const result = await response.json()
POST /api/v1/projects/{ref}/sql
Run SQL (changes) Runs SQL that changes data or structure (CREATE, INSERT, UPDATE, DELETE and so on) on the project's PostgreSQL database and returns the resulting rows. For reading only, use query_sql. SQL follows the PostgreSQL 16 documentation (https://www.postgresql.org/docs/16/sql-commands.html). A new table gets access rules turned on automatically, so unless you then create rules, the publishable key sees nothing. The role names to use in rules are <ref>_anon, <ref>_authenticated and <ref>_service_role. SQL written for Supabase (public., auth.uid(), storage., to authenticated) is run in this project's names, and translated says what was replaced (Supabase name translation).
curl -X POST "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/sql" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"sql":"select 1"}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/sql', {
method: 'POST',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"sql": "select 1"
}),
})
const result = await response.json()
GET /api/v1/projects/{ref}/database
Database connection details Shows the addresses for connecting directly to this project's PostgreSQL: direct (5432, session: migration tools and database clients) and pooler (6543, transaction: serverless). The password is not stored, so it appears as [YOUR-PASSWORD].
curl "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/database" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/database', {
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
POST /api/v1/projects/{ref}/database/password
New database password Creates a new password for direct connections and returns it once. Anything connecting with the old password is refused from its next connection: servers, jobs and tools connected with it now break when they reconnect, so put the project name (name from list_projects) exactly in confirm.This user bypasses row level security, so keep it on servers only. With keep_for_deploys: true the password is also kept sealed, and production servers, middleware and functions get DATABASE_URL, POSTGRES_URL and DIRECT_URL at runtime (never builds). Deployed code can then read every row, like the secret key, so turn it on only when the user wants it. A reset without it stops the handover. Use this only when the user asks. Only owners and admins can do this.
curl -X POST "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/database/password" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"confirm":"my-project"}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/database/password', {
method: 'POST',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"confirm": "my-project"
}),
})
const result = await response.json()
GET /api/v1/projects/{ref}/mysql
List MySQL databases Returns this project's MySQL databases (MariaDB 11.4), which app each goes to (app; null is the whole project), their status and size, and how many the plan allows (max). available false means this server has no MySQL yet.
curl "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/mysql" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/mysql', {
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
POST /api/v1/projects/{ref}/mysql
Create a MySQL database Creates a database and its own login for an app that uses MySQL, such as WordPress. Usually ready within a minute. With app, only that app's deployments get it; without, every app of the project does (while it is the project's only one). That app's servers start with MYSQL_URL, MYSQL_HOST, MYSQL_PORT, MYSQL_USER, MYSQL_PASSWORD, MYSQL_DATABASE and WORDPRESS_DB_HOST, WORDPRESS_DB_USER, WORDPRESS_DB_PASSWORD, WORDPRESS_DB_NAME (never in a build). Backed up every night.
curl -X POST "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/mysql" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"name":"my-name"}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/mysql', {
method: 'POST',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"name": "my-name"
}),
})
const result = await response.json()
PATCH /api/v1/projects/{ref}/mysql/{name}
Connect a MySQL database to an app Changes which app gets a MySQL database. app null makes it the whole project's. One app has at most one database. Running servers get the change when they restart or are deployed again.
curl -X PATCH "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/mysql/my-name" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"app":"owner/repo"}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/mysql/my-name', {
method: 'PATCH',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"app": "owner/repo"
}),
})
const result = await response.json()
DELETE /api/v1/projects/{ref}/mysql/{name}
Delete a MySQL database Deletes a MySQL database with its login and every backup. This cannot be undone: use it only when the user clearly asked, and put the database name exactly in confirm. The app that got it no longer gets MYSQL_* variables from its next start. Only owners and admins can do this.
curl -X DELETE "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/mysql/my-name" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"confirm":"my-project"}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/mysql/my-name', {
method: 'DELETE',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"confirm": "my-project"
}),
})
const result = await response.json()
GET /api/v1/projects/{ref}/mysql/{name}/connection
MySQL connection Returns a MySQL database's address, port, database name, login, password and the variables its app gets (variables). The address is reachable only from apps on this server. The password is shown to a write token only.
curl "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/mysql/my-name/connection" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/mysql/my-name/connection', {
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
GET /api/v1/projects/{ref}/mysql/{name}/backups
List MySQL backups Returns a MySQL database's backups (nightly, made by hand, and taken just before a restore) and its restores.
curl "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/mysql/my-name/backups" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/mysql/my-name/backups', {
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
POST /api/v1/projects/{ref}/mysql/{name}/backups
Back up MySQL now Backs up a MySQL database now. Make one before updating plugins or changing a lot at once. Kept for 7 days. The nightly backup happens on its own as well.
curl -X POST "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/mysql/my-name/backups" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/mysql/my-name/backups', {
method: 'POST',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
POST /api/v1/projects/{ref}/mysql/{name}/restore
Restore MySQL from a backup Puts a MySQL database back to when a backup was taken. Every change since is lost, so use it only when the user clearly asked, and put the database name exactly in confirm. The state just before is backed up first, so undo_backup_id restores it again. Only owners and admins can do this.
curl -X POST "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/mysql/my-name/restore" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"backup_id":"BACKUP_ID","confirm":"my-project"}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/mysql/my-name/restore', {
method: 'POST',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"backup_id": "BACKUP_ID",
"confirm": "my-project"
}),
})
const result = await response.json()
GET /api/v1/projects/{ref}/extensions
Database extensions The PostgreSQL extensions you can turn on (vector from pgvector, postgis, citext, pgcrypto and others), and for each whether this server has it (available), whether it is on (enabled), and its version. Extensions are installed in the extensions schema and used in SQL just as vector(1536) or geometry.
curl "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/extensions" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/extensions', {
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
PUT /api/v1/projects/{ref}/extensions/{name}
Turn on a database extension Turns on one extension (create extension ... with schema extensions). vector for embedding search, postgis for maps and distances. Extensions not on the list are refused. Only owners and admins can do this.
curl -X PUT "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/extensions/my-name" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/extensions/my-name', {
method: 'PUT',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
DELETE /api/v1/projects/{ref}/extensions/{name}
Turn off a database extension Turns off one extension. Refused while columns, indexes or functions that use it remain. If another project on the same database uses it, it stays installed and only this project's record is removed (note). pg_trgm and unaccent are built in and cannot be turned off. Put the extension name exactly in confirm. Only owners and admins can do this.
curl -X DELETE "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/extensions/my-name" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"confirm":"my-project"}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/extensions/my-name', {
method: 'DELETE',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"confirm": "my-project"
}),
})
const result = await response.json()
GET /api/v1/projects/{ref}/database/move
Move to a dedicated database: status Whether this project is on a dedicated database (dedicated), whether its plan includes one (plan_allows), and whether a move was requested, is under way or failed and stopped (stopped, last_error). When size_bytes is above auto_move_max_bytes the project is not moved automatically; request it with move_to_dedicated_database.
curl "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/database/move" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/database/move', {
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
POST /api/v1/projects/{ref}/database/move
Move to a dedicated database Requests the move of a project on the shared database to a database of its own, as the console's "Move now" does. It moves when its turn comes; writes pause during the move and reads carry on. The project as it was just before is kept as a backup, and if the move fails the project stays where it was (a stopped move is tried again when requested again). Needed for Vault and for large databases. Included from the Pro plan. Only owners and admins can do this.
curl -X POST "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/database/move" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/database/move', {
method: 'POST',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
GET /api/v1/projects/{ref}/database/dedicated-disk
Dedicated disk The disk and Postgres of this project's own, used once its database has grown: its size (size_gb), what is used, the monthly cost, 30 days of history, a request in progress and the suggestion to make it smaller (shrink). While the project is on the shared disk, the size that moves it (threshold_gb) and the database's size now.
curl "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/database/dedicated-disk" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/database/dedicated-disk', {
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
POST /api/v1/projects/{ref}/database/dedicated-disk
Move to a dedicated disk Requests the move of this project's database to a disk of its own (max(1.2 x the database, 20 GB)), as the console's "Move to a dedicated disk" does. The disk is billed on its provisioned size at KRW 1,200 (75 cents) per GB a month, and while it moves writes fail and reads work (expected_downtime_seconds in get_dedicated_disk). Enterprise may ask at any time; other paid plans once past the threshold. Only owners and admins can do this.
curl -X POST "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/database/dedicated-disk" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/database/dedicated-disk', {
method: 'POST',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
POST /api/v1/projects/{ref}/database/dedicated-disk/shrink
Make the disk smaller Makes the dedicated disk smaller: a new, smaller disk (1.2 x the database, at least 20 GB) is made, the data moves onto it and the old disk is deleted. Only a disk under 25% used for 7 days can be made smaller (shrink.suggested in get_dedicated_disk). While it moves writes fail and reads work. It is never made smaller on its own. Only owners and admins can do this.
curl -X POST "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/database/dedicated-disk/shrink" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/database/dedicated-disk/shrink', {
method: 'POST',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
GET /api/v1/projects/{ref}/realtime
Tables with realtime on The tables whose changes are sent in real time. Subscribing to a table not listed here receives nothing.
curl "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/realtime" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/realtime', {
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
PUT /api/v1/projects/{ref}/realtime/{table}
Turn realtime on or off for a table Turns change notifications for one table on or off. Notifications also go only for rows that pass the access rules.
curl -X PUT "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/realtime/notes" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"enabled":true}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/realtime/notes', {
method: 'PUT',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"enabled": true
}),
})
const result = await response.json()
Auth and users
GET /api/v1/projects/{ref}/users
The service's users The users who signed up to the service that uses this project. They are separate from platform accounts. Up to 200 come at a time, and total gives the full count. When has_more is true there are more, so call again with a higher offset. Using the length of users as the head count is wrong.
curl "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/users?limit=1&offset=0" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/users?limit=1&offset=0', {
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
POST /api/v1/projects/{ref}/users/{id}/links
Make a sign-in link Makes the link a sign-in mail would carry and returns it instead of mailing it: invite (creates the user when there is none), magiclink (sign-in without a password), recovery (a password reset) or signup (confirms a new sign-up; needs password). Whoever opens action_link is signed in as that user, so it is as good as a password. Make one only when the user clearly asks, and give it only to that person. redirect_to must be an address added with add_redirect_url. Only roles that can see the secret key (owner, admin, developer) can do this.
curl -X POST "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/users/ID/links" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"type":"invite"}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/users/ID/links', {
method: 'POST',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"type": "invite"
}),
})
const result = await response.json()
PATCH /api/v1/projects/{ref}/users/{id}
Change a user Changes one of this project's users: the email, the password, whether the email is confirmed, a ban and its end, and the metadata. Only what you give changes. A new password or a ban signs the person out everywhere. A password needs at least 10 characters, and one known from a breach is refused. Metadata is merged into what is there. Use it only when the user clearly asks.
curl -X PATCH "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/users/ID" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"email":"[email protected]","password":"a-long-passphrase","email_confirm":true,"ban_duration":"value","user_metadata":{},"app_metadata":{}}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/users/ID', {
method: 'PATCH',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"email": "[email protected]",
"password": "a-long-passphrase",
"email_confirm": true,
"ban_duration": "value",
"user_metadata": {},
"app_metadata": {}
}),
})
const result = await response.json()
POST /api/v1/projects/{ref}/users/import
Import users Imports up to 500 users at once from another service (for example a Supabase auth.users export). Ids and bcrypt password hashes are kept, so nobody has to choose a new password. The whole list is checked first: a wrong row is named by number and nothing is imported. An account that already exists is skipped, so repeating a call is safe. dry_run=true only checks.
curl -X POST "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/users/import" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"users":[{"email":"[email protected]","id":"ID","encrypted_password":"value","email_confirmed":"value","user_metadata":"value","app_metadata":"value"}]}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/users/import', {
method: 'POST',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"users": [
{
"email": "[email protected]",
"id": "ID",
"encrypted_password": "value",
"email_confirmed": "value",
"user_metadata": "value",
"app_metadata": "value"
}
]
}),
})
const result = await response.json()
POST /api/v1/projects/{ref}/users
Add a user Creates one user in this project's service. The password must be at least 10 characters.
curl -X POST "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/users" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"email":"[email protected]","password":"a-long-passphrase"}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/users', {
method: 'POST',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"email": "[email protected]",
"password": "a-long-passphrase"
}),
})
const result = await response.json()
GET /api/v1/projects/{ref}/auth/providers
Social sign-in settings Shows which accounts people can use to sign in to this project's service. Every provider the platform supports is returned, so ones not set up yet show configured: false. Providers you registered yourself (custom:<name>) follow, with a custom entry (addresses, scopes, answer field mapping). callback_url is the address to paste as it is into the provider's console.
curl "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/auth/providers" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/auth/providers', {
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
PUT /api/v1/projects/{ref}/auth/providers/{provider}
Turn on social sign-in Saves and turns on one provider's client ID and secret. The secret is sealed and cannot be read back; only its last four characters can be checked. First create an app in the provider's console and register the callback_url from list_auth_providers as its redirect address. To change only the ID of a provider already saved, leave client_secret as an empty string. As on Supabase, a provider of custom:<name> registers an OAuth 2.0 or OpenID Connect provider the platform does not list (for example custom:kakao-xts). It then needs issuer (for OpenID Connect this alone fills in the addresses) or authorize_url and token_url (and userinfo_url), and may take scopes and claims (which field of the answer is id, email, email_verified, name, avatar and phone, as dotted paths). Your app signs in with signInWithOAuth({ provider: "custom:<name>" }), and right after sign-in the session carries provider_token, once.
curl -X PUT "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/auth/providers/google" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"client_id":"CLIENT_ID","client_secret":"CLIENT_SECRET","enabled":true}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/auth/providers/google', {
method: 'PUT',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"client_id": "CLIENT_ID",
"client_secret": "CLIENT_SECRET",
"enabled": true
}),
})
const result = await response.json()
PATCH /api/v1/projects/{ref}/auth/providers/{provider}
Turn social sign-in off and on Turns a provider off or on and keeps its saved credentials. Use it while finding out why a provider misbehaves; turning it back on needs no new secret.
curl -X PATCH "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/auth/providers/google" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"enabled":true}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/auth/providers/google', {
method: 'PATCH',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"enabled": true
}),
})
const result = await response.json()
DELETE /api/v1/projects/{ref}/auth/providers/{provider}
Remove social sign-in Removes a provider's settings along with its credentials. To turn it off for a while, use set_auth_provider_enabled. After removing it this way, you have to get the secret again.
curl -X DELETE "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/auth/providers/google" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/auth/providers/google', {
method: 'DELETE',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
GET /api/v1/projects/{ref}/auth/redirect-urls
Addresses to return to after sign-in The addresses a person can be sent back to after signing in. Nobody is sent to an address not listed here. If sign-in works but goes nowhere, look here first.
curl "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/auth/redirect-urls" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/auth/redirect-urls', {
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
POST /api/v1/projects/{ref}/auth/redirect-urls
Add an address to return to Adds one address to the allow list. Scheme, host and port must all match and the path is not checked, so adding https://app.example.com/callback stores https://app.example.com. A mobile app’s own scheme is accepted too (co.example.app://callback, stored as co.example.app://callback): reverse-DNS, so it has a dot. The response holds the list as actually stored.
curl -X POST "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/auth/redirect-urls" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"url":"https://example.com/hook"}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/auth/redirect-urls', {
method: 'POST',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"url": "https://example.com/hook"
}),
})
const result = await response.json()
DELETE /api/v1/projects/{ref}/auth/redirect-urls
Remove an address to return to Takes one address off the allow list. Give it exactly as list_redirect_urls returned it.
curl -X DELETE "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/auth/redirect-urls" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"url":"https://example.com/hook"}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/auth/redirect-urls', {
method: 'DELETE',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"url": "https://example.com/hook"
}),
})
const result = await response.json()
GET /api/v1/projects/{ref}/auth/sms
SMS sign-in settings Shows the SMS account used for phone sign-in (signInWithOtp({ phone })): the provider (platform, solapi, nhn, aligo, twilio), the sender number, the country codes it may send to, the code length and lifetime, and the hourly limit. Credentials show only their last four characters. platform_available has to be true to choose the platform account (₩100 a message, Korea only).
curl "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/auth/sms" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/auth/sms', {
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
PUT /api/v1/projects/{ref}/auth/sms
Set up SMS sign-in Saves the SMS account and turns it on. Your own provider needs key, secret and account (they differ by provider: Solapi takes API Key and API Secret, NHN Cloud App Key and Secret Key, Aligo API Key and User ID as account, Twilio and Twilio Verify Account SID as account and Auth Token as secret, MessageBird Access Key as key, Textlocal API Key as key, Vonage API Key as key and API Secret as secret) and a sender registered with it (MessageBird, Textlocal and Vonage also take an alphanumeric sender ID of up to 11 characters; Twilio Verify takes its Verify Service SID, starting VA). Phone confirmations, test numbers and the rest are SMS_* keys of update_auth_config. Credentials left empty keep the stored ones. allowed_countries is only 82 (Korea) by default; adding countries you do not serve exposes you to fraud that makes you text premium-rate numbers abroad.
curl -X PUT "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/auth/sms" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"provider":"platform"}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/auth/sms', {
method: 'PUT',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"provider": "platform"
}),
})
const result = await response.json()
DELETE /api/v1/projects/{ref}/auth/sms
Remove SMS sign-in Removes the SMS account settings along with the credentials. Phone sign-in is then refused with phone_provider_disabled. To turn it off for a while, call set_sms_settings with enabled: false.
curl -X DELETE "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/auth/sms" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/auth/sms', {
method: 'DELETE',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
GET /api/v1/projects/{ref}/auth/smtp
SMTP settings Shows the SMTP server and sender this project's auth emails (sign-up confirmation, password reset, sign-in link, email change, invitation) go out through: the same fields as Supabase's SMTP Settings. The password is never shown; password_hint has its last four characters (when it has at least 8). A last_error means that server refused and the email went out from the platform's address instead. configured false means the platform's address is used.
curl "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/auth/smtp" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/auth/smtp', {
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
PUT /api/v1/projects/{ref}/auth/smtp
Set SMTP settings Sends auth emails through this project's SMTP server, with the sender name and address you choose. The first time it needs sender_email, host, username and password; after that, only what changes (an empty password keeps the stored one). The server has to be on a public address and use TLS (from the start on 465, STARTTLS otherwise). If it refuses, the email goes out from the platform's address and the reason is kept in last_error. Check it with test_smtp_settings after saving.
curl -X PUT "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/auth/smtp" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"sender_email":"value","sender_name":"value","host":"value","port":25,"username":"value","password":"a-long-passphrase","minimum_interval_seconds":0,"rate_limit_per_hour":1,"enabled":true}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/auth/smtp', {
method: 'PUT',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"sender_email": "value",
"sender_name": "value",
"host": "value",
"port": 25,
"username": "value",
"password": "a-long-passphrase",
"minimum_interval_seconds": 0,
"rate_limit_per_hour": 1,
"enabled": true
}),
})
const result = await response.json()
DELETE /api/v1/projects/{ref}/auth/smtp
Remove SMTP settings Removes the SMTP settings along with the password. Auth emails then go out from the platform's address. To pause them, call set_smtp_settings with enabled: false.
curl -X DELETE "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/auth/smtp" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/auth/smtp', {
method: 'DELETE',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
POST /api/v1/projects/{ref}/auth/smtp/test
Send an SMTP test email Sends one test email through the saved SMTP server. It does not fall back to the platform, so a failure gives the server's own reason. Without to, it goes to the caller's address.
curl -X POST "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/auth/smtp/test" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"to":"https://example.com"}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/auth/smtp/test', {
method: 'POST',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"to": "https://example.com"
}),
})
const result = await response.json()
GET /api/v1/projects/{ref}/auth/templates
Email templates The subject and HTML body of the six auth emails (confirmation, invite, magic_link, recovery, email_change, reauthentication). A type with custom false uses the default wording, in Korean, English or Japanese to match the request. Give type to see just one. The variables are the same as Supabase: {{ .ConfirmationURL }}, {{ .Token }}, {{ .TokenHash }}, {{ .SiteURL }}, {{ .Email }}, {{ .NewEmail }}, {{ .RedirectTo }}, {{ .Data.<key> }}.
curl "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/auth/templates" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/auth/templates', {
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
GET /api/v1/projects/{ref}/auth/templates/{type}
Email templates The subject and HTML body of the six auth emails (confirmation, invite, magic_link, recovery, email_change, reauthentication). A type with custom false uses the default wording, in Korean, English or Japanese to match the request. Give type to see just one. The variables are the same as Supabase: {{ .ConfirmationURL }}, {{ .Token }}, {{ .TokenHash }}, {{ .SiteURL }}, {{ .Email }}, {{ .NewEmail }}, {{ .RedirectTo }}, {{ .Data.<key> }}.
curl "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/auth/templates/confirmation" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/auth/templates/confirmation', {
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
PUT /api/v1/projects/{ref}/auth/templates/{type}
Save an email template Sets the subject and HTML body of one type. Templates copied from Supabase work as they are. Values are HTML-escaped, and the subject has to be one line. Other syntax such as {{ if }} is refused. reauthentication is stored but not sent yet (reauthenticate is not supported). Check it with preview_email_template before saving.
curl -X PUT "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/auth/templates/confirmation" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"subject":"value","body":"value"}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/auth/templates/confirmation', {
method: 'PUT',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"subject": "value",
"body": "value"
}),
})
const result = await response.json()
DELETE /api/v1/projects/{ref}/auth/templates/{type}
Restore an email template Removes the template of one type, which goes back to the default wording (Korean, English and Japanese).
curl -X DELETE "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/auth/templates/confirmation" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/auth/templates/confirmation', {
method: 'DELETE',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
POST /api/v1/projects/{ref}/auth/templates/{type}/preview
Preview an email template Returns how the email looks with sample values (subject, HTML and text). With subject and body it shows those without saving; without them, the saved template or the default wording.
curl -X POST "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/auth/templates/confirmation/preview" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"subject":"value","body":"value"}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/auth/templates/confirmation/preview', {
method: 'POST',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"subject": "value",
"body": "value"
}),
})
const result = await response.json()
GET /api/v1/projects/{ref}/auth/sso
SAML SSO Shows the SAML IdPs registered for this project with their email domains, and the two addresses to enter in the IdP (acs_url, entity_id). The app signs in with supabase.auth.signInWithSSO({ domain }).
curl "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/auth/sso" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/auth/sso', {
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
DELETE /api/v1/projects/{ref}/auth/sso/{id}
Remove SAML SSO Removes one IdP. Accounts made through it remain, but can no longer sign in through SSO.
curl -X DELETE "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/auth/sso/ID" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/auth/sso/ID', {
method: 'DELETE',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
PUT /api/v1/projects/{ref}/auth/anonymous
Turn anonymous sign-in on or off Turns on or off anonymous sign-in, which gives a session straight away without an email. The current state is anonymous_sign_in in list_auth_providers.
curl -X PUT "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/auth/anonymous" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"enabled":true}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/auth/anonymous', {
method: 'PUT',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"enabled": true
}),
})
const result = await response.json()
DELETE /api/v1/projects/{ref}/users/{id}
Remove a user Removes one of the project's users. This cannot be undone. id is the value list_users returned. Use it only when the user clearly asks, and put that user's email (or id) exactly in confirm.
curl -X DELETE "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/users/ID" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"confirm":"my-project"}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/users/ID', {
method: 'DELETE',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"confirm": "my-project"
}),
})
const result = await response.json()
Storage
POST /api/v1/projects/{ref}/buckets/{bucket}/empty
Empty a bucket Deletes every file in a bucket and keeps the bucket. It cannot be undone, so use it only when the user clearly asks, and put the bucket name exactly in confirm. removed is the number of files deleted.
curl -X POST "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/buckets/value/empty" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"confirm":"my-project"}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/buckets/value/empty', {
method: 'POST',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"confirm": "my-project"
}),
})
const result = await response.json()
GET /api/v1/projects/{ref}/buckets/{bucket}/objects
Files Lists one folder of a bucket: its subfolders and files with name, size and type. Choose the folder with prefix (for example avatars/2024/) and find names with search.
curl "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/buckets/value/objects?prefix=value&search=value" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/buckets/value/objects?prefix=value&search=value', {
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
POST /api/v1/projects/{ref}/buckets/{bucket}/objects
Upload a file Uploads one file to a bucket (up to 2MB). Text goes as it is; for binary set encoding to base64 and put base64 in content. A file with the same name is refused, unless upsert is true, which replaces it. The bucket's size and type limits apply. Upload bigger files through the storage API (/storage/v1).
curl -X POST "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/buckets/value/objects" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"content":"value","name":"my-name"}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/buckets/value/objects', {
method: 'POST',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"content": "value",
"name": "my-name"
}),
})
const result = await response.json()
GET /api/v1/projects/{ref}/buckets/{bucket}/object
Download a file Returns the content of one file (up to 2MB): text as utf-8, binary as base64. For bigger files make an address with create_signed_url.
curl "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/buckets/value/object?name=my-name&encoding=utf-8" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/buckets/value/object?name=my-name&encoding=utf-8', {
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
DELETE /api/v1/projects/{ref}/buckets/{bucket}/object
Delete a file Removes one file from a bucket. This cannot be undone.
curl -X DELETE "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/buckets/value/object?name=my-name" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/buckets/value/object?name=my-name', {
method: 'DELETE',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
POST /api/v1/projects/{ref}/buckets/{bucket}/upload-urls
Make an upload URL Makes a URL to upload one file larger than 2MB, such as an image or a video. The file itself is not sent through this tool. PUT the file bytes as the body to the returned url, with its type (image/png, video/mp4 and so on) as content-type, as in the curl of example. The URL works for that one name for 2 hours. A file larger than max_bytes, or of a type not in allowed_mime_types, is refused; for a file larger than max_bytes use the resumable (TUS) upload in blackwall://storage. For a public bucket, public_url is its public address once uploaded.
curl -X POST "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/buckets/value/upload-urls" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"name":"my-name"}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/buckets/value/upload-urls', {
method: 'POST',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"name": "my-name"
}),
})
const result = await response.json()
POST /api/v1/projects/{ref}/buckets/{bucket}/signed-urls
Create a signed URL Makes an address anyone can download one file of a private bucket from for a set time (1 hour by default, 7 days at most). Whoever has the address downloads without signing in, so make only what you need.
curl -X POST "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/buckets/value/signed-urls" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"name":"my-name"}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/buckets/value/signed-urls', {
method: 'POST',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"name": "my-name"
}),
})
const result = await response.json()
PATCH /api/v1/projects/{ref}/buckets/{bucket}
Change bucket settings Changes whether a bucket is public, the largest one file may be, and the types it takes. Only what you give changes. Making it public lets anyone download its files, so do it only when the user clearly asks. Files already there stay as they are.
curl -X PATCH "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/buckets/value" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"public":true}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/buckets/value', {
method: 'PATCH',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"public": true
}),
})
const result = await response.json()
DELETE /api/v1/projects/{ref}/buckets/{bucket}
Delete a bucket Deletes an empty bucket. One that still holds files is refused, so empty it first with empty_bucket. It cannot be undone. Use it only when the user clearly asks, and put the bucket name exactly in confirm.
curl -X DELETE "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/buckets/value" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"confirm":"my-project"}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/buckets/value', {
method: 'DELETE',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"confirm": "my-project"
}),
})
const result = await response.json()
GET /api/v1/projects/{ref}/buckets
Buckets Returns the storage buckets with the number of files and the size of each.
curl "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/buckets" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/buckets', {
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
POST /api/v1/projects/{ref}/buckets
Create a bucket Anyone can read a public bucket. Only the uploader can read a private bucket. file_size_limit and allowed_mime_types set the largest file and the types it takes from the start (later, with update_bucket).
curl -X POST "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/buckets" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"id":"ID"}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/buckets', {
method: 'POST',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"id": "ID"
}),
})
const result = await response.json()
Deployments and repositories
POST /api/v1/projects/{ref}/deployments/sources/upload-urls
Make an upload URL for a deployment archive For deploying a site too large for deploy_files (over 3MB) without a repository: makes a URL to upload one archive (.zip, .tar, .tar.gz) to. The archive itself is not sent through this tool. PUT the archive as the body to the returned url (as in the curl of example, with no token); the answer carries source, and deploy_source with that source deploys it. The URL works for this project for 1 hour and takes up to max_bytes.
curl -X POST "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/deployments/sources/upload-urls" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/deployments/sources/upload-urls', {
method: 'POST',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
POST /api/v1/projects/{ref}/deployments/sources
Upload files to deploy Send the files to deploy, without a repository, as one archive (.zip, .tar, .tar.gz) as the body. It is kept under the digest of its contents; the deployment is a second call, POST /deployments with {"source": "<digest>"}, so the same bytes can be deployed to a preview and then to production.
curl -X POST "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/deployments/sources" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/octet-stream" \
--data-binary @file
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/deployments/sources', {
method: 'POST',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/octet-stream' },
body: bytes,
})
const result = await response.json()
POST /api/v1/projects/{ref}/deployments
Create a deployment Three kinds, by what the body holds. source is the digest of an archive sent to POST /deployments/sources; files (or files_base64) maps paths to contents; with neither, app, branch and commit build a commit from the repository. target set to production deploys to production, otherwise to a preview.
curl -X POST "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/deployments" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"source":"export default async () => new Response(\"ok\")","files":"value","files_base64":"value","app":"owner/repo","branch":"main","commit":"0123456789abcdef0123456789abcdef01234567","wait":0,"block_on_advisors":true,"prebuilt":true,"target":"preview","message":"value"}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/deployments', {
method: 'POST',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"source": "export default async () => new Response(\"ok\")",
"files": "value",
"files_base64": "value",
"app": "owner/repo",
"branch": "main",
"commit": "0123456789abcdef0123456789abcdef01234567",
"wait": 0,
"block_on_advisors": true,
"prebuilt": true,
"target": "preview",
"message": "value"
}),
})
const result = await response.json()
POST /api/v1/projects/{ref}/deployments/{id}/redeploy
Redeploy Builds the same commit as one deployment again, to the same environment. Use it to rerun a build that failed for a reason unrelated to the commit (an environment variable added later, a package registry that was briefly down). Only owners and admins can deploy to production. The answer has the new deployment's addresses (url, preview_url or production_url) and the security check (advisors).
curl -X POST "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/deployments/ID/redeploy" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/deployments/ID/redeploy', {
method: 'POST',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
POST /api/v1/projects/{ref}/deployments/{id}/rollback
Roll back production Points the production address straight back to a production deployment that served before. Nothing is rebuilt, and the switch takes a few seconds. Custom domains follow. The answer has that deployment's url and production_url. Production is then held (production_held): new production builds are built but not served until you promote one with promote_deployment. Only owners and admins can do this.
curl -X POST "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/deployments/ID/rollback" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/deployments/ID/rollback', {
method: 'POST',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
GET /api/v1/projects/{ref}/deploy-hooks
Deploy hooks Shows the deploy hooks and their addresses. A POST to an address builds the latest commit of its branch, so the address itself is a secret. A read-only token sees only the last four characters of each address (secret_hidden); a token with write access sees all of it.
curl "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/deploy-hooks" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/deploy-hooks', {
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
POST /api/v1/projects/{ref}/deploy-hooks
Create a deploy hook Creates an address that triggers a build without a push. Have a CMS call it when a post is published, or a scheduled job. Only owners and admins can create a hook for the production branch.
curl -X POST "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/deploy-hooks" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"app":"owner/repo","branch":"main"}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/deploy-hooks', {
method: 'POST',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"app": "owner/repo",
"branch": "main"
}),
})
const result = await response.json()
DELETE /api/v1/projects/{ref}/deploy-hooks/{id}
Remove a deploy hook Removes a deploy hook. Whatever called its address no longer causes a deployment.
curl -X DELETE "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/deploy-hooks/ID" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/deploy-hooks/ID', {
method: 'DELETE',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
GET /api/v1/projects/{ref}/deployments/deleted
Recently deleted deployments Returns the deployments deleted in the last 3 days (by hand or because their retention period ended) and until when each can be restored (restorable_until). Meanwhile their own address answers 410.
curl "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/deployments/deleted" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/deployments/deleted', {
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
DELETE /api/v1/projects/{ref}/deployments/{id}
Delete a deployment Deletes one deployment. A deployment being served or still building cannot be deleted. It can be restored with restore_deployment for 3 days, then its files and build log are removed. Production deployments take a project admin, the rest a developer or above.
curl -X DELETE "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/deployments/ID" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/deployments/ID', {
method: 'DELETE',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
POST /api/v1/projects/{ref}/deployments/{id}/restore
Restore a deployment Restores a deployment deleted in the last 30 days. Its own address answers again, and it can be rolled back or promoted to. Production deployments take a project admin, the rest a developer or above.
curl -X POST "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/deployments/ID/restore" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/deployments/ID/restore', {
method: 'POST',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
GET /api/v1/projects/{ref}/deployments
Deployments Shows this project's recent deployments, newest first: status (queued, building, ready, error), environment, addresses, branch, commit and the reason it failed. Deleted deployments are left out (list_deleted_deployments shows them). When next_before is set, pass it as before for the next page. url is the deployment's own dpl- address, production_url the production address, preview_url its branch's preview address. preview_protection says who can open a preview address (members: organization members only, the default / password / off: anyone); null for production, whose address is always public, though with protection on a dpl- address is protected even for a production build.
curl "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/deployments?limit=1&before=value" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/deployments?limit=1&before=value', {
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
GET /api/v1/projects/{ref}/deployments/{id}
One deployment and its build log Shows the status of one deployment, its addresses and the end of its build log. When a build failed, the reason is usually in the last few lines of the log. Environment variable values the customer set are masked as ••••••. url is the deployment's own dpl- address; production_url or preview_url is the production or branch address. preview_protection says who can open a preview address (members: organization members only, the default / password / off: anyone); null for production, whose address is always public. With wait (seconds) it waits for the build to finish.
curl "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/deployments/ID?tail=1&wait=0" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/deployments/ID?tail=1&wait=0', {
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
GET /api/v1/projects/{ref}/branch-previews
Branch previews Shows whether a push to a branch other than production builds a preview in this project's organization (branch_previews). false means only what reaches the production branch (usually main) is built.
curl "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/branch-previews" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/branch-previews', {
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
PUT /api/v1/projects/{ref}/branch-previews
Change branch previews Turns preview builds for branch pushes on or off for the whole organization. false builds only what reaches the production branch (usually main); a skipped push stays in the deployment history as skipped. Redeploys, uploads and deploy hooks still build. Applies to every project in the organization. Only owners and admins can do this.
curl -X PUT "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/branch-previews" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"enabled":true}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/branch-previews', {
method: 'PUT',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"enabled": true
}),
})
const result = await response.json()
GET /api/v1/projects/{ref}/preview-protection
Preview protection Shows who can open deployments that are not production (branch previews, per-deployment addresses): off, members (organisation members only), password. Also returns which addresses are protected (scope), addresses let in without signing in (trusted_ips), paths that pass unchecked (options_paths), bypass keys (bypass_secrets, only their last four characters) and share links (share_links).
curl "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/preview-protection" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/preview-protection', {
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
PUT /api/v1/projects/{ref}/preview-protection
Change preview protection Changes who can open previews. members means organisation members signed in to the console, password means one shared password (a password of at least 8 characters is needed the first time), off means anyone. The production address and connected domains are always public. Only owners and admins can do this.
curl -X PUT "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/preview-protection" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"mode":"off"}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/preview-protection', {
method: 'PUT',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"mode": "off"
}),
})
const result = await response.json()
GET /api/v1/projects/{ref}/apps
Connected repositories and build settings For each repository that deploys to this project, shows the production branch, the folder to build (root_directory), the framework preset (framework; null means detect automatically) and the build command, output directory and install command overrides (build_command, output_directory, install_command; null means the preset default). detected_framework is what the latest build used, and frameworks lists the presets you can choose. A repository appears on its first push.
curl "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/apps" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/apps', {
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
DELETE /api/v1/projects/{ref}/apps/{name}
Delete an app Deletes one app of the project (an app whose folder a monorepo removed). Its addresses stop answering at once, its builds in progress are cancelled, and its deployments are deleted with no restore, their files gone within minutes. A push no longer builds it even if the folder is still in the repository. It cannot be undone. The project's own site, an app with domains and an app with disks are refused, with what to do first. Use it only when the user clearly asks, and put the app name exactly in confirm. Only owners and admins can do this.
curl -X DELETE "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/apps/my-name" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"confirm":"my-project"}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/apps/my-name', {
method: 'DELETE',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"confirm": "my-project"
}),
})
const result = await response.json()
PATCH /api/v1/projects/{ref}/apps/{name}
Change build settings Changes one repository's production branch, folder to build, framework preset, build command, output directory or install command. For a monorepo, put the app folder (for example apps/web) in root_directory. Values you leave out stay as they are; null puts one back to detect automatically (the preset default). An empty command skips that step. If the repository's blackwall.json sets the same item, its value comes first. Takes effect from the next deployment, except port (the port the server listens on), which restarts the server within a minute. Only owners and admins can do this.
curl -X PATCH "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/apps/my-name" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"production_branch":"main","root_directory":".","run_as":"platform","port":"value"}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/apps/my-name', {
method: 'PATCH',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"production_branch": "main",
"root_directory": ".",
"run_as": "platform",
"port": "value"
}),
})
const result = await response.json()
GET /api/v1/projects/{ref}/env
Environment variables The environment variables a deployed app gets when it is built and run. The same name can exist separately for production and preview. A sensitive value is not returned; only its last four characters come as value_hint. readable false means the value cannot be opened and is left out of builds, so save it again. automatic lists the automatic variables that are set without being saved: SUPABASE_URL, NEXT_PUBLIC_SUPABASE_URL, SUPABASE_ANON_KEY, NEXT_PUBLIC_SUPABASE_ANON_KEY, NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY and SUPABASE_SERVICE_ROLE_KEY, the names an app moved from Supabase already reads. available_in says where each is available: the public ones in build and runtime (build, runtime), SUPABASE_SERVICE_ROLE_KEY in runtime only (runtime: servers, middleware, functions), never in builds. A variable saved under the same name comes first, and a saved value goes to builds too (overridden_in).
curl "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/env" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/env', {
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
POST /api/v1/projects/{ref}/env
Save environment variables Saves one or more environment variables. Give them one by one in variables, or the whole content of a .env file in dotenv. A name that exists is overwritten. If any one is invalid, nothing is saved, except that a dotenv line with a name the platform sets is skipped and listed in skipped. PORT, HOST, HOSTNAME, HOME and names starting with BLACKWALL_ are used by the platform and cannot be set. Builds get CI=1 unless you set CI yourself (CI=false, for example). Changed values are used from the next deployment. Without sensitive, a name that looks like a secret (API_KEY, STRIPE_SECRET, DATABASE_URL and the like) is saved as sensitive and cannot be read back (sensitive_keys). Only owners and admins can change production values.
curl -X POST "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/env" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"targets":["production"]}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/env', {
method: 'POST',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"targets": [
"production"
]
}),
})
const result = await response.json()
DELETE /api/v1/projects/{ref}/env/{target}/{key}
Remove an environment variable Removes one environment variable from either production or preview. If the value was sensitive, it cannot be recovered.
curl -X DELETE "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/env/production/API_URL?app=owner%2Frepo&branch=main" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/env/production/API_URL?app=owner%2Frepo&branch=main', {
method: 'DELETE',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
GET /api/v1/projects/{ref}/git
Git connection The same as "Git connection" in the console. Shows the repositories this project deploys (connected: whether a push deploys it), the GitHub accounts linked (github_accounts) how private repositories are fetched (the last four characters of a GitHub or GitLab token, a GitHub App installation), and for each GitHub repository whether it runs its checks on One Server (checks_on_server: available, enabled, state, permission_url, workflows_using). If a private repository build fails at the fetch step, look here first.
curl "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/git" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/git', {
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
PUT /api/v1/projects/{ref}/git/tokens/{provider}
Save a repository token Saves an access token used to fetch private repositories (read access is enough). It is sealed and never shown again. For a self-hosted GitLab, put https://gitlab.example.com in gitlab_base. Used from the next build. Only owners and admins can do this.
curl -X PUT "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/git/tokens/github" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"token":"ghp_xxxxxxxxxxxxxxxxxxxx"}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/git/tokens/github', {
method: 'PUT',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"token": "ghp_xxxxxxxxxxxxxxxxxxxx"
}),
})
const result = await response.json()
DELETE /api/v1/projects/{ref}/git/tokens/{provider}
Remove a repository token Removes the saved token. A connected GitHub App installation is kept. Only owners and admins can do this.
curl -X DELETE "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/git/tokens/github" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/git/tokens/github', {
method: 'DELETE',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
POST /api/v1/projects/{ref}/git/repos
Add a repository Attaches a repository to this project before its first push. Pushes that come through the GitHub App then come to this project, and create_deploy_hook can build without a push. repo is owner/name for GitHub and group/name for GitLab. Only owners and admins can do this.
curl -X POST "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/git/repos" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"provider":"github","repo":"owner/repo"}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/git/repos', {
method: 'POST',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"provider": "github",
"repo": "owner/repo"
}),
})
const result = await response.json()
DELETE /api/v1/projects/{ref}/git/github-app
Disconnect a GitHub account Disconnects a GitHub account (a GitHub App installation) from this project: the one named by installation, or every one when it is empty. Saved tokens and the App installation on GitHub are kept. Connecting needs a person to confirm it on GitHub, so it can only be done in the console. Only owners and admins can do this.
curl -X DELETE "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/git/github-app" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/git/github-app', {
method: 'DELETE',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
DELETE /api/v1/projects/{ref}/git/github-app/{installation}
Disconnect a GitHub account Disconnects a GitHub account (a GitHub App installation) from this project: the one named by installation, or every one when it is empty. Saved tokens and the App installation on GitHub are kept. Connecting needs a person to confirm it on GitHub, so it can only be done in the console. Only owners and admins can do this.
curl -X DELETE "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/git/github-app/value" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/git/github-app/value', {
method: 'DELETE',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
GET /api/v1/projects/{ref}/git/importable
Find repositories to import The same as the import list under Git connection in the console. Shows up to 50 repositories the GitHub App can see on a linked GitHub account, most recently pushed first. With query it searches all of them, also past 300. If you just added a repository on GitHub, pass refresh: true. With several accounts, choose one with installation (github_accounts in list_git_access). Only owners and admins can see it.
curl "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/git/importable?query=value&installation=1" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/git/importable?query=value&installation=1', {
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
POST /api/v1/projects/{ref}/git/import
Import a repository The same as [Connect and deploy] in the console. Connects a repository the GitHub App can see to this project and starts the first deployment from the newest commit of its production branch. An empty branch means the repository's default branch. Build settings (framework and the rest) and environment variables (a .env text in dotenv) are saved before the first build. Importing a disconnected repository again connects it again with its settings. Only owners and admins can do this.
curl -X POST "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/git/import" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"repo":"owner/repo","branch":"main","root_directory":".","installation":1,"dotenv":"API_URL=https://example.com","sensitive":true,"app":"owner/repo"}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/git/import', {
method: 'POST',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"repo": "owner/repo",
"branch": "main",
"root_directory": ".",
"installation": 1,
"dotenv": "API_URL=https://example.com",
"sensitive": true,
"app": "owner/repo"
}),
})
const result = await response.json()
PUT /api/v1/projects/{ref}/git/checks/{repo}/{repo}
Run checks on One Server Turns on or off running a connected GitHub repository's GitHub Actions checks on One Server's machines, as [Run checks on One Server] under Git connection in the console does. On saves the repository variable POOL_RUNNER: a job that says runs-on: ${{ vars.POOL_RUNNER || 'ubuntu-latest' }} runs on One Server. Off deletes it, and jobs go back to GitHub's machines. When state is needs_permission, approve the GitHub App's new permissions at permission_url and it turns on by itself. Only owners and admins can do this.
curl -X PUT "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/git/checks/owner%2Frepo/owner%2Frepo" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"enabled":true}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/git/checks/owner%2Frepo/owner%2Frepo', {
method: 'PUT',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"enabled": true
}),
})
const result = await response.json()
DELETE /api/v1/projects/{ref}/git/repos/{name}
Disconnect a repository The same as [Disconnect] on a repository under Git connection in the console. Pushes to this repository no longer deploy. The deployment serving now, the history, build settings and environment variables stay, and import_repository with the same repository connects it again. Only owners and admins can do this.
curl -X DELETE "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/git/repos/my-name" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/git/repos/my-name', {
method: 'DELETE',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
GET /api/v1/projects/{ref}/volumes
Volumes Returns the app volumes (disk that stays when a server restarts or a new deployment goes out) and their backups, how much the plan allows in total (max_gb) and how much is used (used_gb), and the port each app's server listens on (apps[].listens_on). Volumes are mounted on production servers only.
curl "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/volumes" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/volumes', {
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
POST /api/v1/projects/{ref}/volumes
Create a volume Adds a volume to an app's production servers, mounted read-write at mount_path in the container; its size is a hard cap. For WordPress use /var/www/html. System paths such as /etc, /usr, /proc and /tmp are refused. Ready within a minute; the servers restart with it. Only owners and admins can do this.
curl -X POST "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/volumes" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"app":"owner/repo","mount_path":"value"}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/volumes', {
method: 'POST',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"app": "owner/repo",
"mount_path": "value"
}),
})
const result = await response.json()
PATCH /api/v1/projects/{ref}/volumes/{id}
Grow a volume Makes a volume larger without stopping the server. A volume cannot shrink. Only owners and admins can do this.
curl -X PATCH "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/volumes/ID" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"size_gb":1}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/volumes/ID', {
method: 'PATCH',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"size_gb": 1
}),
})
const result = await response.json()
DELETE /api/v1/projects/{ref}/volumes/{id}
Delete a volume Deletes a volume, every file on it and its backups. Production servers restart without it. This cannot be undone, so use it only when the user clearly asks, and put the volume path (mount_path) exactly in confirm. Only owners and admins can do this.
curl -X DELETE "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/volumes/ID" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"confirm":"my-project"}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/volumes/ID', {
method: 'DELETE',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"confirm": "my-project"
}),
})
const result = await response.json()
POST /api/v1/projects/{ref}/volumes/{id}/backups
Back up a volume Packs the volume's files now and keeps them for 30 days. Finishes within a few minutes and appears in list_volumes under backups. Only owners and admins can do this.
curl -X POST "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/volumes/ID/backups" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/volumes/ID/backups', {
method: 'POST',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
POST /api/v1/projects/{ref}/volumes/{id}/restore
Restore a volume Replaces the volume's current files with a backup's. Files changed after the backup are lost, but the current files are backed up first and kept for 7 days, so that backup undoes it. Use it only when the user asks. Only owners and admins can do this.
curl -X POST "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/volumes/ID/restore" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"backup_id":"BACKUP_ID"}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/volumes/ID/restore', {
method: 'POST',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"backup_id": "BACKUP_ID"
}),
})
const result = await response.json()
GET /api/v1/projects/{ref}/server-memory
Server memory The memory (MB) and CPUs this project's server deployments run with, the most its plan allows, the price per GB-hour and what a server held all month costs. Servers at production and branch addresses always run, requests or not (minimum one instance), so that is what one of them costs a month.
curl "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/server-memory" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/server-memory', {
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
PUT /api/v1/projects/{ref}/server-memory
Change server memory Chooses the memory this project's server deployments (Node servers, workers) run with: 512, 1024, 2048 or 4096 MB. Above 1024 MB they get two CPUs. Metered as runtime_gb_hour. Servers restart with the new size within a minute. Only owners and admins can do this.
curl -X PUT "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/server-memory" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"memory_mb":512}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/server-memory', {
method: 'PUT',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"memory_mb": 512
}),
})
const result = await response.json()
GET /api/v1/projects/{ref}/gpu
GPU jobs and servers This project's GPU jobs (the latest 50), GPU servers and GPU storage, the hourly price of each card and the price of a GB-month of storage, the regions and data centers to choose from, and how many GPUs the organisation may run at once and runs now. The free plan has no GPUs.
curl "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/gpu" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/gpu', {
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
POST /api/v1/projects/{ref}/gpu/jobs
Create a GPU job Rents a GPU and runs a command in a public container image to its end (training, a batch). The GPU is let go when the command ends or max_minutes passes, and the seconds used are billed at the card's hourly price. Results last only if the job uploads them somewhere, such as the project's storage. The image needs curl, wget or python3 to report its start and end. Pulling the image is GPU time too: it is billed and counts toward max_minutes.
curl -X POST "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/gpu/jobs" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"gpu":"rtx4090","image":"value","command":"value"}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/gpu/jobs', {
method: 'POST',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"gpu": "rtx4090",
"image": "value",
"command": "value"
}),
})
const result = await response.json()
GET /api/v1/projects/{ref}/gpu/jobs/{id}
A GPU job One GPU job's status, the time and money it used, its exit code and the end of its output (up to 64KB).
curl "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/gpu/jobs/ID" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/gpu/jobs/ID', {
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
POST /api/v1/projects/{ref}/gpu/jobs/{id}/cancel
Stop a GPU job Stops a GPU job. One not started yet never starts; a running one lets its GPU go. The time until the GPU is let go is billed.
curl -X POST "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/gpu/jobs/ID/cancel" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/gpu/jobs/ID/cancel', {
method: 'POST',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
POST /api/v1/projects/{ref}/gpu/servers
Create a GPU server Creates a GPU server that hosts a model from a public image. Called with the secret key at https://<ref>.<zone>/gpu/v1/servers/<name>/, it starts when stopped (answering 503 meanwhile) and passes the request on. It stops after idle_minutes without a request (0 keeps it up). Billed by the second from when it starts turning on until it is off, image download included. The server receives the x-oneend-gpu-token header, the same value as ONEEND_GPU_TOKEN.
curl -X POST "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/gpu/servers" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"name":"my-name","gpu":"rtx4090","image":"value"}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/gpu/servers', {
method: 'POST',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"name": "my-name",
"gpu": "rtx4090",
"image": "value"
}),
})
const result = await response.json()
POST /api/v1/projects/{ref}/gpu/servers/{name}/stop
Stop a GPU server Stops a GPU server now. The time until it is off is billed. The next request starts it again.
curl -X POST "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/gpu/servers/my-name/stop" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/gpu/servers/my-name/stop', {
method: 'POST',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
DELETE /api/v1/projects/{ref}/gpu/servers/{name}
Delete a GPU server Deletes a GPU server, stopping it first when it runs. This cannot be undone, so put the GPU server name exactly in confirm.
curl -X DELETE "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/gpu/servers/my-name" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"confirm":"my-project"}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/gpu/servers/my-name', {
method: 'DELETE',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"confirm": "my-project"
}),
})
const result = await response.json()
POST /api/v1/projects/{ref}/gpu/volumes
Create GPU storage Creates GPU storage in one data center to keep models and data. Name it as volume on a job or server and it is mounted at /workspace, so nothing has to be downloaded again. Billed by the GB-month for as long as it exists, used or not. Jobs and servers that use it rent their GPU in its data center only. Not on the free plan.
curl -X POST "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/gpu/volumes" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"name":"my-name","datacenter":"value"}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/gpu/volumes', {
method: 'POST',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"name": "my-name",
"datacenter": "value"
}),
})
const result = await response.json()
DELETE /api/v1/projects/{ref}/gpu/volumes/{name}
Delete GPU storage Deletes GPU storage and every file on it. Not while a job or server uses it. This cannot be undone. Storage is billed until it is deleted.
curl -X DELETE "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/gpu/volumes/my-name" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/gpu/volumes/my-name', {
method: 'DELETE',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
GET /api/v1/projects/{ref}/concurrent-builds
Concurrent builds How many of this project's builds may run at once. null means as many as the builders allow.
curl "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/concurrent-builds" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/concurrent-builds', {
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
PUT /api/v1/projects/{ref}/concurrent-builds
Change concurrent builds Sets how many of this project's builds may run at once, 1 to 20, or null for no limit. Builds over the limit wait in the queue and start when one ahead of them finishes; a waiting build is not billed for build minutes. Only owners and admins can do this.
curl -X PUT "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/concurrent-builds" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"concurrent_builds":"value"}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/concurrent-builds', {
method: 'PUT',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"concurrent_builds": "value"
}),
})
const result = await response.json()
Functions
GET /api/v1/projects/{ref}/functions
Functions Shows the deployed functions with the address to call each one and whether it is public. egress says whether outbound requests are on, and outbound_requests_per_minute is the limit a minute on outside requests that functions, pg_net and HTTP jobs share (calls to the project's own API are not counted).
curl "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/functions" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/functions', {
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
GET /api/v1/projects/{ref}/functions/{name}
Read a function's code Shows the code and version of a deployed function. Read the current code before changing it. When deploy_function answered status "building", build.status (building, deployed or failed) and build.error tell how it ended.
curl "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/functions/my-name" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/functions/my-name', {
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
PUT /api/v1/projects/{ref}/functions/{name}
Deploy a function Deploys one function. A function with the same name is replaced as a whole, and the next call runs the new code. The code is one TypeScript file that exports, with export default, (request, { sql }) => response. request has method, headers, claims (the claims of the key it was called with: role anon, authenticated or service_role; null for a public function called with no key), text() and json(); sql(text, values) runs one SQL statement with this project's service_role privileges and returns an array of rows. The response is an object (sent as JSON), a string, or { status, headers, body }. To use npm packages, send dependencies ({"zod":"^3.23.8"}) or package_json (a string) with it. They are installed at deploy time and bundled with the code into one ESM file (up to 5MB; install scripts are not run; no native modules). A package set installed once is reused, so from the second deploy on it takes seconds. If it has not finished in 40 seconds, it answers status "building" at once and the deploy carries on on the server. Then call get_function again until build.status is deployed or failed. For several files, send them together as files ({"lib/util.ts": "..."}) and import them by relative path. To send a whole folder, leave source empty and put everything, index.ts included, in files. As on Supabase, the imports of a deno.json (or import_map.json) and npm:, jsr: and URL imports (such as npm:zod@3, jsr:@supabase/supabase-js@2, https://esm.sh/…, https://deno.land/[email protected]/http/server.ts) work. npm:, jsr: and esm.sh are installed as npm packages at deploy time; any other URL is fetched once at deploy time and bundled with the code (the addresses and SHA-256 fetched are in get_function's remote_imports, and must match a deno.lock when there is one). Nothing is fetched while the function runs. As with Supabase's supabase/functions/<name>/ folder, when the code imports ../_shared/cors.ts, put it in files as "../_shared/cors.ts". Only folders beside the function folder can be sent this way. One call may run for 150 seconds (as on Supabase). To change that, use set_function_limits. The caller's Authorization header (when it is a key of this project) reaches the function as it was sent, so createClient(url, anonKey, { global: { headers: { Authorization: req.headers.get('Authorization') } } }) acts as that person. When you change a bundled function, send back the package_json and files that get_function returned, as they are. Leave them out and it becomes a single-file function. Network access is off by default and can be turned on with set_function_egress. The production environment variables arrive in process.env. Only owners and admins can deploy functions. Who can call it: a private function (the default) needs a key of this project: the publishable key (claims.role anon), a signed-in user's token (authenticated) or the secret key (service_role). This is what Supabase's verify_jwt checks, so supabase.functions.invoke and a fetch with the publishable key work as they are. To accept signed-in users only, check request.claims.role in the function. With public set to true, anyone can call it, with no key at all. Use that only for requests that arrive without a key, such as a payment provider's webhook. Calling: POST https://<ref>.<zone>/functions/v1/<name>, with the header Authorization: Bearer <publishable key, user token or secret key>.
curl -X PUT "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/functions/my-name" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"source":"export default async () => new Response(\"ok\")","public":true,"package_json":"value","package_lock":"value","dependencies":{},"files":{},"entry":"value"}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/functions/my-name', {
method: 'PUT',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"source": "export default async () => new Response(\"ok\")",
"public": true,
"package_json": "value",
"package_lock": "value",
"dependencies": {},
"files": {},
"entry": "value"
}),
})
const result = await response.json()
PATCH /api/v1/projects/{ref}/functions/{name}
Function time limits Sets, without deploying again, how long one call of a function may take (timeout_seconds) and how long one SQL statement of it may take (sql_timeout_seconds), in seconds. The defaults are 150 seconds (as on Supabase's edge functions) and 8 seconds; this server's maximum is get_function's timeout_cap_seconds. null puts one back to its default; leaving it out keeps the current value. Takes effect from the next call. A call past its limit is cut off with 504.
curl -X PATCH "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/functions/my-name" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"public":true}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/functions/my-name', {
method: 'PATCH',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"public": true
}),
})
const result = await response.json()
DELETE /api/v1/projects/{ref}/functions/{name}
Remove a function Removes a function. Its address returns 404, and scheduled jobs that call it fail. It cannot be undone, so use it only when the user clearly asks, and put the function name exactly in confirm.
curl -X DELETE "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/functions/my-name" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"confirm":"my-project"}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/functions/my-name', {
method: 'DELETE',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"confirm": "my-project"
}),
})
const result = await response.json()
PUT /api/v1/projects/{ref}/function-egress
Functions' outbound requests Allows or blocks functions from calling public HTTPS addresses with fetch(). The current state is egress in list_functions. Takes effect within 30 seconds. Only owners and admins can do this.
curl -X PUT "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/function-egress" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"enabled":true}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/function-egress', {
method: 'PUT',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"enabled": true
}),
})
const result = await response.json()
GET /api/v1/projects/{ref}/function-secrets
Function secrets The names of the secrets only functions see, and when each changed. No tool can read a value back. readable false means the value no longer opens and is left out of functions, so save it again. Only owners and admins can see them.
curl "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/function-secrets" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/function-secrets', {
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
POST /api/v1/projects/{ref}/function-secrets
Save function secrets Saves one or more secrets only functions see (a webhook signing key, a mail service's API key). They never reach a site build, and they win over an environment variable of the same name. Functions read them from process.env from their next call. A name already there is overwritten; if any one is wrong, nothing is saved. A saved value cannot be read back: the answer holds names only. Names starting with SUPABASE_ or BLACKWALL, and NODE_ENV, HOME, PATH, NODE_OPTIONS and TZ, are refused. Up to 100 per project and 32KB per value. Only owners and admins can do this.
curl -X POST "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/function-secrets" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"secrets":{},"dotenv":"API_URL=https://example.com"}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/function-secrets', {
method: 'POST',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"secrets": {},
"dotenv": "API_URL=https://example.com"
}),
})
const result = await response.json()
POST /api/v1/projects/{ref}/function-secrets/copy
Copy function secrets Copies function secrets by name from another of your projects (from) into this one (ref). The values move inside the server and the answer holds names only, so the same key need not be pasted again. A name this project already has is skipped (skipped) unless overwrite is true. Names from does not have are listed in missing and the rest are copied. Up to 50 at a time. You must be an owner or admin of both projects (they may be in different organisations).
curl -X POST "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/function-secrets/copy" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"from":"value","names":["my-name"]}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/function-secrets/copy', {
method: 'POST',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"from": "value",
"names": [
"my-name"
]
}),
})
const result = await response.json()
DELETE /api/v1/projects/{ref}/function-secrets/{name}
Delete a function secret Deletes one function secret. The value cannot be brought back, and functions run without it from their next call. Only owners and admins can do this.
curl -X DELETE "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/function-secrets/my-name" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/function-secrets/my-name', {
method: 'DELETE',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
Domains and edge
GET /api/v1/projects/{ref}/domains
Domains Shows the domains connected to this project with what each is for (site/api), the branch it follows, where it redirects, its verification state (with the TXT record to add if not verified yet) and its certificate state.
curl "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/domains" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/domains', {
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
POST /api/v1/projects/{ref}/domains
Connect a domain Connects a domain. Add the returned verification_record (TXT) to DNS and it is verified within a few minutes. With target=api the address answers as the project API (data, sign-in, storage). With branch, it follows that branch's preview. Wildcards such as *.example.com work. With pair_www=true the www address is connected too and one redirects to the other.
curl -X POST "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/domains" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"hostname":"app.example.com"}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/domains', {
method: 'POST',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"hostname": "app.example.com"
}),
})
const result = await response.json()
DELETE /api/v1/projects/{ref}/domains/{hostname}
Disconnect a domain Disconnects a domain. The address stops answering within a few seconds. Use it only when the user clearly asks, and put the domain exactly in confirm.
curl -X DELETE "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/domains/app.example.com" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"confirm":"my-project"}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/domains/app.example.com', {
method: 'DELETE',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"confirm": "my-project"
}),
})
const result = await response.json()
PUT /api/v1/projects/{ref}/domains/{hostname}/redirect
Redirect a domain Makes this domain redirect to another domain of the same project, or, with to empty, serve the site again. With a path in to (example.com/vision), the visited path is appended to it and the query string goes along: vision.example.com/x?y=1 → example.com/vision/x?y=1, and the home page goes to example.com/vision. The domain in to must be connected to this project and not itself a redirect.
curl -X PUT "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/domains/app.example.com/redirect" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"to":"https://example.com","status":308}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/domains/app.example.com/redirect', {
method: 'PUT',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"to": "https://example.com",
"status": 308
}),
})
const result = await response.json()
GET /api/v1/projects/{ref}/edge
Firewall and cache Shows this project's IP deny and allow lists, the request limit per minute for one address, what they apply to, and when the cache was last purged.
curl "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/edge" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/edge', {
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
PUT /api/v1/projects/{ref}/edge
Change the firewall Changes the IP deny list, the allow list (empty allows everyone), the request limit per minute (10 to 100000, null for the platform default) and what they apply to (all/site/api). Only the fields you give change. Only owners and admins can do this.
curl -X PUT "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/edge" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"deny":["value"],"allow":["value"],"rate_per_minute":1,"scope":"all"}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/edge', {
method: 'PUT',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"deny": [
"value"
],
"allow": [
"value"
],
"rate_per_minute": 1,
"scope": "all"
}),
})
const result = await response.json()
POST /api/v1/projects/{ref}/edge/purge
Purge the cache Discards every response stored at the edge because a server deployment allowed sharing with s-maxage. From the next request, the deployment answers again.
curl -X POST "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/edge/purge" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/edge/purge', {
method: 'POST',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
PUT /api/v1/projects/{ref}/domains/{hostname}/certificate
Upload a certificate Uses your own TLS certificate for a connected domain. certificate is the PEM chain (the server certificate first), key is the PEM private key. The domain name must be in the certificate. Takes effect within 1 minute. Only owners and admins can do this.
curl -X PUT "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/domains/app.example.com/certificate" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"certificate":"-----BEGIN CERTIFICATE-----\n…","key":"API_URL"}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/domains/app.example.com/certificate', {
method: 'PUT',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"certificate": "-----BEGIN CERTIFICATE-----\n…",
"key": "API_URL"
}),
})
const result = await response.json()
DELETE /api/v1/projects/{ref}/domains/{hostname}/certificate
Remove an uploaded certificate Removes the uploaded certificate and goes back to the automatically issued one. Only owners and admins can do this.
curl -X DELETE "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/domains/app.example.com/certificate" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/domains/app.example.com/certificate', {
method: 'DELETE',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
Network
GET /api/v1/projects/{ref}/network
Network addresses The addresses the project receives requests on (inbound: a custom domain's A record) and, for a project with the static outbound IP turned on, the static addresses it sends from (outbound.addresses). For a project without it the outbound address is shared and not static, so it is not returned. Do not put it on an allow list.
curl "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/network" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/network', {
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
GET /api/v1/projects/{ref}/network/ips
Network addresses The addresses the project receives requests on (inbound: a custom domain's A record) and, for a project with the static outbound IP turned on, the static addresses it sends from (outbound.addresses). For a project without it the outbound address is shared and not static, so it is not returned. Do not put it on an allow list.
curl "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/network/ips" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/network/ips', {
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
POST /api/v1/projects/{ref}/network/static-outbound-ip
Static outbound IP Turns the static outbound IP, a paid add-on, on or off. When on, server deployments, functions' fetch() and database webhooks leave from a static address, and a monthly price is billed for the time it is on. Pro plan and above; only owners, admins and billing members can do it. It costs money, so use it only when the user clearly asks. The price and the current state are in get_network. In a region whose address does not exist yet the outcome is provisioning: the address is being made (usually under an hour), and until it is ready nothing is billed and no address is returned.
curl -X POST "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/network/static-outbound-ip" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/network/static-outbound-ip', {
method: 'POST',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
DELETE /api/v1/projects/{ref}/network/static-outbound-ip
Static outbound IP Turns the static outbound IP, a paid add-on, on or off. When on, server deployments, functions' fetch() and database webhooks leave from a static address, and a monthly price is billed for the time it is on. Pro plan and above; only owners, admins and billing members can do it. It costs money, so use it only when the user clearly asks. The price and the current state are in get_network. In a region whose address does not exist yet the outcome is provisioning: the address is being made (usually under an hour), and until it is ready nothing is billed and no address is returned.
curl -X DELETE "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/network/static-outbound-ip" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/network/static-outbound-ip', {
method: 'DELETE',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
Scheduled jobs
GET /api/v1/projects/{ref}/jobs
Scheduled jobs Shows the scheduled jobs (cron) with their schedule, next run and last result. Jobs made with cron.schedule in the project's SQL have source sql. limit is the plan's number of jobs. All times are UTC.
curl "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/jobs" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/jobs', {
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
PUT /api/v1/projects/{ref}/jobs/{job}
Create or change a scheduled job Calls a function or runs one SQL statement on a schedule. A job with the same name is changed. schedule is five-field cron (minute hour day month weekday) in UTC. Korea is UTC+9, so midnight in Korea is "0 15 * * *". With kind function, target is the name of a deployed function (called with a POST whose body is {}); with sql, target is SQL run as the service role. External URLs cannot be called. Create a function, or use net.http_post from SQL. SQL has to finish within timeout_seconds (120 by default); when the SQL raises its own statement_timeout it is given that long. Either way, at most the plan's maximum (Free 300 seconds, Pro and Enterprise 3600). Jobs made with cron.schedule in SQL are listed too, with source sql; change them in SQL (cron.alter_job, cron.unschedule) or with set_job_enabled and remove_job. Each plan has a number of jobs per project (limit in list_jobs).
curl -X PUT "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/jobs/nightly" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"schedule":"0 3 * * *","kind":"function","target":"hello"}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/jobs/nightly', {
method: 'PUT',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"schedule": "0 3 * * *",
"kind": "function",
"target": "hello"
}),
})
const result = await response.json()
PATCH /api/v1/projects/{ref}/jobs/{job}
Turn a scheduled job on or off Turns a scheduled job off or back on. When turned back on it does not catch up on missed runs; it runs from the next scheduled time. job is the id or the name.
curl -X PATCH "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/jobs/nightly" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"enabled":true}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/jobs/nightly', {
method: 'PATCH',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"enabled": true
}),
})
const result = await response.json()
POST /api/v1/projects/{ref}/jobs/{job}/run
Run a scheduled job now Runs the job once within a minute, without waiting for its schedule. See the result with list_job_runs.
curl -X POST "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/jobs/nightly/run" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/jobs/nightly/run', {
method: 'POST',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
GET /api/v1/projects/{ref}/jobs/{job}/runs
Scheduled job runs Shows a job's recent runs and their results, newest first, with the error when one failed.
curl "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/jobs/nightly/runs?limit=1" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/jobs/nightly/runs?limit=1', {
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
DELETE /api/v1/projects/{ref}/jobs/{job}
Remove a scheduled job Removes a scheduled job and its run history.
curl -X DELETE "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/jobs/nightly" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/jobs/nightly', {
method: 'DELETE',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
Database webhooks
GET /api/v1/projects/{ref}/webhooks
Database webhooks Shows the webhooks that report table changes and their recent deliveries. attached false means the table was dropped and the webhook stopped. The signing key (signing_secret) is shown once, when the webhook is created (create_db_webhook); the list carries only signing_secret_set and its last four characters (signing_secret_last4).
curl "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/webhooks" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/webhooks', {
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
POST /api/v1/projects/{ref}/webhooks
Create a database webhook Sends a POST when rows are added to, changed in or deleted from a table. Only for committed changes, within a few seconds. With kind url, target is a public https address (no private or internal addresses, redirects are not followed); with function, it is the name of a function in this project. Body: { type: "INSERT"|"UPDATE"|"DELETE", table, schema: "public", record, old_record, hook, delivery, occurred_at }. Verify it with the header x-blackwall-signature: t=<seconds>,v1=<HMAC-SHA256(signing_secret, "<t>.<body>") in hex>. signing_secret is in this answer only and cannot be read again, so save it on the receiving side right away. On failure (a response other than 2xx, or more than 10 seconds), it sends again after 10 seconds, 1 minute, 5 minutes and 30 minutes, and gives up on the fifth try.
curl -X POST "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/webhooks" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"name":"my-name","table":"notes","events":["insert"],"kind":"url","target":"hello"}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/webhooks', {
method: 'POST',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"name": "my-name",
"table": "notes",
"events": [
"insert"
],
"kind": "url",
"target": "hello"
}),
})
const result = await response.json()
PATCH /api/v1/projects/{ref}/webhooks/{webhook}
Turn a database webhook on or off Turns a webhook off or on. Changes made while it is off are never sent. webhook is the id or the name.
curl -X PATCH "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/webhooks/orders" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"enabled":true}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/webhooks/orders', {
method: 'PATCH',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"enabled": true
}),
})
const result = await response.json()
DELETE /api/v1/projects/{ref}/webhooks/{webhook}
Remove a database webhook Removes a webhook, its delivery history and any changes not sent yet.
curl -X DELETE "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/webhooks/orders" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/webhooks/orders', {
method: 'DELETE',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
GET /api/v1/projects/{ref}/webhooks/{webhook}/deliveries
Database webhook deliveries Shows a webhook's recent deliveries with the response status and the reason for any failure, newest first. Kept for 7 days.
curl "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/webhooks/orders/deliveries?limit=1" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/webhooks/orders/deliveries?limit=1', {
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
Backups and restore
GET /api/v1/projects/{ref}/backups
Backups Shows the project backups (automatic every night between 03:00 and 05:00 in the local time of the project region, made by hand, and made just before a restore) and the restore history. retention_days is how long they are kept.
curl "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/backups" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/backups', {
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
POST /api/v1/projects/{ref}/backups
Back up now Backs up the tables, users and files now. Make one before a big change (a migration, a large delete). Kept for 7 days.
curl -X POST "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/backups" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/backups', {
method: 'POST',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
POST /api/v1/projects/{ref}/backups/{backup_id}/restore
Restore a backup Returns the project's tables, users and files to when the backup was made. Give at (an ISO time) instead of backup_id to return to that moment, to the second (Pro and above, within list_backups' point_in_time range); files are then returned to what the rows at that moment point to (including ones deleted in the last 14 days) only on servers that use a file bucket, and otherwise left as they are now. Every change after that point is lost, so use this only when the user clearly asks. The state just before the restore is backed up first, so you can restore again with undo_backup_id. Only owners and admins can do this.
curl -X POST "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/backups/BACKUP_ID/restore" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/backups/BACKUP_ID/restore', {
method: 'POST',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
POST /api/v1/projects/{ref}/backups/restore-to-time
Restore a backup Returns the project's tables, users and files to when the backup was made. Give at (an ISO time) instead of backup_id to return to that moment, to the second (Pro and above, within list_backups' point_in_time range); files are then returned to what the rows at that moment point to (including ones deleted in the last 14 days) only on servers that use a file bucket, and otherwise left as they are now. Every change after that point is lost, so use this only when the user clearly asks. The state just before the restore is backed up first, so you can restore again with undo_backup_id. Only owners and admins can do this.
curl -X POST "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/backups/restore-to-time" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"at":"2026-10-01T14:59:00+09:00"}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/backups/restore-to-time', {
method: 'POST',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"at": "2026-10-01T14:59:00+09:00"
}),
})
const result = await response.json()
Logs and observability
GET /api/v1/projects/{ref}/logs
Logs Shows what happened in the project, newest first: requests to the site, API, sign-in and functions (method, path, status, time taken) and the lines the deployed servers and functions printed. If the app returns 500, look here first with level set to error. For the next page, pass the response's next_before as before. Query strings are not stored.
curl "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/logs?source=site&level=warn" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/logs?source=site&level=warn', {
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
GET /api/v1/projects/{ref}/log-drains
Log drains Where logs are sent (https or datadog), which sources are sent, and the last delivery and error. The signing key (signing_secret) is shown once, when the drain is created (create_log_drain); the list carries only signing_secret_set and, for owners and admins, its last four characters (signing_secret_last4).
curl "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/log-drains" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/log-drains', {
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
POST /api/v1/projects/{ref}/log-drains
Add a log drain Sends this project's logs elsewhere, starting with logs written after it is created. kind=https POSTs signed JSON; kind=datadog needs an API key in secret. An https drain's signing_secret is in this answer only, so save it on the receiving side right away. Up to 5 per project. Only owners and admins can do this.
curl -X POST "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/log-drains" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"name":"my-name","kind":"https","url":"https://example.com/hook"}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/log-drains', {
method: 'POST',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"name": "my-name",
"kind": "https",
"url": "https://example.com/hook"
}),
})
const result = await response.json()
PATCH /api/v1/projects/{ref}/log-drains/{id}
Turn a log drain off or on Stops or restarts sending and keeps the settings. Only owners and admins can do this.
curl -X PATCH "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/log-drains/ID" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"enabled":true}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/log-drains/ID', {
method: 'PATCH',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"enabled": true
}),
})
const result = await response.json()
DELETE /api/v1/projects/{ref}/log-drains/{id}
Remove a log drain Removes a log drain. Only owners and admins can do this.
curl -X DELETE "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/log-drains/ID" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/log-drains/ID', {
method: 'DELETE',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
GET /api/v1/projects/{ref}/metrics
Metrics Returns requests, failures and latency (p50/p95/p99) by surface and by time, and the database size, connections and cache hit rate.
curl "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/metrics?range=1h" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/metrics?range=1h', {
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
GET /api/v1/projects/{ref}/audit
Audit log tab=activity is who changed what in the organisation; tab=access is who accessed personal data. Newest first, up to 200 at a time; when has_more is true, call again with a higher offset. from and to are YYYY-MM-DD (dates in Korea). Only owners and admins can do this.
curl "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/audit?tab=activity&from=value" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/audit?tab=activity&from=value', {
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
Team and notifications
GET /api/v1/projects/{ref}/team
Team members The members of the organisation that owns this project, with their roles, whether they use two-step verification, and invitations not accepted yet.
curl "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/team" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/team', {
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
POST /api/v1/projects/{ref}/team/invitations
Invite a member Sends an invitation link by email. A person joins by opening the link, so nobody is added straight away. For an address that is already a member, only the role changes. Only owners and admins can do this.
curl -X POST "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/team/invitations" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"email":"[email protected]"}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/team/invitations', {
method: 'POST',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"email": "[email protected]"
}),
})
const result = await response.json()
DELETE /api/v1/projects/{ref}/team/invitations/{id}
Cancel an invitation Cancels a sent invitation. Its link stops opening at once. id is in the invitations of list_team.
curl -X DELETE "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/team/invitations/ID" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/team/invitations/ID', {
method: 'DELETE',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
PATCH /api/v1/projects/{ref}/team/members/{email}
Change a member's role Changes the role of someone who is already a member. The owner's role cannot be changed. Only owners and admins can do this.
curl -X PATCH "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/team/members/person%40example.com" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"role":"admin"}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/team/members/person%40example.com', {
method: 'PATCH',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"role": "admin"
}),
})
const result = await response.json()
DELETE /api/v1/projects/{ref}/team/members/{email}
Remove a member Removes someone from the organisation. The owner cannot be removed. Only owners and admins can do this.
curl -X DELETE "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/team/members/person%40example.com" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/team/members/person%40example.com', {
method: 'DELETE',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
PUT /api/v1/projects/{ref}/team/mfa
Require two-step verification Requires two-step verification from every member of the organisation, or stops requiring it. To turn it on, this token's owner must have two-step verification on first. Members without it cannot open this organisation until they turn it on, and are listed in without_mfa in the response. Only owners and admins can do this.
curl -X PUT "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/team/mfa" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"required":true}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/team/mfa', {
method: 'PUT',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"required": true
}),
})
const result = await response.json()
GET /api/v1/projects/{ref}/channels
Notification channels The Slack, KakaoWork and webhook channels that receive news about deployments, domains, usage and billing, with the result of the last delivery. Organisation wide. A webhook channel's signing key (signing_secret) is shown once, when the channel is created (create_channel); the list carries only signing_secret_set and its last four characters (signing_secret_last4).
curl "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/channels" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/channels', {
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
POST /api/v1/projects/{ref}/channels
Add a notification channel Sends notifications to Slack (an Incoming Webhook address), KakaoWork (a bot webhook address), a signed webhook, or email (1 to 10 addresses in emails). An email channel mails each address a confirmation link and sends notifications only to addresses that opened it. Leave notices empty to receive every kind (usage covers limit warnings and traffic spike alerts). The signing_secret of a webhook channel is in this answer only, so save it on the receiving side right away. Check it with test_channel after creating it. Only owners and admins can do this.
curl -X POST "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/channels" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"kind":"slack","name":"my-name"}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/channels', {
method: 'POST',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"kind": "slack",
"name": "my-name"
}),
})
const result = await response.json()
POST /api/v1/projects/{ref}/channels/{id}/test
Test a notification channel Sends a test message to that one channel only. For an email channel it goes to confirmed addresses only, and addresses still waiting are sent the confirmation again. Only owners and admins can do this.
curl -X POST "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/channels/ID/test" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/channels/ID/test', {
method: 'POST',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
PATCH /api/v1/projects/{ref}/channels/{id}
Turn a notification channel off or on Stops or resumes notifications and keeps the settings. Only owners and admins can do this.
curl -X PATCH "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/channels/ID" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"enabled":true}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/channels/ID', {
method: 'PATCH',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"enabled": true
}),
})
const result = await response.json()
DELETE /api/v1/projects/{ref}/channels/{id}
Remove a notification channel Removes a notification channel. Only owners and admins can do this.
curl -X DELETE "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/channels/ID" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/channels/ID', {
method: 'DELETE',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
Billing and usage
GET /api/v1/projects/{ref}/usage
Usage Returns the number of tables, rows, users and files, the storage used, this month's metered amounts, and the limits a minute (limits.outbound_requests_per_minute: outside requests that functions, pg_net and HTTP jobs share; calls to the project's own API are not counted).
curl "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/usage" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/usage', {
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
GET /api/v1/projects/{ref}/billing/plan
Plan The organisation's current plan, any scheduled change, the plans it can choose and their monthly prices, and the paid add-ons running in the organisation (addons). On the Free plan, free holds its limits (one person, no custom domains, deployments a day, paused after 3 unused days, build minutes and traffic) and what is Pro's. Each add-on is turned on and off with its own tool (set_static_outbound_ip). Changing the plan needs a payment, so it is done only on the console's billing page. Only owners, admins and billing members can see it.
curl "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/billing/plan" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/billing/plan', {
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
GET /api/v1/projects/{ref}/billing/spend
Spend controls The spend cap (on: usage stops at what the plan includes and no overage is charged), the monthly overage limit and its alert webhook, and this month's usage. Only owners, admins and billing members can see it.
curl "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/billing/spend" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/billing/spend', {
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
PUT /api/v1/projects/{ref}/billing/spend-cap
Turn the spend cap on or off Turns the spend cap of a paid plan on or off. On, usage stops at what is included and there is no overage (the console spend limit's "Allowances only"). Off, what goes over is billed, so turning it off takes the project name (name from list_projects) exactly in confirm. Only owners, admins and billing members can do this.
curl -X PUT "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/billing/spend-cap" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"enabled":true}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/billing/spend-cap', {
method: 'PUT',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"enabled": true
}),
})
const result = await response.json()
PUT /api/v1/projects/{ref}/billing/spend-limit
Monthly spend limit Sets the limit on a month's overage (in the currency's smallest unit, won) and the webhook address to alert as it is approached. With the spend cap off, this is the console spend limit's "Allow overage up to an amount" (null: "No limit"). spend_limit_minor null removes the limit. Leave webhook_url out to keep the current address. New alert addresses are better added as notification channels (create_channel). Only owners, admins and billing members can do this.
curl -X PUT "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/billing/spend-limit" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"spend_limit_minor":"value"}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/billing/spend-limit', {
method: 'PUT',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"spend_limit_minor": "value"
}),
})
const result = await response.json()
GET /api/v1/projects/{ref}/billing
Bill and usage One month's bill (usage, included amount and charge per item) and usage by day. Empty period means this month (UTC). Amounts are in the smallest unit of currency (KRW: won, USD: cents). included is what the plans held this month allow, split by the days on each; list_included is the Pro allowance. amount_minor and total_minor are what is charged; list_amount_minor and list_total_minor are the list price. An organisation with billing_exempt true (the operator's own) is charged 0 and is never stopped for payment; its list price is the Pro rate card. Cards and payment history are only in the console. Only owners, admins and billing members can see it.
curl "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/billing?period=value" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/billing?period=value', {
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
Other
GET /api/v1/projects/{ref}/transfer
Organizations to transfer to The other organizations this project can move to (ones where you are an owner or admin), with id, name and plan. can_transfer says whether you can move it, which needs you to be an owner of its current organization. Put an id in organisation of transfer_project.
curl "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/transfer" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/transfer', {
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
POST /api/v1/projects/{ref}/transfer
Transfer project Moves the project to another organization. You must be an owner of its current organization and an owner or admin of the receiving one, and the receiving plan must have room for another project. From the move on, usage is billed to the receiving organization, so this month's bill splits at that moment. Access given to members of the old organization is removed, and only an owner of the receiving organization can move it back. Addresses, keys, data and deployments stay as they are. Use it only when the user clearly asks, and put the project name exactly in confirm.
curl -X POST "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/transfer" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"organisation":"My team","confirm":"my-project"}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/transfer', {
method: 'POST',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"organisation": "My team",
"confirm": "my-project"
}),
})
const result = await response.json()
GET /api/v1/projects/{ref}/server
Dedicated server Shows the project's dedicated server: size (tier), location, status, address, monthly price, standby, automatic failover, restore days, when it may next move, and jobs in progress. server is null when the project uses the shared server; offered is false while dedicated servers are not open.
curl "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/server" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/server', {
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
POST /api/v1/projects/{ref}/server
Rent a dedicated server Rents a server for this project alone. Show sizes and monthly prices per location with list_server_sizes first, and pass only what the user chose. Usually ready within 10 minutes; the database and app move onto it, then the address switches. From the Pro plan. Only owners and admins can do this.
curl -X POST "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/server" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"tier":"value"}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/server', {
method: 'POST',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"tier": "value"
}),
})
const result = await response.json()
PATCH /api/v1/projects/{ref}/server
Change the server size Changes the dedicated server's size. when=now does it now, tonight between 03:00 and 05:00 in the server location's time. Without a standby the server does not answer for 3 to 5 minutes; with one, only the few seconds of the switch. Changing size is free; the monthly price is the new size's (list_server_sizes). Only owners and admins can do this.
curl -X PATCH "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/server" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"tier":"value"}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/server', {
method: 'PATCH',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"tier": "value"
}),
})
const result = await response.json()
DELETE /api/v1/projects/{ref}/server
Give back the dedicated server Gives the dedicated server back: a last backup, the database and app moved to the shared server, then the server (and its standby) deleted. Writes pause during the move. Use it only when the user asks, and put the ref exactly in confirm. Only owners and admins can do this.
curl -X DELETE "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/server" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"confirm":"my-project"}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/server', {
method: 'DELETE',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"confirm": "my-project"
}),
})
const result = await response.json()
PUT /api/v1/projects/{ref}/server/standby
Standby server Turns a standby server of the same size in the same location on or off. It replicates the database continuously and costs the same as its size a month (list_server_sizes). With auto_failover=true the project switches to it on its own once the primary has not answered for 60 seconds (needs a standby). Only owners and admins can do this.
curl -X PUT "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/server/standby" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"standby":true}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/server/standby', {
method: 'PUT',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"standby": true
}),
})
const result = await response.json()
POST /api/v1/projects/{ref}/server/move
Move the server Moves the dedicated server to another location. Free, once a month (next_move_at). A server is made there and replicated; writes pause for a few seconds when the address switches. The old server is kept for 7 days. The monthly price is the new location's (list_server_sizes). Only owners and admins can do this.
curl -X POST "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/server/move" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"region":"kr"}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/server/move', {
method: 'POST',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"region": "kr"
}),
})
const result = await response.json()
PUT /api/v1/projects/{ref}/server/restore-days
Restore days Sets how far back the project can be restored to a moment: 7 or 28 days. 28 is only on a dedicated server and adds a monthly charge (get_server options, get_billing). Only owners and admins can do this.
curl -X PUT "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/server/restore-days" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"days":7}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/server/restore-days', {
method: 'PUT',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"days": 7
}),
})
const result = await response.json()
GET /api/v1/projects/{ref}/s3-keys
S3 access keys The S3 endpoint (endpoint, region, force_path_style), the TUS address for resumable uploads, and each S3 access key's name, access key ID, last use and revoked state. The secret access key is never returned.
curl "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/s3-keys" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/s3-keys', {
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
POST /api/v1/projects/{ref}/s3-keys
Create an S3 access key Creates an access key ID and secret access key that the AWS SDKs, the aws CLI or rclone sign requests to /storage/v1/s3 with. It acts as the service role and bypasses access rules, so keep it on a server. The secret access key is in this response only and cannot be seen again. Only owners and admins can create keys, up to 20 per project.
curl -X POST "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/s3-keys" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"name":"my-name"}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/s3-keys', {
method: 'POST',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"name": "my-name"
}),
})
const result = await response.json()
DELETE /api/v1/projects/{ref}/s3-keys/{id}
Revoke an S3 access key Revokes one S3 access key. Requests signed with it are refused within 30 seconds. Other keys are not affected. This cannot be undone.
curl -X DELETE "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/s3-keys/ID" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/s3-keys/ID', {
method: 'DELETE',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
POST /api/v1/projects/{ref}/storage/policies
Create a file access rule Adds one access rule to the file table (objects). Takes name, command (select, insert, update, delete or all), roles, using and check. The project login does not own the file table, so rules cannot be made with SQL; use this route.
curl -X POST "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/storage/policies" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/storage/policies', {
method: 'POST',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({}),
})
const result = await response.json()
POST /api/v1/projects/{ref}/storage/copy-from-import
Copy files from an import Copies a Supabase project's buckets and files into a project here (ref), read with a Supabase account connected in import_sources. A bucket missing here is made with the source's public flag, size limit and types; files go into the same store upload_object writes to, held to the same limits. A file already here with the same size is passed over, so calling again is safe. One call copies up to 200 files (max_files) within 45 seconds; when files remain, call again with the answer's next until done is true. The answer gives each bucket's created, copied, skipped, failed and bytes, and the first few failed files. The Supabase key never appears in the conversation. Bucket access rules are not copied. dry_run shows the counts and changes nothing. Owners, admins and developers only.
curl -X POST "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/storage/copy-from-import" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"buckets":["value"],"rename":{},"dry_run":true,"max_files":1}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/storage/copy-from-import', {
method: 'POST',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"buckets": [
"value"
],
"rename": {},
"dry_run": true,
"max_files": 1
}),
})
const result = await response.json()
GET /api/v1/projects/{ref}/deployment-retention
Deployment retention Returns how many days canceled, failed, preview and production deployments are kept: the days in force (days), the project's own number (project_days, null when it follows the plan) and the plan default (plan_days). Also what is kept whatever the period (always_kept) and how many days a deleted deployment can be restored (restore_days).
curl "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/deployment-retention" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/deployment-retention', {
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
PUT /api/v1/projects/{ref}/deployment-retention
Change deployment retention Changes how long each kind of deployment is kept. A deployment past its period is deleted and can be restored with restore_deployment for 3 days. Recent and served deployments are kept whatever the period. Only project admins can do this.
curl -X PUT "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/deployment-retention" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"canceled_days":"value","error_days":"value","preview_days":"value","production_days":"value"}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/deployment-retention', {
method: 'PUT',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"canceled_days": "value",
"error_days": "value",
"preview_days": "value",
"production_days": "value"
}),
})
const result = await response.json()
GET /api/v1/projects/{ref}/schemas
Project schemas The schemas the project made with SQL besides public (create schema blackquant), and whether the data API exposes each (exposed). In the database the name is app_<ref>_<name>, but SQL and clients use the name as written.
curl "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/schemas" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/schemas', {
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
PUT /api/v1/projects/{ref}/schemas/exposed
Set exposed schemas Sets, as a whole list, the schemas the data API (/rest/v1) answers for besides public (Supabase's Exposed schemas). Use an exposed schema with the Accept-Profile / Content-Profile headers, supabase-js db: { schema } or .schema(). Row level security and the anon, authenticated and service_role privileges apply exactly as in public. An empty list exposes only public. Takes effect within 30 seconds. Only owners and admins can do this.
curl -X PUT "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/schemas/exposed" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"exposed":["value"]}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/schemas/exposed', {
method: 'PUT',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"exposed": [
"value"
]
}),
})
const result = await response.json()
GET /api/v1/projects/{ref}/data-api
Data API settings Whether the data API (/rest/v1) is on, the most rows one read returns (max_rows, null for no cap), the exposed schemas and the search path. search_path_choices are the schemas the search path can take: public, the schemas the project made with create schema, and extensions.
curl "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/data-api" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/data-api', {
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
PATCH /api/v1/projects/{ref}/data-api
Change the Data API settings Turns the data API (/rest/v1) on or off and sets the row cap and the search path. Only what is given changes. A schema on the search path comes after the one asked for, so functions and views find its tables and functions without the schema name. Takes effect within 30 seconds. Only owners and admins can do this.
curl -X PATCH "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/data-api" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"enabled":true,"max_rows":1,"search_path":["value"]}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/data-api', {
method: 'PATCH',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"enabled": true,
"max_rows": 1,
"search_path": [
"value"
]
}),
})
const result = await response.json()
POST /api/v1/projects/{ref}/{param0}/{param1}
Add SAML SSO Registers a SAML IdP from its metadata (an https URL or the XML). The metadata needs an HTTP-Redirect sign-in address and a signing certificate. signInWithSSO with an email domain in domains goes to this IdP. A domain belongs to one IdP only. A new IdP can be added on the Enterprise plan only (new_providers_allowed in list_sso_providers); IdPs already added keep working on any plan.
curl -X POST "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/value/value" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"metadata_url":"value","metadata_xml":"value","domains":["value"],"attribute_mapping":{}}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/value/value', {
method: 'POST',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"metadata_url": "value",
"metadata_xml": "value",
"domains": [
"value"
],
"attribute_mapping": {}
}),
})
const result = await response.json()
PUT /api/v1/projects/{ref}/{param0}/{param1}/{param2}
Add SAML SSO Registers a SAML IdP from its metadata (an https URL or the XML). The metadata needs an HTTP-Redirect sign-in address and a signing certificate. signInWithSSO with an email domain in domains goes to this IdP. A domain belongs to one IdP only. A new IdP can be added on the Enterprise plan only (new_providers_allowed in list_sso_providers); IdPs already added keep working on any plan.
curl -X PUT "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/value/value/value" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"metadata_url":"value","metadata_xml":"value","domains":["value"],"attribute_mapping":{}}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/value/value/value', {
method: 'PUT',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"metadata_url": "value",
"metadata_xml": "value",
"domains": [
"value"
],
"attribute_mapping": {}
}),
})
const result = await response.json()
GET /api/v1/projects/{ref}/config/auth
Show the whole sign-in configuration Returns this project's whole sign-in configuration under the same keys as Supabase's auth config, in lower case: sign-ups (disable_signup, mailer_autoconfirm, security_manual_linking_enabled, external_anonymous_users_enabled), the email provider and password rules, phone and the SMS provider (sms_*), SAML (saml_*), Web3, and for each social provider external_<provider>_enabled, client_id, secret, url and email_optional, and the custom providers switch. A secret is given as its last four characters, like ••••abcd; handing that back to update_auth_config leaves the stored one alone. callback_url is the address to paste into a provider's console.
curl "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/config/auth" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/config/auth', {
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
PATCH /api/v1/projects/{ref}/config/auth
Change the sign-in configuration Changes only the keys given (GoTrue's upper-case names work too), checked by the same rules as the console's Sign In / Providers page: a provider switched on needs what it needs (external_google_client_id, a Keycloak realm url), an Apple secret must be an ES256 JWT with more than 7 days left, and an SMS message must contain {{ .Code }}. If any of it is wrong nothing is saved, and each key's reason comes back. Kakao's consent items are external_kakao_scopes (profile_nickname, account_email, gender and so on, separated by commas), the Naver fields to keep are external_naver_scopes, and Google's and GitHub's additional scopes are external_<provider>_additional_scopes. An empty string removes a secret. Only owners, admins and developers can do this.
curl -X PATCH "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/config/auth" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/config/auth', {
method: 'PATCH',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({}),
})
const result = await response.json()
GET /api/v1/projects/{ref}/config/auth/custom-providers
Custom sign-in providers Shows the OAuth and OIDC providers the project defined itself (custom:<identifier>), the plan’s limit (max_providers) and the switch (enabled). The app signs in with signInWithOAuth({ provider: "custom:<identifier>" }).
curl "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/config/auth/custom-providers" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/config/auth/custom-providers', {
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
POST /api/v1/projects/{ref}/config/auth/custom-providers
Create a custom sign-in provider Creates one OAuth or OIDC provider (custom:<identifier>) and turns it on, in the same place set_auth_provider writes. With provider_type oidc the issuer alone is enough: the endpoints and jwks_uri are read from {issuer}/.well-known/openid-configuration, and each id_token's signature, issuer, audience, expiry and nonce are checked against those keys. With oauth2, give the issuer or authorization_url and token_url; endpoints left empty are {issuer}/oauth/authorize, /oauth/token and /oauth/userinfo. claim_map says which field of the answer is id, email, email_verified, name, avatar and phone (dotted paths). PKCE is on by default. Refused past the plan’s limit.
curl -X POST "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/config/auth/custom-providers" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"identifier":"value","name":"my-name","provider_type":"oidc","client_id":"CLIENT_ID","client_secret":"CLIENT_SECRET"}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/config/auth/custom-providers', {
method: 'POST',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"identifier": "value",
"name": "my-name",
"provider_type": "oidc",
"client_id": "CLIENT_ID",
"client_secret": "CLIENT_SECRET"
}),
})
const result = await response.json()
PUT /api/v1/projects/{ref}/config/auth/custom-providers/{identifier}
Change a custom sign-in provider Changes one custom provider. The identifier cannot change. An empty client_secret keeps the stored one.
curl -X PUT "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/config/auth/custom-providers/value" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"identifier":"value","name":"my-name","provider_type":"oidc","client_id":"CLIENT_ID"}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/config/auth/custom-providers/value', {
method: 'PUT',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"identifier": "value",
"name": "my-name",
"provider_type": "oidc",
"client_id": "CLIENT_ID"
}),
})
const result = await response.json()
PATCH /api/v1/projects/{ref}/config/auth/custom-providers/{identifier}
Turn a custom sign-in provider off or on Turns one custom provider off or on. Off, existing sessions stay, but new sign-ins fail until it is turned on again.
curl -X PATCH "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/config/auth/custom-providers/value" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"enabled":true}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/config/auth/custom-providers/value', {
method: 'PATCH',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"enabled": true
}),
})
const result = await response.json()
DELETE /api/v1/projects/{ref}/config/auth/custom-providers/{identifier}
Delete a custom sign-in provider Deletes one custom provider. It cannot be undone, and users who signed in with it can no longer get in.
curl -X DELETE "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/config/auth/custom-providers/value" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/config/auth/custom-providers/value', {
method: 'DELETE',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
POST /api/v1/projects/{ref}/config/auth/copy-from-import
Copy sign-in settings from an import Copies a Supabase project's sign-in setup into a project here (ref), read with a Supabase account connected in import_sources: each social provider switched on there (client ID, secret and the rest, checked as update_auth_config checks them), the redirect allow list (uri_allow_list, as add_redirect_url adds it) and site_url only when this project's is empty. Secrets never appear in the conversation; the answer says per provider whether it was copied and why not. Sign-in fails until the answer's callback_url is registered in each provider's console. dry_run shows what would be copied and changes nothing. Owners, admins and developers only.
curl -X POST "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/config/auth/copy-from-import" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"providers":["google"],"dry_run":true}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/config/auth/copy-from-import', {
method: 'POST',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"providers": [
"google"
],
"dry_run": true
}),
})
const result = await response.json()
GET /api/v1/projects/{ref}/config/auth/third-party-auth
Third-party auth The other identity services whose tokens the Data API takes: Firebase, Clerk, WorkOS, Auth0, Amazon Cognito and OpenID issuers.
curl "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/config/auth/third-party-auth" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/config/auth/third-party-auth', {
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
POST /api/v1/projects/{ref}/config/auth/third-party-auth
Add third-party auth Takes another identity service's JWTs as sign-ins to this project. value depends on type: firebase the project ID, clerk https://clerk.<domain> or https://<name>.clerk.accounts.dev, workos the issuer URL, auth0 the tenant name (the start of <name>.auth0.com), cognito the user pool ID (with region), oidc the issuer URL. For Auth0 and Cognito, giving audiences is recommended.
curl -X POST "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/config/auth/third-party-auth" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"type":"firebase","value":"value"}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/config/auth/third-party-auth', {
method: 'POST',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"type": "firebase",
"value": "value"
}),
})
const result = await response.json()
DELETE /api/v1/projects/{ref}/config/auth/third-party-auth/{id}
Remove third-party auth Removes one third-party auth integration. Requests from users signed in with that service are refused with 401 within 30 seconds.
curl -X DELETE "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/config/auth/third-party-auth/ID" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/config/auth/third-party-auth/ID', {
method: 'DELETE',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
GET /api/v1/projects/{ref}/analytics
Web analytics Returns page views and visitors per day, with the top pages, referrers, countries, devices, browsers and operating systems. Nothing that identifies a person is stored, so these are totals only.
curl "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/analytics?days=1" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/analytics?days=1', {
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
GET /api/v1/projects/{ref}/analytics/breakdown
Web Analytics breakdown Returns campaigns (utm_source, utm_medium, utm_campaign), routes, custom events and how many bots were filtered. With event, also that event's values per property. Totals only.
curl "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/analytics/breakdown?days=1&event=value" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/analytics/breakdown?days=1&event=value', {
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
PUT /api/v1/projects/{ref}/analytics/previews
Count preview visits Sets whether visits to preview deployments and dpl- addresses count in Web Analytics. Off (the default), previews get no script and what they send is dropped. Only owners and admins can do this.
curl -X PUT "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/analytics/previews" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"include_previews":true}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/analytics/previews', {
method: 'PUT',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"include_previews": true
}),
})
const result = await response.json()
GET /api/v1/projects/{ref}/analytics/export
Export Web Analytics Returns the period's totals as a CSV string, by day, dimension and value.
curl "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/analytics/export?days=1" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/analytics/export?days=1', {
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
GET /api/v1/projects/{ref}/analytics/reports
Custom reports Returns the saved Web Analytics reports and the names of the charts a report can hold.
curl "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/analytics/reports" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/analytics/reports', {
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
GET /api/v1/projects/{ref}/analytics/reports/{id}
Show a custom report Returns one saved report with its period's totals, breakdowns and speed.
curl "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/analytics/reports/ID" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/analytics/reports/ID', {
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
POST /api/v1/projects/{ref}/analytics/reports
Save a custom report Creates a report, or changes the one id names. Developers and above can do this.
curl -X POST "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/analytics/reports" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"name":"my-name","widgets":["views"]}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/analytics/reports', {
method: 'POST',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"name": "my-name",
"widgets": [
"views"
]
}),
})
const result = await response.json()
PATCH /api/v1/projects/{ref}/analytics/reports
Save a custom report Creates a report, or changes the one id names. Developers and above can do this.
curl -X PATCH "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/analytics/reports" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"name":"my-name","widgets":["views"]}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/analytics/reports', {
method: 'PATCH',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"name": "my-name",
"widgets": [
"views"
]
}),
})
const result = await response.json()
DELETE /api/v1/projects/{ref}/analytics/reports/{id}
Delete a custom report Deletes the report only; the analytics stay as they are. Developers and above can do this.
curl -X DELETE "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/analytics/reports/ID" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/analytics/reports/ID', {
method: 'DELETE',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
GET /api/v1/projects/{ref}/speed-insights
Speed Insights Returns the 75th percentile and rating of the Core Web Vitals (LCP, INP, CLS, FCP, TTFB) that real visitors measured, and the slowest pages.
curl "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/speed-insights?days=1&device=all" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/speed-insights?days=1&device=all', {
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
PUT /api/v1/projects/{ref}/insights
Turn analytics on or off Turns Web Analytics and Speed Insights on or off. When on, the site's HTML gets the /_oneend/insights/script.js script. Apps that use Vercel's @vercel/analytics and @vercel/speed-insights are counted in the same place with no code change. No cookies are used and no address is stored. Only owners and admins can do this.
curl -X PUT "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/insights" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"analytics":true,"speed_insights":true,"vitals_sample_percent":1}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/insights', {
method: 'PUT',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"analytics": true,
"speed_insights": true,
"vitals_sample_percent": 1
}),
})
const result = await response.json()
GET /api/v1/projects/{ref}/remote-cache
Remote cache Returns the Turborepo remote cache's address, how many outputs it holds and their size, the last 30 days' hits and uploads, and this month's metered storage (remote_cache_gb_hour) with its price. Downloads are counted as egress_gb.
curl "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/remote-cache" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/remote-cache', {
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
DELETE /api/v1/projects/{ref}/remote-cache/artifacts
Clear the remote cache Deletes every stored output. The next builds fill it again, and the metered storage drops by what was cleared. Developers and above can do this.
curl -X DELETE "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/remote-cache/artifacts" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/remote-cache/artifacts', {
method: 'DELETE',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
GET /api/v1/projects/{ref}/flags
Feature flags Returns the project's feature flags together with the flag-shaped values kept in its edge config. source says where each is kept and shadows whether it hides an edge config value of the same key. Where both have a key, the flag decides.
curl "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/flags" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/flags', {
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
GET /api/v1/projects/{ref}/flags/evaluate
Evaluate a feature flag Returns what the app would get: with a context (e.g. {"user": {"id": "u1"}}) and an environment, the flag's rules decide; with no flag of that key, the edge config value does. source says which decided.
curl "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/flags/evaluate?key=API_URL&environment=value" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/flags/evaluate?key=API_URL&environment=value', {
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
PUT /api/v1/projects/{ref}/flags/{key}/environments/{environment}
Turn a feature flag on or off Turns a flag on or off in one environment. Production takes owners and admins; other environments, developers and above.
curl -X PUT "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/flags/API_URL/environments/value" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"enabled":true}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/flags/API_URL/environments/value', {
method: 'PUT',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"enabled": true
}),
})
const result = await response.json()
GET /api/v1/projects/{ref}/edge-config
Read edge config Returns the project's edge config (values and feature flags that change without a deploy), with its version, size and limits.
curl "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/edge-config" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/edge-config', {
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
GET /api/v1/projects/{ref}/edge-config/tokens
Edge config read tokens Returns the read tokens other projects read this project's edge config with, the projects each is connected to (variable name, environments), and other projects' edge configs connected to this one. The tokens themselves are not returned.
curl "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/edge-config/tokens" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/edge-config/tokens', {
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
POST /api/v1/projects/{ref}/edge-config/tokens
Create an edge config read token Creates a read token and, with connect, connects it to a project in the same organization. From its next deployment, that project gets the connection string (https://<ref>.<zone>/config/v1?token=…) as a variable. The token is shown only this once. Project admins only.
curl -X POST "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/edge-config/tokens" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"name":"my-name"}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/edge-config/tokens', {
method: 'POST',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"name": "my-name"
}),
})
const result = await response.json()
DELETE /api/v1/projects/{ref}/edge-config/tokens/{id}
Revoke a read token Revokes a read token. It stops reading at once, and connected projects lose the variable with their next deployment.
curl -X DELETE "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/edge-config/tokens/ID" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/edge-config/tokens/ID', {
method: 'DELETE',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
PUT /api/v1/projects/{ref}/edge-config/tokens/{id}/connections/{ref}
Connect a read token to a project Connects a read token to another project in the organization as a variable in its deployments. If already connected, changes the variable name and environments. Takes a developer or above of that project (owners and admins for production).
curl -X PUT "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/edge-config/tokens/ID/connections/abcdefghijklmnopqrst" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"variable":"value","targets":["production"]}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/edge-config/tokens/ID/connections/abcdefghijklmnopqrst', {
method: 'PUT',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"variable": "value",
"targets": [
"production"
]
}),
})
const result = await response.json()
DELETE /api/v1/projects/{ref}/edge-config/tokens/{id}/connections/{ref}
Disconnect a read token Takes a read token out of one project. The variable leaves with that project's next deployment.
curl -X DELETE "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/edge-config/tokens/ID/connections/abcdefghijklmnopqrst" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/edge-config/tokens/ID/connections/abcdefghijklmnopqrst', {
method: 'DELETE',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
GET /api/v1/projects/{ref}/edge-config/history
Edge config history Returns who changed which key, when, from what to what, most recent first.
curl "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/edge-config/history?limit=1" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/edge-config/history?limit=1', {
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
PATCH /api/v1/projects/{ref}/edge-config
Change edge config Sets or deletes keys. Every server has the change within a few seconds, and it is kept in the history. A flag is true or false, or {"enabled": true, "percent": 20}, or {"enabled": true, "allow": ["user-1"]}. Developers and above can do this.
curl -X PATCH "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/edge-config" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"set":{},"delete":["value"]}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/edge-config', {
method: 'PATCH',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"set": {},
"delete": [
"value"
]
}),
})
const result = await response.json()
GET /api/v1/projects/{ref}/rolling-releases
Rolling releases Returns the rolling release settings, the release in progress (the share of visitors the new deployment gets), and recent ones.
curl "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/rolling-releases" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/rolling-releases', {
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
PUT /api/v1/projects/{ref}/rolling-releases
Rolling release settings Decides whether new production deployments go out in stages. stages is a rising list of shares (for example [10, 50]), stage_minutes the length of each, and with auto_advance false each stage waits for approval. Above abort_error_rate (0.05 is 5%) the release is rolled back automatically. Only owners and admins can do this.
curl -X PUT "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/rolling-releases" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"enabled":true,"stages":["value"],"stage_minutes":1,"auto_advance":true,"abort_error_rate":0.001}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/rolling-releases', {
method: 'PUT',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"enabled": true,
"stages": [
"value"
],
"stage_minutes": 1,
"auto_advance": true,
"abort_error_rate": 0.001
}),
})
const result = await response.json()
POST /api/v1/projects/{ref}/rolling-releases/{action}
Advance a rolling release Moves the release in progress to its next stage. From the last stage it goes to everybody. Only owners and admins can do this.
curl -X POST "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/rolling-releases/value" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"reason":"value"}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/rolling-releases/value', {
method: 'POST',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"reason": "value"
}),
})
const result = await response.json()
GET /api/v1/projects/{ref}/kv
KV keys Returns the KV store's keys by prefix, 50 at a time, with usage, limits and the REST address. Only roles that may see secrets can do this.
curl "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/kv?prefix=value&cursor=value" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/kv?prefix=value&cursor=value', {
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
GET /api/v1/projects/{ref}/kv/{id}
Read a KV value Returns one key's value and the seconds it has left (ttl, -1 for no expiry).
curl "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/kv/ID" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/kv/ID', {
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
PUT /api/v1/projects/{ref}/kv/{id}
Save a KV value Stores a JSON value at a key. ttl is the seconds until it expires. Developers and above can do this.
curl -X PUT "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/kv/ID" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"value":"value"}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/kv/ID', {
method: 'PUT',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"value": "value"
}),
})
const result = await response.json()
DELETE /api/v1/projects/{ref}/kv/{id}
Delete a KV key Deletes a key. Developers and above can do this.
curl -X DELETE "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/kv/ID" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/kv/ID', {
method: 'DELETE',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
GET /api/v1/projects/{ref}/ai-gateway
AI gateway Returns the AI gateway's OpenAI-compatible address, its settings, its providers (keys as their last four characters only), and the last 30 days of use.
curl "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/ai-gateway" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/ai-gateway', {
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
PUT /api/v1/projects/{ref}/ai-gateway
AI gateway settings Turns the AI gateway on or off and sets whether signed-in users may call it, the cache in seconds, the requests per minute, the fallback to the platform's provider (billed per token), and the daily requests and tokens one user of the app may use. The user is a signed-in user's id, or, with the secret key, the x-oneend-user header or the body's user. Only owners and admins can do this.
curl -X PUT "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/ai-gateway" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"enabled":true,"allow_users":true,"cache_seconds":0,"rate_per_minute":1,"platform_fallback":true}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/ai-gateway', {
method: 'PUT',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"enabled": true,
"allow_users": true,
"cache_seconds": 0,
"rate_per_minute": 1,
"platform_fallback": true
}),
})
const result = await response.json()
GET /api/v1/projects/{ref}/ai-gateway/logs
AI gateway calls Returns recent calls with their provider, model, status, tokens, latency and whether they fell back. Conversations are not stored.
curl "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/ai-gateway/logs?limit=1" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/ai-gateway/logs?limit=1', {
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
POST /api/v1/projects/{ref}/ai-gateway/providers
Add an AI provider Adds a provider with its key: OpenAI-compatible, Anthropic (translated to and from its Messages API) or Google Gemini. Only public https addresses are accepted. The key is sealed and never shown again. Only owners and admins can do this.
curl -X POST "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/ai-gateway/providers" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"name":"my-name","kind":"openai"}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/ai-gateway/providers', {
method: 'POST',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"name": "my-name",
"kind": "openai"
}),
})
const result = await response.json()
PATCH /api/v1/projects/{ref}/ai-gateway/providers/{id}
Turn an AI provider off or on Stops or resumes using a provider and keeps its settings and key. Only owners and admins can do this.
curl -X PATCH "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/ai-gateway/providers/ID" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"enabled":true}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/ai-gateway/providers/ID', {
method: 'PATCH',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"enabled": true
}),
})
const result = await response.json()
DELETE /api/v1/projects/{ref}/ai-gateway/providers/{id}
Remove an AI provider Removes a provider and its sealed key. Only owners and admins can do this.
curl -X DELETE "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/ai-gateway/providers/ID" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/ai-gateway/providers/ID', {
method: 'DELETE',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
PUT /api/v1/projects/{ref}/ai-gateway/budgets
AI gateway budgets Sets the project's AI gateway budgets in dollars (day, week and month, UTC). Once one is spent, calls are refused until the next period. A value left out is kept. Only owners and admins can do this.
curl -X PUT "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/ai-gateway/budgets" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"daily_usd":"value","weekly_usd":"value","monthly_usd":"value"}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/ai-gateway/budgets', {
method: 'PUT',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"daily_usd": "value",
"weekly_usd": "value",
"monthly_usd": "value"
}),
})
const result = await response.json()
GET /api/v1/projects/{ref}/ai-gateway/keys
AI gateway keys Returns the gateway keys with their names, prefixes, budgets, this month's spend and when each was last used. Never the keys themselves.
curl "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/ai-gateway/keys" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/ai-gateway/keys', {
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
POST /api/v1/projects/{ref}/ai-gateway/keys
Create an AI gateway key Creates a gateway key (bwai_…) for one app, or for one customer the project resells AI to, with its own budgets, tag and limits per minute. The key is in this answer once and never again. Keys with a tag (external_ref) do not count toward the 50 keys a project may have. Only owners and admins can do this.
curl -X POST "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/ai-gateway/keys" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"name":"my-name"}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/ai-gateway/keys', {
method: 'POST',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"name": "my-name"
}),
})
const result = await response.json()
PUT /api/v1/projects/{ref}/ai-gateway/keys/{id}/limits
AI gateway key limits Changes one gateway key's limits on requests and tokens per minute. Every server counts the same minute. A value left out is kept; null removes the limit. Only owners and admins can do this.
curl -X PUT "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/ai-gateway/keys/ID/limits" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"rate_per_minute":"value","tokens_per_minute":"value"}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/ai-gateway/keys/ID/limits', {
method: 'PUT',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"rate_per_minute": "value",
"tokens_per_minute": "value"
}),
})
const result = await response.json()
PUT /api/v1/projects/{ref}/ai-gateway/aliases
AI model aliases Sets the model names callers use (aliases) and the model each is sent to, each with an optional system prompt put first. Answers carry the alias as their model. The list given replaces the whole list. With aliases_only on, nothing but an alias can be asked for and /models lists only the aliases. Only owners and admins can do this.
curl -X PUT "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/ai-gateway/aliases" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"aliases":[{"alias":"value","target":"hello","system_prompt":"value"}]}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/ai-gateway/aliases', {
method: 'PUT',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"aliases": [
{
"alias": "value",
"target": "hello",
"system_prompt": "value"
}
]
}),
})
const result = await response.json()
PUT /api/v1/projects/{ref}/ai-gateway/hooks
AI gateway hooks Sets the https address asked before, and told after, every call made with a gateway key. If ai.before does not answer 2xx within timeout_ms, the call is refused (a 402 is passed on as a low balance). ai.after carries the usage, cost and status, and is sent again for a day until it is taken. The answer holds the signing secret. A null url turns hooks off. Only owners and admins can do this.
curl -X PUT "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/ai-gateway/hooks" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"url":"https://example.com/hook","timeout_ms":200}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/ai-gateway/hooks', {
method: 'PUT',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"url": "https://example.com/hook",
"timeout_ms": 200
}),
})
const result = await response.json()
PATCH /api/v1/projects/{ref}/ai-gateway/keys/{id}
AI gateway key budgets Changes one gateway key's budgets. A value left out is kept. Only owners and admins can do this.
curl -X PATCH "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/ai-gateway/keys/ID" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"daily_usd":"value","weekly_usd":"value","monthly_usd":"value"}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/ai-gateway/keys/ID', {
method: 'PATCH',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"daily_usd": "value",
"weekly_usd": "value",
"monthly_usd": "value"
}),
})
const result = await response.json()
DELETE /api/v1/projects/{ref}/ai-gateway/keys/{id}
Revoke an AI gateway key Revokes a gateway key. Every server refuses it within 30 seconds. Only owners and admins can do this.
curl -X DELETE "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/ai-gateway/keys/ID" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/ai-gateway/keys/ID', {
method: 'DELETE',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
GET /api/v1/projects/{ref}/ai-gateway/spend
AI gateway spend Returns today's, this week's and this month's spend against the budgets, and spend per day, model and key, in dollars. Calls to a provider with the project's own key are estimated at list price.
curl "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/ai-gateway/spend?days=1" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/ai-gateway/spend?days=1', {
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
GET /api/v1/projects/{ref}/middleware
Middleware settings Returns whether the site's middleware (middleware.ts) runs and its time limit.
curl "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/middleware" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/middleware', {
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
PUT /api/v1/projects/{ref}/middleware
Change middleware settings Turns the site's middleware off or on and sets its time limit (100 to 5000ms). Off serves without middleware, with no new deploy. Only owners and admins can do this.
curl -X PUT "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/middleware" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"enabled":true,"timeout_ms":100}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/middleware', {
method: 'PUT',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"enabled": true,
"timeout_ms": 100
}),
})
const result = await response.json()
GET /api/v1/projects/{ref}/branches
Database branches This project's database branches: name, the branch's own project ref (use it with every other tool), the git branch it is wired to, status (creating, ready, merging, resetting, failed, deleting), size and when it expires. Also returns the automatic branching settings.
curl "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/branches" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/branches', {
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
POST /api/v1/projects/{ref}/branches
Create a database branch Makes a preview database from the project's schema: the project's migrations (the history apply_migrations records) are replayed in order and the seed is run. Rows are copied only with with_data. A branch is a project with a ref of its own; use that ref with run_sql, get_project_keys and every other tool. With git_branch, that branch's preview deployments use this database. Available from the Pro plan.
curl -X POST "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/branches" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"name":"my-name","git_branch":"value","with_seed":true,"with_data":true}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/branches', {
method: 'POST',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"name": "my-name",
"git_branch": "value",
"with_seed": true,
"with_data": true
}),
})
const result = await response.json()
PUT /api/v1/projects/{ref}/branching
Automatic database branches Whether a database branch is made automatically for every git branch deployed as a preview, the seed SQL every branch gets, and how many days an unused branch is kept (1 to 90, extended by every deployment). Only owners and admins can do this.
curl -X PUT "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/branching" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"automatic":true,"seed_sql":"value","lifetime_days":1}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/branching', {
method: 'PUT',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"automatic": true,
"seed_sql": "value",
"lifetime_days": 1
}),
})
const result = await response.json()
POST /api/v1/projects/{ref}/branches/{name}/merge
Merge a database branch Applies the migrations only the branch has to the project (production), in version order, each in a transaction of its own; stops at the first failure, rolling back only that one. Rows do not move. Change the schema in a branch with apply_migrations, not run_sql, for it to be merged.
curl -X POST "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/branches/my-name/merge" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/branches/my-name/merge', {
method: 'POST',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
POST /api/v1/projects/{ref}/branches/{name}/reset
Reset a database branch Drops the branch's database and makes it again from the project's migrations and seed. All the branch's rows and users are lost and no backup is kept. Put the branch name exactly in confirm.
curl -X POST "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/branches/my-name/reset" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"confirm":"my-project"}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/branches/my-name/reset', {
method: 'POST',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"confirm": "my-project"
}),
})
const result = await response.json()
DELETE /api/v1/projects/{ref}/branches/{name}
Delete a database branch Deletes the branch with its database and keys. It cannot be undone, so put the branch name exactly in confirm. Deleting the git branch or closing its pull request deletes it automatically.
curl -X DELETE "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/branches/my-name" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"confirm":"my-project"}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/branches/my-name', {
method: 'DELETE',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"confirm": "my-project"
}),
})
const result = await response.json()
GET /api/v1/projects/{ref}/queues
Queues The queues (the same SQL functions as pgmq: pgmq.send, pgmq.read, pgmq.pop, pgmq.archive, pgmq.delete), with how many messages each holds, how many can be read now, how many are archived and the age of the oldest. enabled says whether pgmq is installed, exposed whether the data API (pgmq_public) can call it.
curl "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/queues" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/queues', {
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
GET /api/v1/projects/{ref}/queues/metrics
Queue metrics From the queue samples taken every five minutes: each queue's current depth, ready messages, oldest wait and archived count, and across all queues the depth, messages sent and messages processed over time. 24 hours by default, up to 168.
curl "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/queues/metrics?hours=1" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/queues/metrics?hours=1', {
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
POST /api/v1/projects/{ref}/queues
Create a queue Makes one queue (pgmq.create), installing pgmq the first time. Messages are kept in the table pgmq.q_<name>; in SQL, put one in with pgmq.send(name, message) and read with pgmq.read(name, seconds, count). Only in a database of its own.
curl -X POST "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/queues" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"name":"my-name"}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/queues', {
method: 'POST',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"name": "my-name"
}),
})
const result = await response.json()
PUT /api/v1/projects/{ref}/queues/api
Open queues to the data API true makes the pgmq_public schema (send, send_batch, read, pop, archive, delete) so the data API can call it as supabase.schema("pgmq_public").rpc("send", ...). It runs as the caller, so for the publishable key or signed-in users to use it, grant privileges and write access rules on the queue tables. Only owners and admins can do this.
curl -X PUT "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/queues/api" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"exposed":true}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/queues/api', {
method: 'PUT',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"exposed": true
}),
})
const result = await response.json()
DELETE /api/v1/projects/{ref}/queues/{name}
Delete a queue Deletes a queue with its messages and archive (pgmq.drop_queue). It cannot be undone, so put the queue name exactly in confirm.
curl -X DELETE "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/queues/my-name" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"confirm":"my-project"}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/queues/my-name', {
method: 'DELETE',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"confirm": "my-project"
}),
})
const result = await response.json()
POST /api/v1/projects/{ref}/queues/{name}/purge
Empty a queue Deletes all of a queue's messages (pgmq.purge_queue). The archive is kept. It cannot be undone, so put the queue name exactly in confirm.
curl -X POST "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/queues/my-name/purge" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"confirm":"my-project"}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/queues/my-name/purge', {
method: 'POST',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"confirm": "my-project"
}),
})
const result = await response.json()
POST /api/v1/projects/{ref}/queues/{name}/messages
Send a message to a queue Puts one JSON message on a queue (pgmq.send). It cannot be read for delay seconds.
curl -X POST "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/queues/my-name/messages" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"message":"value"}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/queues/my-name/messages', {
method: 'POST',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"message": "value"
}),
})
const result = await response.json()
GET /api/v1/projects/{ref}/queues/{name}/messages
Look at queue messages Shows the messages at the front of a queue without taking them. Neither the read count nor the visibility time changes, so it never takes a message a worker was about to get.
curl "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/queues/my-name/messages?limit=1" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/queues/my-name/messages?limit=1', {
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
GET /api/v1/projects/{ref}/vault
Vault secrets The names and descriptions of the secrets in Vault. Values are never returned. The project's code reads one with the secret key: select decrypted_secret from vault.decrypted_secrets where name = ...
curl "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/vault" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/vault', {
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
POST /api/v1/projects/{ref}/vault
Store a Vault secret Encrypts one secret and stores it in vault.secrets in the project's database (vault.create_secret). The platform holds the key and it is never stored in the database, so dumps and backups hold only ciphertext. Turns Vault on the first time. Only owners and admins can do this.
curl -X POST "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/vault" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"name":"my-name","value":"value"}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/vault', {
method: 'POST',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"name": "my-name",
"value": "value"
}),
})
const result = await response.json()
PATCH /api/v1/projects/{ref}/vault/{name}
Change a Vault secret Changes a secret's value or description (vault.update_secret). Only owners and admins can do this.
curl -X PATCH "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/vault/my-name" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"value":"value","description":"value"}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/vault/my-name', {
method: 'PATCH',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"value": "value",
"description": "value"
}),
})
const result = await response.json()
DELETE /api/v1/projects/{ref}/vault/{name}
Delete a Vault secret Deletes one secret. Only owners and admins can do this.
curl -X DELETE "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/vault/my-name" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/vault/my-name', {
method: 'DELETE',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
GET /api/v1/projects/{ref}/network-restrictions
Database network restrictions The addresses that may connect to the database directly (5432 and 6543) and whether TLS is required. restricted false means every address may connect. your_address_allowed says whether the address this request came from is allowed.
curl "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/network-restrictions" \
-H "Authorization: Bearer $ONEEND_TOKEN"
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/network-restrictions', {
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}` },
})
const result = await response.json()
PUT /api/v1/projects/{ref}/network-restrictions
Change database network restrictions Changes the addresses allowed to connect directly (a list of CIDRs, up to 100) and whether TLS is required. allow_all allows every address again. Refused without confirm when the address this request came from is not on the list. The console, the API and run_sql do not go through the pooler, so a restriction can always be undone. Only owners and admins can do this.
curl -X PUT "https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/network-restrictions" \
-H "Authorization: Bearer $ONEEND_TOKEN" \
-H "content-type: application/json" \
-d '{"allowed_cidrs":["value"],"allow_all":true,"enforce_ssl":true,"confirm":true}'
const response = await fetch('https://end.blackall.ai/api/v1/projects/abcdefghijklmnopqrst/network-restrictions', {
method: 'PUT',
headers: { authorization: `Bearer ${process.env.ONEEND_TOKEN}`, 'content-type': 'application/json' },
body: JSON.stringify({
"allowed_cidrs": [
"value"
],
"allow_all": true,
"enforce_ssl": true,
"confirm": true
}),
})
const result = await response.json()